<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://www.benjaminmaurer.at/feed.xml" rel="self" type="application/atom+xml" /><link href="http://www.benjaminmaurer.at/" rel="alternate" type="text/html" hreflang="en" /><updated>2024-09-20T16:05:04+00:00</updated><id>http://www.benjaminmaurer.at/feed.xml</id><title type="html">Ben’s Blog</title><subtitle>This description is work in progress.</subtitle><author><name>Benjamin Maurer</name></author><entry><title type="html">Generating Tests using Scala 3 Macros</title><link href="http://www.benjaminmaurer.at/2024/09/20/scala3_macros.html" rel="alternate" type="text/html" title="Generating Tests using Scala 3 Macros" /><published>2024-09-20T00:00:00+00:00</published><updated>2024-09-20T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2024/09/20/scala3_macros</id><content type="html" xml:base="http://www.benjaminmaurer.at/2024/09/20/scala3_macros.html"><![CDATA[<h1 id="porting-old-code">Porting Old Code…</h1>

<p>At work, I just finished getting our in-house libraries to cross-compile to Scala 2.13 and 3.3.
Of course, at some point I encountered a macro, and since the macro system got a complete overhaul
in Scala 3, I needed to rewrite that.</p>

<p>I’ve had almost no contact with Scala 2 or 3 macros before, so I wasn’t quite looking forward to the task.
Co-Pilot produced some good looking code, which had only one compilation error. However, after trying to get it to
work for a few hours, I realized, that the code was rubbish.
(See, AI won’t come for our jobs just yet ;) )</p>

<h1 id="the-task">The Task</h1>

<h2 id="goal">Goal</h2>

<p>This particular macro is intended to generate test cases for translation keys.
You define an object with a bunch of translation keys of type <code class="language-plaintext highlighter-rouge">TranslationKeyN[M, I1..IN]</code>,
where <code class="language-plaintext highlighter-rouge">N</code> is the arity of the key (how many interpolation parameters it has), <code class="language-plaintext highlighter-rouge">M</code> is a marker trait and
<code class="language-plaintext highlighter-rouge">I1..IN</code> the types of the interpolation values.
This is to make sure, that each key has a translation with the appropriate number of parameters.</p>

<h2 id="steps">Steps</h2>

<p>Alright, so we have a test class with an overloaded method, one for each arity.
Our users call the macro with some container object <code class="language-plaintext highlighter-rouge">C</code>, which contains the keys for some
marker trait (i.e., the keys that belong grouped together, e.g., for some email).</p>

<p>We need to:</p>

<ul>
  <li>Enumerate the members of <code class="language-plaintext highlighter-rouge">C</code></li>
  <li>Filter the public value definitions (<code class="language-plaintext highlighter-rouge">val</code>s)</li>
  <li>Filter the ones of the right type (<code class="language-plaintext highlighter-rouge">TranslationKeyN</code>)</li>
  <li>Generate an expression calling the right overload</li>
</ul>

<p>The details of the implementation look a bit complex, but I found it an interesting example for a macro,
because we deal with reflection (enumerating members), calling methods on instances, overloaded methods even,
type arguments and even contextual abstractions (implicits/using/given).</p>

<h1 id="a-first-try">A First Try</h1>

<p>This article is not going to be an in-depth introduction to Scala 3 macros.
But here are some helpful resources:</p>

<ul>
  <li><a href="https://docs.scala-lang.org/scala3/guides/macros/index.html">The official Tutorial</a></li>
  <li><a href="https://softwaremill.com/scala-3-macros-tips-and-tricks/">Scala 3 macros tips &amp; tricks (Softwaremill)</a></li>
  <li><a href="https://github.com/lampepfl/dotty-macro-examples">lampepfl: dotty-macro-examples</a></li>
  <li><a href="https://github.com/scala/scala3/blob/3.5.0/library/src/scala/quoted/Quotes.scala">Actual Scala 3 library source code</a> (this is, probably, the most useful one!)</li>
</ul>

<p>Alright, so here is an outline of our <code class="language-plaintext highlighter-rouge">TranslationTest</code> class:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">TranslationsTest</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span><span class="nc">:</span>
  <span class="k">def</span> <span class="nf">testTranslationKey</span><span class="o">(</span><span class="n">key</span><span class="k">:</span> <span class="kt">TranslationKey0</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span>
    <span class="nf">testKeyInternal</span><span class="o">(</span><span class="nv">key</span><span class="o">.</span><span class="py">value</span><span class="o">)(</span><span class="nf">key</span><span class="o">()(</span><span class="k">_</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">testTranslationKey</span><span class="o">[</span><span class="kt">I1:</span> <span class="kt">Arbitrary</span><span class="o">](</span><span class="n">key</span><span class="k">:</span> <span class="kt">TranslationKey1</span><span class="o">[</span><span class="kt">A</span>, <span class="kt">I1</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span>
    <span class="nf">testKeyInternal</span><span class="o">(</span><span class="nv">key</span><span class="o">.</span><span class="py">value</span><span class="o">)(</span><span class="nf">key</span><span class="o">(</span><span class="n">random</span><span class="o">[</span><span class="kt">I1</span><span class="o">])(</span><span class="k">_</span><span class="o">))</span>

  <span class="c1">// Provide more overloads...</span>

  <span class="n">inline</span> <span class="k">def</span> <span class="nf">testAllTranslationKeys</span><span class="o">[</span><span class="kt">C</span><span class="o">](</span><span class="n">container</span><span class="k">:</span> <span class="kt">C</span><span class="o">)</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span>
    <span class="n">$</span><span class="o">{</span> <span class="n">macroImpl</span><span class="o">[</span><span class="kt">A</span>, <span class="kt">C</span><span class="o">](</span><span class="ss">'this</span><span class="o">,</span> <span class="ss">'container</span><span class="o">)</span> <span class="o">}</span>
</code></pre></div></div>

<p>The method <code class="language-plaintext highlighter-rouge">testKeyInternal</code> will use the translation bundles to generate a table driven test.
But in my example, it just does some <code class="language-plaintext highlighter-rouge">println</code>-ing.
Using the <code class="language-plaintext highlighter-rouge">random</code> function, we generate some random input for the interpolation arguments,
i.e., for a key “<code class="language-plaintext highlighter-rouge">Welcome </code>” of type <code class="language-plaintext highlighter-rouge">TranslationKey1[User, String]</code>,
we need an <code class="language-plaintext highlighter-rouge">Arbitrary[String]</code> instance to generate some random value.
This comes from <a href="https://github.com/typelevel/scalacheck/blob/main/doc/UserGuide.md">scalacheck</a>.</p>

<p>In the original code, <code class="language-plaintext highlighter-rouge">TranslationsTest</code> serves as a base-class for tests and a call to the
<code class="language-plaintext highlighter-rouge">inline</code> method will generate the test cases there.</p>

<p>The method is the entry point to the macro and contains a splice with the call to the macro.
We are passing quoted references to <code class="language-plaintext highlighter-rouge">this</code> and the container object with the keys.
(extra credit: you don’t need to pass <code class="language-plaintext highlighter-rouge">this</code>, because you can get a reference to the owner of a splice.
In my case, it wasn’t necessary, because this is library internal code and the user facing code would be the same.)</p>

<p>Let’s give the actual macro a try now. The implementation has to be in a different compilation unit -
in my example I put it into <code class="language-plaintext highlighter-rouge">Macro.scala</code>:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">scala.quoted.</span><span class="o">*</span>

<span class="k">def</span> <span class="nf">macroImpl</span><span class="o">[</span><span class="kt">T</span>, <span class="kt">C</span><span class="o">](</span>
    <span class="n">testsExpr</span><span class="k">:</span> <span class="kt">Expr</span><span class="o">[</span><span class="kt">TranslationsTest</span><span class="o">[</span><span class="kt">T</span><span class="o">]],</span>
    <span class="n">container</span><span class="k">:</span> <span class="kt">Expr</span><span class="o">[</span><span class="kt">C</span><span class="o">]</span>
<span class="o">)(</span><span class="n">using</span> <span class="n">quotes</span><span class="k">:</span> <span class="kt">Quotes</span><span class="o">,</span> <span class="n">tTpe</span><span class="k">:</span> <span class="kt">Type</span><span class="o">[</span><span class="kt">T</span><span class="o">],</span> <span class="n">cTpe</span><span class="k">:</span> <span class="kt">Type</span><span class="o">[</span><span class="kt">C</span><span class="o">])</span><span class="k">:</span> <span class="kt">Expr</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span>
  <span class="k">import</span> <span class="nn">quotes.reflect.</span><span class="o">*</span>

  <span class="k">val</span> <span class="nv">tkTypes</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span>
    <span class="nv">TypeRepr</span><span class="o">.</span><span class="py">of</span><span class="o">[</span><span class="kt">TranslationKey0</span><span class="o">[</span><span class="kt">T</span><span class="o">]],</span>
    <span class="nv">TypeRepr</span><span class="o">.</span><span class="py">of</span><span class="o">[</span><span class="kt">TranslationKey1</span><span class="o">[</span><span class="kt">T</span>, <span class="k">_</span><span class="o">]],</span>
    <span class="nv">TypeRepr</span><span class="o">.</span><span class="py">of</span><span class="o">[</span><span class="kt">TranslationKey2</span><span class="o">[</span><span class="kt">T</span>, <span class="k">_</span>, <span class="k">_</span><span class="o">]],</span>
    <span class="nv">TypeRepr</span><span class="o">.</span><span class="py">of</span><span class="o">[</span><span class="kt">TranslationKey3</span><span class="o">[</span><span class="kt">T</span>, <span class="k">_</span>, <span class="k">_</span>, <span class="k">_</span><span class="o">]],</span>
    <span class="nv">TypeRepr</span><span class="o">.</span><span class="py">of</span><span class="o">[</span><span class="kt">TranslationKey4</span><span class="o">[</span><span class="kt">T</span>, <span class="k">_</span>, <span class="k">_</span>, <span class="k">_</span>, <span class="k">_</span><span class="o">]]</span>
  <span class="o">)</span>

  <span class="k">def</span> <span class="nf">isTranslationsKey</span><span class="o">(</span><span class="n">t</span><span class="k">:</span> <span class="kt">TypeRepr</span><span class="o">)</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=</span>
    <span class="nv">tkTypes</span><span class="o">.</span><span class="py">exists</span><span class="o">(</span><span class="n">t</span> <span class="o">&lt;:&lt;</span> <span class="k">_</span><span class="o">)</span>

  <span class="k">val</span> <span class="nv">containerType</span><span class="k">:</span> <span class="kt">TypeRepr</span> <span class="o">=</span> <span class="nv">TypeRepr</span><span class="o">.</span><span class="py">of</span><span class="o">[</span><span class="kt">C</span><span class="o">]</span>
  <span class="k">val</span> <span class="nv">containerTerm</span><span class="k">:</span> <span class="kt">Term</span> <span class="o">=</span> <span class="nv">container</span><span class="o">.</span><span class="py">asTerm</span>
</code></pre></div></div>

<p>Let’s have a look at the start of the function.
We have our type arguments for the maker type <code class="language-plaintext highlighter-rouge">T</code> and the container type <code class="language-plaintext highlighter-rouge">C</code>.
The first parameter is our expression containing <code class="language-plaintext highlighter-rouge">this</code> and the second one our container object.
We need to use <code class="language-plaintext highlighter-rouge">Quotes</code> because this is a macro and we need instances of <code class="language-plaintext highlighter-rouge">Type[A]</code> for any type <code class="language-plaintext highlighter-rouge">A</code>
we want to reference in our quote.
The way I understand this, this is due to the JVM using type erasure for generics and if we want
to actually do something with the type, it needs to be reified.</p>

<p>Alright, so the rest is mostly machinery to check that a member value has the type we are looking for.
Then we get a type representation of <code class="language-plaintext highlighter-rouge">C</code>, which we can use for reflection and a term of the container,
so we can use that to access the actual members of it.</p>

<p>Moving on:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">calls</span> <span class="k">=</span> <span class="nv">containerType</span><span class="o">.</span><span class="py">typeSymbol</span><span class="o">.</span><span class="py">fieldMembers</span><span class="o">.</span><span class="py">map</span> <span class="o">{</span> <span class="n">symbol</span> <span class="k">=&gt;</span>
  <span class="c1">// Val definition is `val name: tpt = _rhs`</span>
  <span class="k">case</span> <span class="nc">ValDef</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="n">tpt</span><span class="o">,</span> <span class="k">_</span><span class="o">)</span> <span class="k">if</span> <span class="nf">isTranslationsKey</span><span class="o">(</span><span class="nv">tpt</span><span class="o">.</span><span class="py">tpe</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">field</span><span class="k">:</span> <span class="kt">Term</span> <span class="o">=</span> <span class="nc">Select</span><span class="o">(</span><span class="n">containerTerm</span><span class="o">,</span> <span class="n">symbol</span><span class="o">)</span> <span class="c1">// container.`name`</span>
    <span class="nc">Some</span><span class="o">('{</span><span class="nv">$testsExpr</span><span class="o">.</span><span class="py">testTranslationKey</span><span class="o">(</span><span class="nc">$i</span><span class="o">{</span><span class="nv">field</span><span class="o">.</span><span class="py">asExpr</span><span class="o">})})</span>

  <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nc">None</span>
<span class="o">}.</span><span class="py">flatten</span>
</code></pre></div></div>

<p>We just get the value definitions that match and access the value on the actual container,
passing it to the function we want to call in quoted code. Easy.</p>

<h1 id="the-actual-solution">The Actual Solution</h1>

<p>Unfortunately, this doesn’t work…</p>

<p>I was hoping it would just figure out the correct overload, but the expression we get from the term <code class="language-plaintext highlighter-rouge">field</code>
is just an <code class="language-plaintext highlighter-rouge">Expr[Any]</code>.
I tried a few things to get this to work, but then I gave up and just constructed the AST manually,
applying the type arguments, arguments and resolving the givens (implicits):</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Map over all member fields of container type,</span>
  <span class="c1">// searching for all translation keys.</span>
  <span class="k">val</span> <span class="nv">calls</span> <span class="k">=</span> <span class="nv">containerType</span><span class="o">.</span><span class="py">typeSymbol</span><span class="o">.</span><span class="py">fieldMembers</span><span class="o">.</span><span class="py">map</span> <span class="o">{</span> <span class="n">symbol</span> <span class="k">=&gt;</span>
    <span class="nv">symbol</span><span class="o">.</span><span class="py">tree</span> <span class="k">match</span>
      <span class="c1">// Val definition is `val name: tpt = _`</span>
      <span class="k">case</span> <span class="nc">ValDef</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="n">tpt</span><span class="o">,</span> <span class="k">_</span><span class="o">)</span> <span class="k">if</span> <span class="nf">isTranslationsKey</span><span class="o">(</span><span class="nv">tpt</span><span class="o">.</span><span class="py">tpe</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="o">{</span>
        <span class="k">val</span> <span class="nv">field</span><span class="k">:</span> <span class="kt">Term</span> <span class="o">=</span> <span class="nc">Select</span><span class="o">(</span><span class="n">containerTerm</span><span class="o">,</span> <span class="n">symbol</span><span class="o">)</span> <span class="c1">// container.`name`</span>
        <span class="k">val</span> <span class="nv">interpolationTArgs</span> <span class="k">=</span> <span class="nv">tpt</span><span class="o">.</span><span class="py">tpe</span><span class="o">.</span><span class="py">typeArgs</span><span class="o">.</span><span class="py">tail</span> <span class="c1">// I1, I2, I3, ...</span>

        <span class="c1">// Resolve the needed `testTranslationKey` overload</span>
        <span class="k">val</span> <span class="nv">callOverload</span> <span class="k">=</span> <span class="nv">Select</span><span class="o">.</span><span class="py">overloaded</span><span class="o">(</span>
          <span class="nv">testsExpr</span><span class="o">.</span><span class="py">asTerm</span><span class="o">,</span>
          <span class="s">"testTranslationKey"</span><span class="o">,</span>
          <span class="n">interpolationTArgs</span><span class="o">,</span>
          <span class="nc">List</span><span class="o">(</span><span class="n">field</span><span class="o">)</span>
        <span class="o">)</span>

        <span class="c1">// Resolve givens/implicit for Arbitrary value generation</span>
        <span class="k">val</span> <span class="nv">arbitraryTpe</span> <span class="k">=</span>
          <span class="nc">TypeIdent</span><span class="o">(</span><span class="nv">Symbol</span><span class="o">.</span><span class="py">requiredClass</span><span class="o">(</span><span class="s">"org.scalacheck.Arbitrary"</span><span class="o">)).</span><span class="py">tpe</span>
        <span class="k">val</span> <span class="nv">implicits</span> <span class="k">=</span> <span class="nv">interpolationTArgs</span><span class="o">.</span><span class="py">map</span> <span class="o">{</span> <span class="n">t</span> <span class="k">=&gt;</span>
          <span class="nv">Implicits</span><span class="o">.</span><span class="py">search</span><span class="o">(</span><span class="nv">arbitraryTpe</span><span class="o">.</span><span class="py">appliedTo</span><span class="o">(</span><span class="n">t</span><span class="o">))</span> <span class="k">match</span>
            <span class="k">case</span> <span class="n">success</span><span class="k">:</span> <span class="kt">ImplicitSearchSuccess</span> <span class="o">=&gt;</span>
              <span class="nv">success</span><span class="o">.</span><span class="py">tree</span>
            <span class="k">case</span> <span class="n">failure</span> <span class="k">=&gt;</span>
              <span class="nv">report</span><span class="o">.</span><span class="py">errorAndAbort</span><span class="o">(</span><span class="n">s</span><span class="s">"Could not find implicit: $failure"</span><span class="o">)</span>
        <span class="o">}</span>
        <span class="k">val</span> <span class="nv">res</span> <span class="k">=</span>
          <span class="nf">if</span> <span class="o">(</span><span class="nv">implicits</span><span class="o">.</span><span class="py">nonEmpty</span><span class="o">)</span> <span class="nc">Apply</span><span class="o">(</span><span class="n">callOverload</span><span class="o">,</span> <span class="n">implicits</span><span class="o">)</span>
          <span class="k">else</span> <span class="n">callOverload</span>

        <span class="nc">Some</span><span class="o">(</span><span class="nv">res</span><span class="o">.</span><span class="py">asExpr</span><span class="o">)</span>
      <span class="o">}</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nc">None</span>
  <span class="o">}.</span><span class="py">flatten</span>
</code></pre></div></div>

<p>We need the final conditional, because at arity 0 (<code class="language-plaintext highlighter-rouge">TranslationKey0</code>) we don’t have any implicits to apply.</p>

<p>Finally, we return a code block with all the calls:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Block expression with all calls</span>
<span class="nv">Expr</span><span class="o">.</span><span class="py">block</span><span class="o">(</span><span class="n">calls</span><span class="o">,</span> <span class="o">'{</span> <span class="o">()</span> <span class="o">})</span>
</code></pre></div></div>

<p>You can find the whole code in <a href="https://github.com/cptwunderlich/translation-keys-macro">this GitHub repository</a>.</p>

<h1 id="conclusion">Conclusion</h1>

<p>Scala 3 macros are very powerful, but it takes some time getting used to thinking in this “meta” way.
Furthermore, there aren’t a ton of resources online about this topic. Maybe this article can help someone trying
to solve a similar problem.</p>

<p>If you have any suggestions on how to improve this macro, or generals suggestions, as well as questions,
just contact me via Twitter or <a href="https://github.com/cptwunderlich/cptwunderlich.github.io/discussions/2">the GitHub discussion for this post</a>.</p>]]></content><author><name>Benjamin Maurer</name></author><category term="Scala" /><category term="Scala3" /><category term="programming" /><summary type="html"><![CDATA[Porting Old Code…]]></summary></entry><entry><title type="html">Automagic Scala Migrations</title><link href="http://www.benjaminmaurer.at/2024/02/16/scala_migrations.html" rel="alternate" type="text/html" title="Automagic Scala Migrations" /><published>2024-02-16T00:00:00+00:00</published><updated>2024-02-16T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2024/02/16/scala_migrations</id><content type="html" xml:base="http://www.benjaminmaurer.at/2024/02/16/scala_migrations.html"><![CDATA[<h1 id="what--why">What &amp; Why</h1>

<p>We have an internal library and sbt plugin, which pins many library versions
and provides some base functionality.
The latest release features several larger updates, most notably Play 2.9.</p>

<p>However, there is a lot of churn related to library updates.
We use the <a href="https://github.com/scala-steward-org/scala-steward-action">scala-steward Github action</a> to keep our services up-to-date,
but when there are code changes, incompatible versions, etc. a human has to intervene.</p>

<p>This new update in particular had a few mechanic changes related to Play 2.9 and a newer <a href="https://github.com/softwaremill/tapir/releases/tag/v1.9.0">Tapir version</a>.
So to make this update less painful for my colleagues, I decided to invest some time and figure out how to build <a href="https://scalacenter.github.io/scalafix/">scalafix</a> migrations.</p>

<p>I was fantasizing about an automatic process, in which this update would get applied, merged and just magically work,
without anyone taking much notice. Alas, my expectations were soon dampened, but I did not expect it to go as badly as it did…
Anyway, I still believe that this is an awesome tool and the investment was worthwhile and will come in handy in the future.</p>

<p>This report is intended as a supplement to the tools’ documentation and might help others in their journey to automatic scala migrations - and maybe a reader will have some suggestions for me.</p>

<h1 id="the-project-setup">The Project Setup</h1>

<h2 id="the-tools">The Tools</h2>

<p>For our scala-steward Github action to run migrations, we first have to write them. The tool used to create and apply linters and migrations is scalafix. It is based on <a href="https://scalameta.org/">scalameta</a>, a library to represent and query scala programs as syntax trees, as well as storing semantic information, like types and symbols, in a database format (SemanticDB).</p>

<h2 id="the-requirements">The Requirements</h2>

<p>I did not set out to write some generally applicable scalafix rules, which should be published for anyone to use.
The migration should be very specific to our company’s needs. Our artifacts are published to our own, private Sonatype Nexus Repository and our code is in our private GitHub Enterprise organization.</p>

<p>So I have to work with these constraints. That means, that all the tools need to be able to resolve artifacts from the private repo and GitHub resources cannot be accessed without authentication.</p>

<h2 id="project-structure">Project structure</h2>

<p>Scalafix allows you to use predefined rules (both internal and community release ones), but we don’t care about this for now.</p>

<p><a href="https://scalacenter.github.io/scalafix/docs/developers/setup.html">The developer guide</a> tells us about our options to setup the project. You might want to have the rules as a sub-module in your project’s sbt build, or as a separate project all together.</p>

<p>Rules can be consumed in different forms by scalafix. You can publish them as an artifact, like any other scala code. Or you can consume their source code and let scalafix compile them on the fly. Sources can be read via the <code class="language-plaintext highlighter-rouge">file:</code>, <code class="language-plaintext highlighter-rouge">http:</code> and <code class="language-plaintext highlighter-rouge">github:</code> protocols. The <a href="https://scalacenter.github.io/scalafix/docs/developers/tutorial.html#run-the-rule-from-source-code">tutorial</a> contains some more information on this.</p>

<p>I chose to add them to the existing libraries project, as a sub-module. The migration is split up into several rules, each one taking care of a specific change. Rules are published to our Nexus repository as a compiled artifact.</p>

<p>Using the <code class="language-plaintext highlighter-rouge">github:</code> or <code class="language-plaintext highlighter-rouge">http:</code> schemes, I would have had to publish the rules on the public internet, e.g., in a gist on my personal GitHub account, because those do not work with authentication. That’s a big no-no.</p>

<p>So the folder structure started out like in the tutorial. A <code class="language-plaintext highlighter-rouge">scalafix</code> folder in my project folder and inside the <code class="language-plaintext highlighter-rouge">input</code>, <code class="language-plaintext highlighter-rouge">output</code>, <code class="language-plaintext highlighter-rouge">rules</code> and <code class="language-plaintext highlighter-rouge">tests</code> folders.
The default package name for rules you find in the tutorial (and basically all rules you find linked) is <code class="language-plaintext highlighter-rouge">fix</code>.
As I thought this is just the first migration of many, and all of them will live in this project, I named my package <code class="language-plaintext highlighter-rouge">v2_5</code> - because it is the migration to version 2.5.
If you do that and you use the <code class="language-plaintext highlighter-rouge">github:</code> scheme to run rules from source, be aware that you have to <a href="https://scalacenter.github.io/scalafix/docs/developers/tutorial.html#using-github">specify the package path</a>.</p>

<p>Also make sure to use the correct package name in the <code class="language-plaintext highlighter-rouge">resources/META-INF/services/scalafix.v1.Rule</code> file.</p>

<p>The <code class="language-plaintext highlighter-rouge">input</code> directory holds your test files, which should be rewritten. After applying a rule from <code class="language-plaintext highlighter-rouge">rules</code>, the result should match the corresponding file in <code class="language-plaintext highlighter-rouge">output</code>. All of this is orchestrated by the test runner in <code class="language-plaintext highlighter-rouge">tests</code>.</p>

<h2 id="cross-compilation">Cross Compilation</h2>

<p>In our case, I wanted to rewrite the <code class="language-plaintext highlighter-rouge">Dependencies.scala</code> of our sbt build. One of the changes was renaming an artifact. Tapir upgraded from Play 2.8 straight to Play 3.0, which replaces Akka with Pekko, <a href="https://github.com/softwaremill/tapir/releases/tag/v1.8.3">in a bugfix release</a><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. So I needed to change that to the newly created <a href="https://github.com/softwaremill/tapir/pull/3313">play29 modules</a> <code class="language-plaintext highlighter-rouge">tapir-play29-server</code>, etc.</p>

<p>To test this rule, the input file needs some sbt dependencies (e.g., for the <code class="language-plaintext highlighter-rouge">%%</code> functions). Sadly, sbt is still stuck on Scala 2.12.
So I needed to support Scala 2.12 and 2.13 inputs (I skipped Scala 3 for now).</p>

<p>I was struggling quite a bit with the correct setup, so here the short version for you.
I’m building the scalafix rules themselves with Scala 2.13 and the inputs and outputs are cross-compiled.
Dependencies are managed on a per-Scala-version basis. Here is a slightly edited version of the relevant sections from <code class="language-plaintext highlighter-rouge">build.sbt</code>:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">sbtScalaVersion</span>       <span class="k">=</span> <span class="s">"2.12.18"</span>
<span class="k">val</span> <span class="nv">scala2_13</span>             <span class="k">=</span> <span class="s">"2.13.12"</span>
<span class="k">val</span> <span class="nv">scalafixCrossVersions</span> <span class="k">=</span> <span class="n">sbtScalaVersion</span> <span class="o">::</span> <span class="nc">List</span><span class="o">(</span><span class="n">scala2_13</span><span class="o">)</span>

<span class="k">lazy</span> <span class="k">val</span> <span class="nv">`</span><span class="n">scalafix</span><span class="o">-</span><span class="n">input` = (project in file("scalafix/input"))
  .settings(
    crossScalaVersions := scalafixCrossVersions,
    evictionErrorLevel := Level.Warn,
    publish / skip := true,
    libraryDependencies ++= {
      CrossVersion.partialVersion(scalaVersion.value) match {
        case Some((2, 13)) =&gt;
          Seq(
            "com.softwaremill.sttp.tapir" %% "tapir-play-server"     % "1.8.2",
            "com.typesafe.play"           %% "play-slick"            % "5.0.2",
            "com.lightbend.akka"          %% "akka-persistence-jdbc" % "4.0.0"
          )
        case Some((2, 12)) =&gt; Seq("org.scala-sbt" % "sbt" % "1.9.8")
        case _             =&gt; Seq.empty
      }
    }
  )
  .disablePlugins(ScalafixPlugin)

lazy val `scalafix</span><span class="o">-</span><span class="n">output` = (project in file("scalafix/output"))
  .settings(
    crossScalaVersions := scalafixCrossVersions,
    publish / skip := true,
    libraryDependencies ++= {
      CrossVersion.partialVersion(scalaVersion.value) match {
        case Some((2, 13)) =&gt;
          Seq(
            "com.softwaremill.sttp.tapir" %% "tapir-play29-server"   % "1.9.8",
            "com.typesafe.play"           %% "play-slick"            % "5.2.0",
            "com.lightbend.akka"          %% "akka-persistence-jdbc" % "5.3.0"
          )
        case Some((2, 12)) =&gt; Seq("org.scala-sbt" % "sbt" % "1.9.8")
        case _             =&gt; Seq.empty
      }
    }
  )
  .disablePlugins(ScalafixPlugin)

lazy val `scalafix</span><span class="o">-</span><span class="n">rules` = (project in file("scalafix/rules"))
  .settings(commonSettings)
  .settings(
    name               := "underpin-scalafix-rules",
    scalaVersion       := scala2_13,
    crossScalaVersions := scalafixCrossVersions,
    scalacOptions += "-Ywarn-unused",
    libraryDependencies +=
      "ch.epfl.scala" %%
        "scalafix-core" %
        _root_.scalafix.sbt.BuildInfo.scalafixVersion
  )
  .disablePlugins(ScalafixPlugin)

lazy val `scalafix</span><span class="o">-</span><span class="n">tests` = (project in file("scalafix/tests"))
  .settings(
    crossScalaVersions := scalafixCrossVersions,
    publish / skip := true,
    evictionErrorLevel := Level.Warn,
    scalafixTestkitOutputSourceDirectories :=
      (`scalafix</span><span class="o">-</span><span class="n">output` / Compile / sourceDirectories).value,
    scalafixTestkitInputSourceDirectories :=
      (`scalafix</span><span class="o">-</span><span class="n">input` / Compile / sourceDirectories).value,
    scalafixTestkitInputClasspath :=
      (`scalafix</span><span class="o">-</span><span class="n">input` / Compile / fullClasspath).value,
    scalafixTestkitInputScalacOptions :=
      (`scalafix</span><span class="o">-</span><span class="n">input` / Compile / scalacOptions).value,
    scalafixTestkitInputScalaVersion :=
      (`scalafix</span><span class="o">-</span><span class="n">input` / Compile / scalaVersion).value
  )
  .dependsOn(`scalafix</span><span class="o">-</span><span class="n">input`, `scalafix</span><span class="o">-</span><span class="n">rules</span><span class="o">`)</span>
  <span class="o">.</span><span class="py">enablePlugins</span><span class="o">(</span><span class="nc">ScalafixTestkitPlugin</span><span class="o">)</span>
</code></pre></div></div>

<p>This means that I have all the sources for the rules in the usual <code class="language-plaintext highlighter-rouge">src/main/scala</code> folder,
but the input and output sources are separated in <code class="language-plaintext highlighter-rouge">src/main/scala-2.12</code> and <code class="language-plaintext highlighter-rouge">src/main/scala-2.13</code> respectively.</p>

<h1 id="writing-rules">Writing Rules</h1>

<p>This is the actual fun part!
Two important concepts to understand, is the <a href="https://scalameta.org/docs/trees/guide.html#what-is-a-syntax-tree">Syntax Tree</a> and Tokens.
The former one is a tree representation of your program, which you will write matchers against.
Tokens are the building blocks of your program and represent keywords, identifiers and even indentation etc. We typically want to modify these.</p>

<p>The <a href="https://scalacenter.github.io/scalafix/docs/developers/setup.html">scalafix guide </a> describes how to write rules and there are many existing rules you can learn from.</p>

<h2 id="syntactic-vs-semantic-rules">Syntactic vs. Semantic Rules</h2>

<p>First, we need to decide whether we want to write a <em>syntactic</em> or <em>semantic</em> rule.</p>

<p>A <em>syntactic</em> only needs a parsed program, i.e., the program structure and won’t need a semanticDB with resolved types and symbols. I’d recommend to use syntactic rules whenever possible. They are faster and they work on programs with (semantic) compilation errors. For example, you update some dependencies and multiple changes are necessary to get the program to compile again. I might be biased, because I had huge problems with semantic rules in this regard. You might also get a <code class="language-plaintext highlighter-rouge">stale semanticDB</code> error with semantic rules, if the code was modified but not compiled/a new semanticDB generated in the meantime.</p>

<p>Syntactic rules are, however, less <em>powerful</em>. For example, if your code contains unqualified uses of two types with the same name, e.g., <code class="language-plaintext highlighter-rouge">com.someframework.Url</code> and <code class="language-plaintext highlighter-rouge">org.other.Url</code>, your rule might only see an identifier <code class="language-plaintext highlighter-rouge">Url</code>. It’s up to you to make sure you are rewriting the correct ones. This might be easy, if you know your codebase and you can ascertain that such situations won’t come up, simply by grepping through your code base.</p>

<p><em>Semantic</em> rules, on the other hand, have access to the resolved types and symbols. So you can, e.g., use scalafix’ <a href="https://scalacenter.github.io/scalafix/docs/developers/symbol-matcher.html">SymbolMatcher</a> to look for occurrences of <code class="language-plaintext highlighter-rouge">com.someframework.Url</code>.
Depending on how you run your scalafix rules, you’ll need to <a href="https://scalacenter.github.io/scalafix/docs/users/installation.html#sbt">set your build to generate semanticDB files</a>, e.g.,</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">semanticdbEnabled</span> <span class="o">:=</span> <span class="kc">true</span><span class="o">,</span> <span class="c1">// enable SemanticDB</span>
<span class="n">semanticdbVersion</span> <span class="o">:=</span> <span class="nv">scalafixSemanticdb</span><span class="o">.</span><span class="py">revision</span><span class="o">,</span> <span class="c1">// only required for Scala 2.x</span>
</code></pre></div></div>

<h2 id="what-to-match">What to Match</h2>

<p>I’m typically starting out by building a minimal example of what I want to rewrite (as input)
and what I would like it to look like afterwards (the output).
If you can think of any edge cases, or similar looking code you <em>don’t want to rewrite</em>, put that into the test as well.</p>

<p>Then paste the code into the <a href="https://scalameta.org/docs/trees/astexplorer.html">Scalameta AST Explorer</a>, to get an idea what the syntax tree looks like.
Besides that, I found looking at the Scalameta <a href="https://github.com/scalameta/scalameta/blob/9df6bbfc4d9bd67ae6e0a51283dee3d5f944d7c5/scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala">source for Tree nodes</a> helpful to find out, what nodes I can match against.</p>

<p>Other than that, I start by writing my matchers and placing plenty of <code class="language-plaintext highlighter-rouge">println</code>s inside, to orient myself (and see how wrong I got things).</p>

<h1 id="a-concrete-example">A Concrete Example</h1>

<p>Let’s start with a syntactic rule.
<a href="https://github.com/softwaremill/tapir/releases/tag/v1.9.0#DecodeFailureHandler">Tapir’s DecodeFailureHandler</a> has changed.</p>

<p>What used to be</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">DecodeFailureHandler</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">apply</span><span class="o">(</span><span class="n">ctx</span><span class="k">:</span> <span class="kt">DecodeFailureContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]]</span>
<span class="o">}</span>
</code></pre></div></div>

<p>got a type argument for an effect type:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">DecodeFailureHandler</span><span class="o">[</span><span class="kt">F</span><span class="o">[</span><span class="k">_</span><span class="o">]]</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">apply</span><span class="o">(</span><span class="n">ctx</span><span class="k">:</span> <span class="kt">DecodeFailureContext</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">monad</span><span class="k">:</span> <span class="kt">MonadError</span><span class="o">[</span><span class="kt">F</span><span class="o">])</span><span class="k">:</span> <span class="kt">F</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]]]</span>
<span class="o">}</span>
</code></pre></div></div>

<p>So I took a look at our actual DecodeFailureHandlers and made this test input:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
rule = FailureHandler
*/</span>
<span class="k">import</span> <span class="nn">sttp.tapir.server.interceptor.decodefailure.</span><span class="o">{</span><span class="nc">DecodeFailureHandler</span><span class="o">,</span> <span class="nc">DefaultDecodeFailureHandler</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">sttp.tapir.server.model.ValuedEndpointOutput</span>
<span class="k">import</span> <span class="nn">sttp.tapir.server.interceptor.DecodeFailureContext</span>
<span class="k">import</span> <span class="nn">scala.concurrent.ExecutionContext</span>

<span class="k">class</span> <span class="nc">FailureHandler</span> <span class="k">extends</span> <span class="nc">DecodeFailureHandler</span> <span class="o">{</span>

  <span class="k">private</span> <span class="k">def</span> <span class="nf">renderResponse</span><span class="o">()</span><span class="k">:</span> <span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]</span> <span class="k">=</span> <span class="o">???</span>

  <span class="k">override</span> <span class="k">def</span> <span class="nf">apply</span><span class="o">(</span><span class="n">ctx</span><span class="k">:</span> <span class="kt">DecodeFailureContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="nv">DefaultDecodeFailureHandler</span><span class="o">.</span><span class="py">respond</span><span class="o">(</span><span class="n">ctx</span><span class="o">)</span> <span class="k">match</span> <span class="o">{</span>
        <span class="k">case</span> <span class="nc">Some</span><span class="o">((</span><span class="n">sc</span><span class="o">,</span> <span class="n">hs</span><span class="o">))</span> <span class="k">=&gt;</span>
          <span class="nc">Some</span><span class="o">(</span><span class="nf">renderResponse</span><span class="o">())</span>
        <span class="k">case</span> <span class="nc">None</span> <span class="k">=&gt;</span>
          <span class="nc">None</span>
      <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="k">class</span> <span class="nc">DifferentClass</span> <span class="o">{</span>
  <span class="c1">// Dummy to keep EC import</span>
  <span class="k">def</span> <span class="nf">bar</span><span class="o">(</span><span class="n">ec</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span> <span class="k">=</span> <span class="o">???</span>

  <span class="c1">// Don't rewrite this</span>
  <span class="k">def</span> <span class="nf">apply</span><span class="o">(</span><span class="n">ctx</span><span class="k">:</span> <span class="kt">DecodeFailureContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="o">???</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>As this rule is intended for our services using Play, we’ll use <code class="language-plaintext highlighter-rouge">Future</code> as our effect type.
The second class was added, to make sure my rule wouldn’t rewrite similar looking code. The <code class="language-plaintext highlighter-rouge">ExecutionContext</code> import was added,
because my first draft messed up some code which already had the EC import.</p>

<p>And what is our desired output? We need some imports (potentially), substitute F with Future, add the implicit MonadError and wrap the result in a Future:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">sttp.tapir.server.interceptor.decodefailure.</span><span class="o">{</span><span class="nc">DecodeFailureHandler</span><span class="o">,</span> <span class="nc">DefaultDecodeFailureHandler</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">sttp.tapir.server.model.ValuedEndpointOutput</span>
<span class="k">import</span> <span class="nn">sttp.tapir.server.interceptor.DecodeFailureContext</span>
<span class="k">import</span> <span class="nn">scala.concurrent.ExecutionContext</span>
<span class="k">import</span> <span class="nn">scala.concurrent.Future</span>
<span class="k">import</span> <span class="nn">sttp.monad.MonadError</span>

<span class="k">class</span> <span class="nc">FailureHandler</span><span class="o">()(</span><span class="k">implicit</span> <span class="n">ec</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">DecodeFailureHandler</span><span class="o">[</span><span class="kt">Future</span><span class="o">]</span> <span class="o">{</span>

  <span class="k">private</span> <span class="k">def</span> <span class="nf">renderResponse</span><span class="o">()</span><span class="k">:</span> <span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]</span> <span class="k">=</span> <span class="o">???</span>

  <span class="k">override</span> <span class="k">def</span> <span class="nf">apply</span><span class="o">(</span><span class="n">ctx</span><span class="k">:</span> <span class="kt">DecodeFailureContext</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">monad</span><span class="k">:</span> <span class="kt">MonadError</span><span class="o">[</span><span class="kt">Future</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]]]</span> <span class="k">=</span> <span class="nc">Future</span> <span class="o">{</span>
      <span class="nv">DefaultDecodeFailureHandler</span><span class="o">.</span><span class="py">respond</span><span class="o">(</span><span class="n">ctx</span><span class="o">)</span> <span class="k">match</span> <span class="o">{</span>
        <span class="k">case</span> <span class="nc">Some</span><span class="o">((</span><span class="n">sc</span><span class="o">,</span> <span class="n">hs</span><span class="o">))</span> <span class="k">=&gt;</span>
          <span class="nc">Some</span><span class="o">(</span><span class="nf">renderResponse</span><span class="o">())</span>
        <span class="k">case</span> <span class="nc">None</span> <span class="k">=&gt;</span>
          <span class="nc">None</span>
      <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="k">class</span> <span class="nc">DifferentClass</span> <span class="o">{</span>
  <span class="c1">// Dummy to keep EC import</span>
  <span class="k">def</span> <span class="nf">bar</span><span class="o">(</span><span class="n">ec</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span> <span class="k">=</span> <span class="o">???</span>

  <span class="c1">// Don't rewrite this</span>
  <span class="k">def</span> <span class="nf">apply</span><span class="o">(</span><span class="n">ctx</span><span class="k">:</span> <span class="kt">DecodeFailureContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ValuedEndpointOutput</span><span class="o">[</span><span class="k">_</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="o">???</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Great. Let’s start with the rule:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">v2_5</span>

<span class="k">import</span> <span class="nn">scalafix.v1._</span>
<span class="k">import</span> <span class="nn">scala.meta._</span>

<span class="k">class</span> <span class="nc">FailureHandler</span> <span class="k">extends</span> <span class="nc">SyntacticRule</span><span class="o">(</span><span class="s">"FailureHandler"</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">isRewrite</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=</span> <span class="kc">true</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">description</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">"You can add a description, if you like"</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">fix</span><span class="o">(</span><span class="k">implicit</span> <span class="n">doc</span><span class="k">:</span> <span class="kt">SyntacticDocument</span><span class="o">)</span><span class="k">:</span> <span class="kt">Patch</span> <span class="o">=</span> <span class="o">???</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">fix</code> method is where the magic happens.
As a starting point, we want to match on a class definition, which extends <code class="language-plaintext highlighter-rouge">sttp.tapir.server.interceptor.decodefailure.DecodeFailureHandler</code>.
I’m cutting some corners here. Syntactic rules are simpler, as mentioned above. I am able to grep our entire code base,
so I know, that we don’t have any other <code class="language-plaintext highlighter-rouge">DecodeFailureHandler</code> this one could be confused with.
This is actually a very specific scenario and I know very well which files this should affect.
So I can get away with a syntactic rule, just matching on “some class” extending something named “DecodeFailureHandler”.
You could use scalafix’ <a href="https://scalacenter.github.io/scalafix/docs/developers/symbol-information.html#lookup-class-parents">Symbol</a> to lookup a class and its parents. But that needs semantic information.</p>

<p>Let’s match on a class definition:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">override</span> <span class="k">def</span> <span class="nf">fix</span><span class="o">(</span><span class="k">implicit</span> <span class="n">doc</span><span class="k">:</span> <span class="kt">SemanticDocument</span><span class="o">)</span><span class="k">:</span> <span class="kt">Patch</span> <span class="o">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">clazz</span> <span class="k">=</span> <span class="nv">doc</span><span class="o">.</span><span class="py">tree</span><span class="o">.</span><span class="py">collect</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">c</span> <span class="k">@</span> <span class="nv">Defn</span><span class="o">.</span><span class="py">Class</span><span class="o">.</span><span class="py">After_4_6_0</span><span class="o">(</span>
            <span class="k">_</span><span class="o">,</span>
            <span class="n">name</span><span class="o">,</span>
            <span class="n">params</span><span class="o">,</span>
            <span class="nv">Ctor</span><span class="o">.</span><span class="py">Primary</span><span class="o">.</span><span class="py">After_4_6_0</span><span class="o">(</span><span class="k">_</span><span class="o">,</span> <span class="k">_</span><span class="o">,</span> <span class="n">ctorParams</span><span class="o">),</span>
            <span class="nv">Template</span><span class="o">.</span><span class="py">After_4_4_0</span><span class="o">(</span><span class="k">_</span><span class="o">,</span>
                                 <span class="nc">List</span><span class="o">(</span><span class="nv">Init</span><span class="o">.</span><span class="py">After_4_6_0</span><span class="o">(</span><span class="nv">Type</span><span class="o">.</span><span class="py">Name</span><span class="o">(</span><span class="s">"DecodeFailureHandler"</span><span class="o">),</span> <span class="nv">Name</span><span class="o">.</span><span class="py">Anonymous</span><span class="o">(),</span> <span class="nc">Nil</span><span class="o">)),</span>
                                 <span class="k">_</span><span class="o">,</span>
                                 <span class="n">stats</span><span class="o">,</span>
                                 <span class="k">_</span><span class="o">))</span> <span class="k">if</span> <span class="nv">params</span><span class="o">.</span><span class="py">values</span><span class="o">.</span><span class="py">isEmpty</span> <span class="o">&amp;&amp;</span> <span class="nv">ctorParams</span><span class="o">.</span><span class="py">isEmpty</span> <span class="k">=&gt;</span> <span class="o">???</span>
        <span class="c1">// More to come...</span>
  <span class="o">}</span>
  <span class="o">???</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Note that the <code class="language-plaintext highlighter-rouge">fix</code> method returns a <a href="https://scalacenter.github.io/scalafix/docs/developers/patch.html">Patch</a>, which represents the changes we are performing. This type is very important, you’ll need those methods to generate the changes you want.</p>

<p>Inside the method, we apply our partial function to the syntax tree with <code class="language-plaintext highlighter-rouge">collect</code>.
The <code class="language-plaintext highlighter-rouge">Defn.Class</code> node represents a class definition. What about the ugly <code class="language-plaintext highlighter-rouge">After_4_6_0</code>? Scalameta uses these versioned matchers for backwards compatibility. This is a great thing, otherwise every new version might break your rules.</p>

<p>The class definition contains a bunch of stuff: <code class="language-plaintext highlighter-rouge">Defn.Class(modifiers, name, paramClause, ctor, template)</code>.
This <code class="language-plaintext highlighter-rouge">Template</code> structure is very confusing, but contains lots of things we care about. Looking at this in the <a href="https://astexplorer.net/#/gist/ec56167ffafb20cbd8d68f24a37043a9/24f036976d6f7869e4b4cc74bd835c43093b8c2f">AST explorer</a> brings some clarity.</p>

<p>Note that this matches syntactically, i.e., this matches only if the class only extends <code class="language-plaintext highlighter-rouge">DecodeFailureHandler</code>. If you test for multiple super-classes, you’ll have to search the list of <code class="language-plaintext highlighter-rouge">Inits</code> (or use a semantic rule).
I’m also testing for “no type parameters” and “empty constructor”, because that’s what I see in our code base. Your mileage may vary.</p>

<p>Now I want to modify the class definition, by adding an implicit argument and by adding <code class="language-plaintext highlighter-rouge">[Future]</code> to <code class="language-plaintext highlighter-rouge">DecodeFailureHandler</code> and by wrapping <code class="language-plaintext highlighter-rouge">Future.apply</code> around the method body. I know that all source files I want to rewrite use curly braces around the body, so I can get away with simply placing <code class="language-plaintext highlighter-rouge">Future</code> before the opening brace <code class="language-plaintext highlighter-rouge">{</code>.
This means I want a patch that manipulates the tokens of the tree node we just matched:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// continued in the match above</span>
<span class="k">val</span> <span class="nv">tokens</span>     <span class="k">=</span> <span class="nv">c</span><span class="o">.</span><span class="py">tokens</span>  <span class="c1">// Tokens of the class definition</span>
<span class="k">val</span> <span class="nv">identifier</span> <span class="k">=</span> <span class="nv">tokens</span><span class="o">.</span><span class="py">find</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">is</span><span class="o">[</span><span class="kt">Token.Ident</span><span class="o">])</span> <span class="c1">// First identifier should be the name of declared class</span>
<span class="k">val</span> <span class="nv">traitName</span>  <span class="k">=</span> <span class="nv">tokens</span><span class="o">.</span><span class="py">find</span> <span class="o">{</span> <span class="k">case</span> <span class="nv">Token</span><span class="o">.</span><span class="py">Ident</span><span class="o">(</span><span class="s">"DecodeFailureHandler"</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="kc">true</span><span class="o">;</span> <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="kc">false</span> <span class="o">}</span> <span class="c1">// Find the token in the `extends` clause</span>
</code></pre></div></div>

<p>Patch lets us add text left or right of tokens, replace tree nodes, remove tokens, etc.
So given <code class="language-plaintext highlighter-rouge">FailureHandler</code> (remember, no type parameters, no constructors), we want <code class="language-plaintext highlighter-rouge">FailureHandler()(implicit ec: ExecutionContext)</code>. We can just replace the identifier token: <code class="language-plaintext highlighter-rouge">Patch.replaceToken(identifier.get, s"${name.value}()(implicit ec: ExecutionContext)")</code><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>. Yes, we’re playing fast and loose with Options here, but I’m sure that token exists, since we matched the tree node.</p>

<p>Adding the type argument to <code class="language-plaintext highlighter-rouge">DecodeFailureHandler</code> is even easier: <code class="language-plaintext highlighter-rouge">Patch.addRight(traitName.get, "[Future]")</code>.</p>

<p>How do we get to the <code class="language-plaintext highlighter-rouge">apply</code> method? See this <code class="language-plaintext highlighter-rouge">stats</code> field in the class definitions template above?
These are the <em>statements</em> that make up the body of the class.
We need to match on those statements, to find the right method definition:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nv">stats</span><span class="o">.</span><span class="py">collect</span> <span class="o">{</span> <span class="k">case</span> <span class="n">m</span> <span class="k">@</span> <span class="nv">Defn</span><span class="o">.</span><span class="py">Def</span><span class="o">.</span><span class="py">After_4_7_3</span><span class="o">(</span><span class="n">mods</span><span class="o">,</span> <span class="nv">Term</span><span class="o">.</span><span class="py">Name</span><span class="o">(</span><span class="s">"apply"</span><span class="o">),</span> <span class="k">_</span><span class="o">,</span> <span class="nc">Some</span><span class="o">(</span><span class="n">tpe</span><span class="o">),</span> <span class="n">body</span><span class="o">)</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">modsStr</span> <span class="k">=</span> <span class="nv">mods</span><span class="o">.</span><span class="py">mkString</span><span class="o">(</span><span class="s">" "</span><span class="o">)</span>
    <span class="nv">Patch</span><span class="o">.</span><span class="py">replaceTree</span><span class="o">(</span>
      <span class="n">m</span><span class="o">,</span>
      <span class="n">s</span><span class="s">"$modsStr def apply(ctx: DecodeFailureContext)(implicit monad: MonadError[Future]): Future[$tpe] = Future $body"</span><span class="o">)</span>
  <span class="o">}.</span><span class="py">asPatch</span>
</code></pre></div></div>

<p>Again, I can simplify things a bit, because I know what the code looks like, on which this rule will be applied.
I’m simply replacing the whole tree node, instead of fiddling around with tokens.</p>

<p>These three patches need to be assembled into one, e.g., like so: <code class="language-plaintext highlighter-rouge">Patch.fromIterable(Seq(p1, p2, p3))</code>.</p>

<p>The last piece missing is the imports. I know that some of the sources have some of the required imports, so I don’t want to add them unconditionally (although this could be cleaned up with another scalafix rule, <code class="language-plaintext highlighter-rouge">RemoveUnused</code>), but the <code class="language-plaintext highlighter-rouge">MonadError</code> import is never present:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">val</span> <span class="nv">imports</span> <span class="k">=</span> <span class="nv">Patch</span><span class="o">.</span><span class="py">addGlobalImport</span><span class="o">(</span><span class="n">importer</span><span class="s">"sttp.monad.MonadError"</span><span class="o">)</span> <span class="o">+</span>
    <span class="o">(</span><span class="nf">if</span> <span class="o">(</span><span class="nf">hasImport</span><span class="o">(</span><span class="nv">doc</span><span class="o">.</span><span class="py">tree</span><span class="o">,</span> <span class="s">"Future"</span><span class="o">))</span> <span class="nv">Patch</span><span class="o">.</span><span class="py">empty</span>
      <span class="k">else</span> <span class="nv">Patch</span><span class="o">.</span><span class="py">addGlobalImport</span><span class="o">(</span><span class="n">importer</span><span class="s">"scala.concurrent.Future"</span><span class="o">))</span> <span class="o">+</span>
    <span class="o">(</span><span class="nf">if</span> <span class="o">(</span><span class="nf">hasImport</span><span class="o">(</span><span class="nv">doc</span><span class="o">.</span><span class="py">tree</span><span class="o">,</span> <span class="s">"ExecutionContext"</span><span class="o">))</span> <span class="nv">Patch</span><span class="o">.</span><span class="py">empty</span>
      <span class="k">else</span> <span class="nv">Patch</span><span class="o">.</span><span class="py">addGlobalImport</span><span class="o">(</span><span class="n">importer</span><span class="s">"scala.concurrent.ExecutionContext"</span><span class="o">))</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">hasImport</code> method just matches on the tree, looking for <code class="language-plaintext highlighter-rouge">Import</code> statements.</p>

<p>Since we only want to add the imports, if this file <em>actually contains</em> a failure handler, we assemble the final patch conditionally:</p>

<p><code class="language-plaintext highlighter-rouge">if (clazz.isEmpty) Patch.empty else (imports + clazz)</code></p>

<p>The complete rule can be found in this <a href="https://gist.github.com/cptwunderlich/8cbb9ae09b0d7cabdcd4a8b72183c363">gist</a>.</p>

<h1 id="semantic-rules">Semantic Rules</h1>

<p>Additionally to what you can do in a syntactic rule, you may also use <a href="https://scalacenter.github.io/scalafix/docs/developers/symbol-matcher.html">symbol matchers</a> and so on.</p>

<p>You can use a symbol matcher in a pattern matching a tree node. For example, if we want to match an element in a parameter list of type <code class="language-plaintext highlighter-rouge">play.api.ApplicationLoader.Context</code>, we can do this like so:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">private</span> <span class="k">def</span> <span class="nf">patchContextParam</span><span class="o">(</span><span class="n">paramClause</span><span class="k">:</span> <span class="kt">Term.ParamClause</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">doc</span><span class="k">:</span> <span class="kt">SemanticDocument</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">contextMatcher</span> <span class="k">=</span> <span class="nv">SymbolMatcher</span><span class="o">.</span><span class="py">exact</span><span class="o">(</span><span class="s">"play/api/ApplicationLoader.Context#"</span><span class="o">)</span>

    <span class="nv">paramClause</span><span class="o">.</span><span class="py">values</span><span class="o">.</span><span class="py">collect</span> <span class="o">{</span> <span class="k">case</span> <span class="n">p</span> <span class="k">@</span> <span class="nv">Term</span><span class="o">.</span><span class="py">Param</span><span class="o">(</span><span class="k">_</span><span class="o">,</span> <span class="n">name</span><span class="o">,</span> <span class="nc">Some</span><span class="o">(</span><span class="nf">contextMatcher</span><span class="o">(</span><span class="n">tpe</span><span class="o">)),</span> <span class="k">_</span><span class="o">)</span> <span class="k">=&gt;</span>
      <span class="nv">Patch</span><span class="o">.</span><span class="py">replaceTree</span><span class="o">(</span><span class="n">p</span><span class="o">,</span> <span class="n">s</span><span class="s">"$name: $tpe"</span><span class="o">)</span>
    <span class="o">}.</span><span class="py">asPatch</span>
  <span class="o">}</span>
</code></pre></div></div>

<p>We place the matcher <code class="language-plaintext highlighter-rouge">contextMatcher(_)</code> where want to match a tree node in our match expression.
The name in parenthesis is bound to the matched tree node.</p>

<h1 id="applying-rules">Applying Rules</h1>

<p>This is where things got complicated for me.</p>

<h2 id="private-repos">Private Repos</h2>

<p>As outlined in the beginning, we need to publish rules to a private repository.
This simply uses our normal release process. It just pushes some jar files to Nexus.</p>

<p>When <em>consuming</em> rules from a private repository though, you need to add a <em>resolver</em>.
We have an sbt resolver configured for our normal dependencies, but we need an additional <em>scalafixResolver</em>.</p>

<p>If you want to use the rules from your sbt project, add the resolver to the build:</p>

<p><code class="language-plaintext highlighter-rouge">ThisBuild / scalafixResolvers += coursierapi.MavenRepository.of("https://private.reposit.ory")</code></p>

<p>Since I created these migrations for use with scala-steward, this is not necessary (I will explain scala-stewards mechanism soon).
But it is useful for testing and applying rules manually.
You can also add it to the current sbt session only, by typing <code class="language-plaintext highlighter-rouge">set ThisBuild / scalafixResolvers += coursierapi.MavenRepository.of("https://private.reposit.ory")</code> in the sbt console.</p>

<h2 id="sbt-vs-scalafix-cli">Sbt vs. scalafix-cli</h2>

<p>When run from the sbt build, the scalafix rules can’t rewrite the sbt build files themselves. Like that <code class="language-plaintext highlighter-rouge">Dependency.scala</code> file I wanted to rewrite, remember? At least, I haven’t found a way to achieve this.</p>

<p>But there is a <a href="https://scalacenter.github.io/scalafix/docs/users/installation.html#command-line">scalafix CLI tool</a>, which can be applied to any file.</p>

<p>This is especially useful for standard rules and those published via http/GitHub. To use artifacts from a private repository, you need to resolve them yourself. Luckily, that is quite simple with coursier:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scalafix \
  --tool-classpath $(cs fetch my.org::my-scalafix-rules:2.5.0 -p) \
  -r TapirPlay29Dependencies \
  ~/myproject/project/Dependencies.scala
</code></pre></div></div>

<p>You may also want to use the <code class="language-plaintext highlighter-rouge">--scala-version</code> flag. I wrote and published my rules in Scala 2.13, which is the current default.</p>

<p>One <em>important thing</em> to note is the double semicolon <code class="language-plaintext highlighter-rouge">::</code> in the artifact coordinates. This works similar to sbt’s <code class="language-plaintext highlighter-rouge">%%</code> for cross-compiling. Many of the existing rules and examples use only one semicolon. Apparently, this is from an older version, which didn’t support cross-publishing. You might have to add the version suffix (“_2.13”) if you use that.</p>

<h1 id="scala-steward">Scala-Steward</h1>

<p>The star of the show! Let’s put everything together to realize my dream of <em>automagic</em> upgrades!</p>

<h2 id="try-before-you-buy">Try Before You Buy!</h2>

<p>The good thing about reading blog posts about things is, that you don’t have to go through the mistakes the author has gone through in order to write this.</p>

<p>When scala-steward opens a PR on GitHub - that’s it! If you mess up the config, or your rules don’t work quite like you wanted, you don’t get a second chance. You can’t delete PRs, only close them. Scala-steward will see a closed PR for the given version and that’s that.</p>

<p>So to test your config, you can issue updates against a different branch from <em>main</em>.
To make testing simpler, I used the scala-steward docker container.</p>

<p>Here is the magical incantation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run -v /home/ben/Projects/scala-steward-test:/opt/scala-steward \
  -v /home/ben/.sbt:/root/.sbt \
  -v /home/ben/.config/coursier:/root/.config/coursier \
  --env COURSIER_REPOSITORIES="ivy2Local|central|https://my.private.repo" \
  -it fthomas/scala-steward:latest \
  --workspace  "/opt/scala-steward/workspace" \
  --git-author-email "benjamin.maurer@noreply.com" \
  --do-not-fork \
  --forge-login "scala-steward-test" \
  --repos-file "/opt/scala-steward/repos.md" \
  --repo-config "/opt/scala-steward/default.scala-steward.conf" \
  --git-ask-pass "/opt/scala-steward/.github/askpass/pass.sh" \
  --scalafix-migrations "/opt/scala-steward/scalafix-migrations.conf"
</code></pre></div></div>

<p>What does this mean?
I’m mounting the directory <code class="language-plaintext highlighter-rouge">/home/ben/Projects/scala-steward-test</code> as <code class="language-plaintext highlighter-rouge">/opt/scala-steward</code> in the container. I have all the configuration files in this folder.
The folders <code class="language-plaintext highlighter-rouge">~/.sbt</code> and <code class="language-plaintext highlighter-rouge">~/.config/coursier</code> are mounted into the container, so it has my credentials for the private repository (this is not a very secure way of doing things, but for a quick test, it’s OK).
The environment variable <code class="language-plaintext highlighter-rouge">COURSIER_REPOSITORIES</code> tells coursier which repositories to use to resolve artifacts.
My <code class="language-plaintext highlighter-rouge">pass.sh</code> is a very janky construct, that just echos my personal <a href="https://github.com/settings/tokens">GitHub access token</a>.</p>

<p><code class="language-plaintext highlighter-rouge">repos.md</code> contains the repository configuration. It’s a markdown list in the format <code class="language-plaintext highlighter-rouge">- org/repo[:branch]</code>.
If you don’t specify a branch, it will use main/master.</p>

<p><code class="language-plaintext highlighter-rouge">default.scala-steward.conf</code> the, well, default scala-steward config (can be overwritten with project specific configs).
You might want to allow pre-release updates for your artifact, if you are testing migrations before the release:
<code class="language-plaintext highlighter-rouge">updates.allowPreReleases = [ { groupId = "my.org", artifactId = "my-artifact" } ]</code></p>

<p><code class="language-plaintext highlighter-rouge">scalafix-migrations.conf</code> contains the list of migrations.
I found the <a href="https://github.com/scala-steward-org/scala-steward/blob/main/docs/scalafix-migrations.md">documentation</a> of this a bit lacking, but you can take a <a href="https://github.com/scala-steward-org/scala-steward/blob/main/modules/core/src/main/scala/org/scalasteward/core/edit/scalafix/ScalafixMigration.scala#L28">look at the sources</a> to find out what all the fields mean (I’m planning on improving the docs).</p>

<p>Here an example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>migrations = [
  {
    groupId: "my.org",
    artifactIds: ["my-artifact"],
    newVersion: "2.5.0-RC1",
    rewriteRules: [
        "dependency:FailureHandler@my.org::my-scalafix-rules:2.5.0-RC7",
        "replace:akka.persistence.jdbc.config.JournalTableConfiguration/akka.persistence.jdbc.config.LegacyJournalTableConfiguration"
    ],
    executionOrder: "post-update",
    target: "sources",
    doc: "https://cptwunderlich.github.io/"
  }
]
</code></pre></div></div>

<p>First you define for <em>which</em> artifact and version the migration applies. <code class="language-plaintext highlighter-rouge">rewriteRules</code> contains a list of scalafix rules, with a protocol prefix (http, github, dependency…), unless it is a built-in rule.</p>

<p>Now it gets interesting. <code class="language-plaintext highlighter-rouge">executionOrder</code> can be <code class="language-plaintext highlighter-rouge">pre-update</code>, i.e., before the artifact version is incremented, or <code class="language-plaintext highlighter-rouge">post-update</code>.
According to the docs, a <code class="language-plaintext highlighter-rouge">pre-update</code> migration could affect the update, so it is resolved again (i.e., you may change <code class="language-plaintext highlighter-rouge">Dependencies.scala</code>).</p>

<p><code class="language-plaintext highlighter-rouge">target</code> can be <code class="language-plaintext highlighter-rouge">sources</code> or <code class="language-plaintext highlighter-rouge">build</code>. This one’s interesting and not well documented. Basically, “sources” is a transformation of the project’s sources, just like the sbt-based scalafix invocation seen earlier. “build” can be applied to the build files.
And if we look at the implementation, this actually maps to the sbt-scalafix vs scalafix-cli scenario above.
There is a difference though. “source” creates a new sbt project and sets the <code class="language-plaintext highlighter-rouge">scalafixResolvers</code> from the coursier resolvers. That’s why you don’t need to set the <code class="language-plaintext highlighter-rouge">scalafixResolver</code> in your project for scala-steward - and on the flipside only setting it there won’t make it work in scala-steward.</p>

<p>This brings me to my first big defeat: the “build” variant invokes scalafix-cli, which can’t resolve artifacts from private repositories on its own. The trick above with downloading dependencies with coursier and using <code class="language-plaintext highlighter-rouge">--tools-classpath</code> doesn’t work, because scala-steward can’t do this.
For now, this just doesn’t work and there is no way to run a shell script or similar. (But maybe we can make this work <a href="https://github.com/scala-steward-org/scala-steward/issues/3276">#3276</a>, <a href="https://github.com/scala-steward-org/scala-steward/pull/3133">#3133</a>).
I also tried using an artifact migration for this, but this seems to only be triggered if there is a new version for the artifact to be migrated. It didn’t work either way.</p>

<h2 id="github-action">Github Action</h2>

<p>I added the <code class="language-plaintext highlighter-rouge">scalafix-migration.conf</code> to the root directory of our GitHub repo with the config for the <a href="https://github.com/scala-steward-org/scala-steward-action">scala-steward GitHub action</a>.</p>

<p>To the job’s steps, I added the checkout action and then I can simply refer to the config file:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">jobs</span><span class="pi">:</span>
  <span class="na">scala-steward</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-22.04</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Launch Scala Steward</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Add SBT credentials for Nexus</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="c1"># redacted</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout repo so migrations config is available</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Launch Scala Steward</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">scala-steward-org/scala-steward-action@v2</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">github-app-id</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">github-app-installation-id</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">github-app-key</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">scalafix-migrations</span><span class="pi">:</span> <span class="s1">'</span><span class="s">scalafix-migrations.conf'</span>
</code></pre></div></div>

<h1 id="conclusion">Conclusion</h1>

<p>So, did I achieve an automatic upgrade? Far from it.
Scalafix and scala-steward are amazing tools and I’m happy I invested the time. I’m sure this will make future migrations easier.</p>

<h2 id="limitations">Limitations</h2>

<p>There are a few limitations though:</p>

<ol>
  <li>I didn’t mention it so far, but you can’t change configuration files this way.</li>
  <li>Migrations of build files don’t work with private repos - you’ll need to publish to maven central, or put the source on a public GitHub repo or web site.</li>
  <li>Migrations can fail if the code doesn’t compile, or the semanticDB is stale (and the PR will be opened nonetheless <a href="https://github.com/scala-steward-org/scala-steward/issues/3273">#3273</a>).</li>
</ol>

<p>I’m not quite sure I understand nr. 3 completely. After upgrading the dependency, the code doesn’t compile anymore. Syntactic rules still work, bc. those are not parser errors, but type errors.
It seems like semantic rules don’t work on sources that don’t compile (yet). Maybe bc. scala-steward checks the project out and doesn’t have old semanticDBs lying around?
Speaking of which, some users report the error “stale semanticDB found”. This might be the case, if one rule changes the code, but it is not re-compiled - not quite sure.</p>

<p>In general have I seen issue when mixing multiple semantic rules. Sometimes it seems like the first rule works, but then the code doesn’t compile properly so the second rule doesn’t. This is just anecdotal, I have not investigated this. But the built-in <code class="language-plaintext highlighter-rouge">replace</code> rule seems never to work for me in combination with other rules. I just went back to using <code class="language-plaintext highlighter-rouge">sed</code> where possible.</p>

<h2 id="documentation">Documentation</h2>

<p>I think the docs can be improved. I had quite the hard start with scalafix. But it might be me.
Now in hindsight, the docs make a lot of sense to me. But in the beginning, I didn’t quite get it and more importantly, I couldn’t find a lot of things.</p>

<p>A few words on cross-compilation, or rather which Scala versions to use might be helpful. I wasn’t sure whether rules had to be compiled with the same version as the code they are applied to (seems like they don’t).
I also at first thought, that they require Scala 2.12, like sbt does. But the rules I looked at seem to be old.
Scala 2.13 is the default, AFAIK.</p>

<p>The scala-steward documentation lacks a description of the config values for migrations.
Private repos could also do with some better explanations.</p>

<p>I hope I can contribute this sometime soon.</p>

<p>If you start out with scalafix (and scala-steward), don’t make the same mistake I did - take more notes on which things caused you problems, or where the docs were not clear enough. That will help to improve them!</p>

<h2 id="pebkac">PEBKAC</h2>

<p>Remember those double semicolons? They are important!
After all the testing and releasing libraries and preparatory work, I messed up the scala-steward config in a flurry.
I had single semicolons and scala-steward tried to resolve the wrong version.
So instead of half-applied migrations, I got none…</p>

<p>My colleagues had to make due with a migration guide, containing lots of <code class="language-plaintext highlighter-rouge">sed</code> commands and big <code class="language-plaintext highlighter-rouge">scalafix</code> incantation.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>I won’t forget, I won’t forgive. /jk <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Can’t remember why I didn’t just add the text right of the token, but I probably tried that. ¯_(ツ)_/¯ <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Benjamin Maurer</name></author><category term="scala" /><category term="scalafix" /><category term="scalameta" /><category term="scala-steward" /><category term="programming" /><summary type="html"><![CDATA[What &amp; Why]]></summary></entry><entry><title type="html">SSA transformation for GHC’s native code generator (Part 3)</title><link href="http://www.benjaminmaurer.at/2021/07/27/ssa_for_ncg_part3.html" rel="alternate" type="text/html" title="SSA transformation for GHC’s native code generator (Part 3)" /><published>2021-07-27T00:00:00+00:00</published><updated>2021-07-27T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2021/07/27/ssa_for_ncg_part3</id><content type="html" xml:base="http://www.benjaminmaurer.at/2021/07/27/ssa_for_ncg_part3.html"><![CDATA[<h1 id="another-try">Another Try</h1>

<p>In the <a href="/2021/04/27/ssa_for_ncg_part1.html">first</a> <a href="/2021/04/30/ssa_for_ncg_part2.html">two</a> parts of this series,
I described my motivations for bringing <abbr title="Static Single Assignment">SSA</abbr> transformation to <abbr title="GHC's Native Code Generator">NCG</abbr>, what <abbr title="Static Single Assignment">SSA</abbr> form is and an evaluation of my implementation.</p>

<p>My original implementation used the classic Cytron et al. algorithm. The reason for that was, that a) there was plenty of literature
on that (e.g. in “Engineering a Compiler”) and b) that <abbr title="Glasgow Haskell Compiler">GHC</abbr> already had functions to calculate the dominators etc.
To be honest, I did look at the Braun et al.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> paper (which is probably the most popular one these days), but I found it a bit confusing.
While the base algorithm is quite simple, there are plenty of improvements and additions they describe.</p>

<p>Alas, as my implementation was just way too slow to be practical (up to 30% increase in compile times), I set out to reimplement it with
the Braun et al. algorithm.</p>

<h1 id="ssa-à-la-braun-et-al"><abbr title="Static Single Assignment">SSA</abbr> à la Braun et al.</h1>

<p>The basic algorithm is quite simple. Looking at all blocks, all instructions in those blocks, we “remember” the new value for any definition
and we look up the current value for any use.
The look-up starts out local, checking if there is a definition in the current block and recurses into the block’s predecessors if there is none.
If we only have one predecessor, we can simply walk up until we find a definition or multiple predecessors.
Otherwise we have to place Phi-nodes, bc. we have merging control-flow.</p>

<p>Phi nodes are placed “defensively”, to mark already visited blocks and their arguments may be added later (incomplete Phis).
After adding a Phi’s arguments, it’s checked for “triviality” and removed if it is trivial.
A Phi node is trivial, if it doesn’t merge at least two distinct values. The argument list is cleaned of any duplicates
and the declaring Phi itself (a possible self-reference). If only one distinct value remains, they Phi node can be replaced with that value.
For example: <code class="language-plaintext highlighter-rouge">p1 = φ(p1, v2)</code> is trivial and each occurrence of <code class="language-plaintext highlighter-rouge">p1</code> can be replaced with <code class="language-plaintext highlighter-rouge">v2</code>.
Whereas <code class="language-plaintext highlighter-rouge">p2 = φ(v1, p1)</code> actually merges two distinct values and therefore is not trivial.</p>

<p>Incomplete Phis are added for blocks, which are not yet “sealed”. I’ll simply quote the paper<sup id="fnref:1:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> here, section 2.3,
as this is a very clear explanation:</p>

<blockquote>
  <p>We call a basic block sealed if no further predecessors will be added to the block.
As only filled blocks may have successors, predecessors are always filled. Note
that a sealed block is not necessarily filled. Intuitively, a filled block contains
all its instructions and can provide variable definitions for its successors.
Conversely, a sealed block may look up variable definitions in its predecessors as all
predecessors are known.</p>
</blockquote>

<p>The algorithm is capable of constructing <abbr title="Static Single Assignment">SSA</abbr> form as the <abbr title="Control Flow Graph">CFG</abbr> is being constructed.
In <abbr title="GHC's Native Code Generator">NCG</abbr>, we don’t need this, as instruction selection happens before and we have a complete <abbr title="Control Flow Graph">CFG</abbr> and filled blocks.
I’m still using these two states<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>, because you need to handle loop tail’s edges to the loop head.
In that case, you won’t have the definitions from the loop body when you are processing the loop head.
To avoid recursing into the whole loop body (and having to figure out when to stop, so you won’t get an infinite recursion),
I simply consider blocks “not sealed” if not all of their predecessors are filled.
My definition of “filled” is, that all instructions have been processed to find definitions (i.e., the block has been “visited”).</p>

<h2 id="value-numbering">Value Numbering</h2>

<p>I did not mention anything about generating new <abbr title="Static Single Assignment">SSA</abbr> names for definitions in the previous section.
In fact, neither does the paper.
You see, the algorithm performs a <a href="https://en.wikipedia.org/wiki/Value_numbering">(global) value numbering</a> as a natural side-effect.
That is because the algorithm looks for the current <em>value</em> of a variable. This may be a simple value or an expression.
Think of it as the right hand side of an expression.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># source
x &lt;- 2
y &lt;- 2
z &lt;- x + y
u &lt;- x + 2

# result
v1 &lt;- 2

v2 &lt;- v1 + v1
v3 &lt;- v2
</code></pre></div></div>

<p><abbr title="Global Value Numbering">GVN</abbr> is an optimization and also the basis for further optimizations.</p>

<p>The paper seems to assumes some expressions like in an <abbr title="Abstract Syntax Tree">AST</abbr> or some <abbr title="Immediate Representation">IR</abbr>.
Unfortunately, things aren’t as easy with assembly.</p>

<p>To make it short, there are several challenges:
You basically have to model the semantics of any instruction you want to consider for
all supported ISAs.
After all, you have <code class="language-plaintext highlighter-rouge">addq $2,%v1</code> and you need to know that this means <code class="language-plaintext highlighter-rouge">v1 &lt;- 2 + v1</code>,
or that <code class="language-plaintext highlighter-rouge">xor %v1,%v1</code> means <code class="language-plaintext highlighter-rouge">v1 &lt;- 0</code>, or multiplication/division by bit-shifting.
Further more, some instructions have implicit (result) operands, like status registers etc.
Most of the time, you won’t simply add constants (immediate values) to virtual registers though.
You will have to deal with memory access, like memory access relative to the base pointer,
so you will need to keep track of the current offset.
Also complex addressing modes accessing memory, e.g., ModR/M-Addressing for x86: <code class="language-plaintext highlighter-rouge">mov (%esi,%ebx,4), %edx</code>.</p>

<p>All in all, it seemed too complex. For that reason, my implementation simply generates a new <abbr title="Static Single Assignment">SSA</abbr> name
for definitions of virtual registers.</p>

<h2 id="removing-trivial-phis">Removing Trivial Phis</h2>

<p>As I wrote earlier, Phi nodes are placed “defensively” and are later checked for “triviality”.
If a Phi node is deemed trivial, it can be replaced by its only argument value.
In turn, any Phi node having that trivial Phi as an argument could now become trivial:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p1 = φ(p1, v1)
p2 = φ(p1, v1)

# p1 is trivial: p1 -&gt; v1
p2 = φ(v1, v1)

# p2 has become trivial: p2 -&gt; v1
</code></pre></div></div>

<p>This is conceptually quite simple, but some things have to be considered when implementing this.
As this may remove previously inserted (and used!) Phis, there will be instructions using these Phis.
In the paper, it looks as if they are using def-use chains to find and rewrite all those uses.
We don’t have those and computing them incurs an overhead.
Instead, I simply keep a mapping of all renamings (e.g., <code class="language-plaintext highlighter-rouge">{p2 -&gt; p1, p1 -&gt; v1, p3 -&gt; v2}</code>)
and then perform a second rewriting pass over the code with the “canonized” names
(e.g., <code class="language-plaintext highlighter-rouge">{p2 -&gt; v1, p1 -&gt; v1, p3 -&gt; v2}</code>).</p>

<p>This also necessitates keeping a Phi dependency graph, to keep track of all Phi users of a Phi node,
in case that node becomes trivial and all users have to be updated.</p>

<p>The whole procedure is quite imperative and “mutating” in nature, so I’m making extensive use of the
state monad. I’d actually like to see the state be shrunk somewhat, but I’ll look into optimizations in the future.</p>

<h1 id="ssa-flavor-and-optimizations"><abbr title="Static Single Assignment">SSA</abbr> Flavor and Optimizations</h1>

<p>In my previous articles, I wrote that I was using “pruned” <abbr title="Static Single Assignment">SSA</abbr> - precomputing liveness to make sure to only
insert live Phi nodes.
The Braun et al. algorithm naturally produces pruned <abbr title="Static Single Assignment">SSA</abbr> form, as it will only insert Phi nodes “on-demand”,
i.e., when it encounters the use of a variable coming from merging control-flow.</p>

<p>As for <em>minimality</em>, - <em>minimal <abbr title="Static Single Assignment">SSA</abbr></em> requires that Phi nodes for a variable are only placed in the first
block where multiple definitions of that variable meet for the first time - the algorithm produces
<em>minimal <abbr title="Static Single Assignment">SSA</abbr></em> only for <a href="https://en.wikipedia.org/wiki/Control-flow_graph#Reducibility">reducible control flow</a>.
Section 3.2 contains the description of a post-processing pass to remove any Phi nodes inserted because
of irreducible control flow.
So far, I have not implemented this though. Looking at some simple benchmarks, I could not see any excess
of Phi nodes. I might have to revisit this later though.</p>

<p>The paper also contains some extensions to remove the number of temporary Phi nodes inserted, in section 3.3.
It may be worth looking at these to improve performance, but I have not implemented them for now.</p>

<h1 id="other-implementations">Other Implementations</h1>

<p>I looked at <a href="https://github.com/KhronosGroup/SPIRV-Tools/blob/e0937d7fd1dbcb306c93d0806954a0dac08f48b9/source/opt/ssa_rewrite_pass.cpp">SPIRV-Tools</a>
and <a href="https://github.com/bytecodealliance/wasmtime/blob/3da677796b58fac7aedaa87b51c494da4e8df2a6/cranelift/frontend/src/ssa.rs">Cranelift’s</a> implementations
for inspiration.
(There is also <a href="https://llvm.org/doxygen/MemorySSAUpdater_8cpp_source.html">LLVM</a>, but the whole situation there is much more complicated
and I didn’t really dive into that)</p>

<p>I found both implementations very readable, but my situation in Haskell somewhat different, so many things did not apply.</p>

<p>There is also <a href="https://github.com/libfirm/libfirm">LibFirm</a>, which contains the original implementation by the paper authors.
(Alas, it’s written in C and I find navigating the code base quite challenging).</p>

<h1 id="results">Results</h1>

<p>So, how did it turn out?
To test my implementation, I made sure that both versions are rebased on master.
Then I used “cabaltest” - just a simple script to compile Cabal with provided flags - for comparison.
There is a big caveat here: I only did one compile per configuration, but by repeating some of them, I saw quite the variability.
I’d say that you should add ~5% error bars mentally.</p>

<p>To my chagrin, I also found out, that my first version seems to perform particularly badly with -O2, but quite OK with -O1.
I did my last evaluation only with baseline (no optimizations) and -O2 - which was a bad choice anyway.
But it wasn’t all for naught, because the new implementation is still faster and uses way less memory.</p>

<table>
  <thead>
    <tr>
      <th>Branch</th>
      <th>Flags</th>
      <th>User Time</th>
      <th>Time Change %</th>
      <th>Allocated</th>
      <th>Alloc. Change %</th>
      <th>Max residency</th>
      <th>Max Res Change %</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Asm-ssa cytron (7ffabc)</td>
      <td>‘-O1</td>
      <td>199.77</td>
      <td> </td>
      <td>176875852448</td>
      <td> </td>
      <td>531635592</td>
      <td> </td>
    </tr>
    <tr>
      <td>Asm-ssa cytron (7ffabc)</td>
      <td>‘-O1 -fssa-transform</td>
      <td>211.19</td>
      <td>5.72%</td>
      <td>222723463896</td>
      <td>25.92%</td>
      <td>539740512</td>
      <td>1.52%</td>
    </tr>
    <tr>
      <td>Asm-ssa cytron (7ffabc)</td>
      <td>‘-O2</td>
      <td>258.68</td>
      <td> </td>
      <td>223571517608</td>
      <td> </td>
      <td>684983536</td>
      <td> </td>
    </tr>
    <tr>
      <td>Asm-ssa cytron (7ffabc)</td>
      <td>‘-O2 -fssa-transform</td>
      <td>318.62</td>
      <td>23.17%</td>
      <td>336322854056</td>
      <td>50.43%</td>
      <td>690025104</td>
      <td>0.74%</td>
    </tr>
    <tr>
      <td>Asm-ssa-braun (b5b113)</td>
      <td>‘-O1</td>
      <td>210.6</td>
      <td> </td>
      <td>176875529800</td>
      <td> </td>
      <td>552021824</td>
      <td> </td>
    </tr>
    <tr>
      <td>Asm-ssa-braun (b5b113)</td>
      <td>‘-O1 -fssa-transform</td>
      <td>227.87</td>
      <td>8.20%</td>
      <td>180666914120</td>
      <td>2.14%</td>
      <td>547049824</td>
      <td>-0.90%</td>
    </tr>
    <tr>
      <td>Asm-ssa-braun (b5b113)</td>
      <td>‘-O2</td>
      <td>225.9</td>
      <td> </td>
      <td>223570497192</td>
      <td> </td>
      <td>688337672</td>
      <td> </td>
    </tr>
    <tr>
      <td>Asm-ssa-braun (b5b113)</td>
      <td>‘-O2 -fssa-transform</td>
      <td>249.13</td>
      <td>10.28%</td>
      <td>227890634696</td>
      <td>1.93%</td>
      <td>686895536</td>
      <td>-0.21%</td>
    </tr>
  </tbody>
</table>

<p>By looking at this table you might think “hey! the new version is actually <em>slower</em> at -O1”.
I’m not convinced that it is, see my comment regarding the “error bars”.
I’ve seen changes of 10 seconds or more across runs, so I’m inclined to say that they are about equal in terms of
speed for -O1, where the new version performs much fewer allocations.
Either way, I’ll keep the new one anyway and rerunning the benchmarks would take quite a long time.
Mind you that the new implementation is absolutely not optimized and I’m sure that there are quite some gains to be had.</p>

<p>I also wanted to look at the number of Phi arguments, to see how I can optimize their representation (currently it’s just a list).</p>

<table>
  <thead>
    <tr>
      <th>Impl</th>
      <th>prog</th>
      <th>count</th>
      <th>min args</th>
      <th>max args</th>
      <th>avg args</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>old</td>
      <td>real/small-pt</td>
      <td>216</td>
      <td>2</td>
      <td>5</td>
      <td>2</td>
    </tr>
    <tr>
      <td>new</td>
      <td>real/small-pt</td>
      <td>216</td>
      <td>2</td>
      <td>5</td>
      <td>2</td>
    </tr>
    <tr>
      <td>old</td>
      <td>spectral/simple</td>
      <td>345</td>
      <td>2</td>
      <td>4</td>
      <td>2</td>
    </tr>
    <tr>
      <td>new</td>
      <td>spectral/simple</td>
      <td>345</td>
      <td>2</td>
      <td>4</td>
      <td>2</td>
    </tr>
    <tr>
      <td>old</td>
      <td>shootout/fannkuch-redux</td>
      <td>257</td>
      <td>2</td>
      <td>7</td>
      <td>2</td>
    </tr>
    <tr>
      <td>new</td>
      <td>shootout/fannkuch-redux</td>
      <td>257</td>
      <td>2</td>
      <td>5</td>
      <td>2</td>
    </tr>
  </tbody>
</table>

<p>The “count” columns refers to the total number of Phi functions in the compiled modules.
Interestingly, they are the same for the three benchmarks I looked at from the “nofib” suite.
So there aren’t any superfluous Phi nodes inserted by the new implementation (see <em>minimality</em> above).
It’s curious that the old implementation seems to insert <em>more</em> arguments in the last program,
as indicated by the higher “max args” number.
Those may be duplicate elements, as the argument lists are de-duplicated for the triviality check
in the new implementations, but I have not verified this hunch.</p>

<h1 id="conclusion">Conclusion</h1>

<p>I’m somewhat satisfied with the new implementation, but I think there is still a lot of potential for improvement.
Especially performance can always be better.
I might have to look into the post-processing step to ensure minimality for irreducible control flow later,
but for now I have my eyes on <em>liveness analysis</em>.
But stay tuned, I might write about that soon.</p>

<p>For those who want to keep track of this effort, the <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/19453">ticket</a> is still the same
and <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6170">this is a new MR</a>.</p>

<p>If you spot any mistakes, omissions or want to provide feedback, comments, questions - you can reach me on <a href="https://twitter.com/cptwunderlich">Twitter</a>, or via mail with my username at gmail.</p>

<p><img src="https://visitor-badge.glitch.me/badge?page_id=cptwunderlich.ssa4ncg3-2021" alt="readers" /></p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://link.springer.com/chapter/10.1007%2F978-3-642-37051-9_6">Braun et al. - “Simple and Efficient Construction of Static Single Assignment Form”</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:1:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://github.com/KhronosGroup/SPIRV-Tools/blob/e0937d7fd1dbcb306c93d0806954a0dac08f48b9/source/opt/ssa_rewrite_pass.cpp">SPIRV-Tools <abbr title="Static Single Assignment">SSA</abbr> rewrite pass</a> seems to only use “sealed”, but IIRC that differed from the paper’s definition. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Benjamin Maurer</name></author><category term="Haskell" /><category term="GHC" /><category term="compilers" /><category term="ssa" /><category term="register_allocation" /><category term="programming" /><summary type="html"><![CDATA[Another Try]]></summary></entry><entry><title type="html">SSA transformation for GHC’s native code generator (Part 2)</title><link href="http://www.benjaminmaurer.at/2021/04/30/ssa_for_ncg_part2.html" rel="alternate" type="text/html" title="SSA transformation for GHC’s native code generator (Part 2)" /><published>2021-04-30T00:00:00+00:00</published><updated>2021-04-30T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2021/04/30/ssa_for_ncg_part2</id><content type="html" xml:base="http://www.benjaminmaurer.at/2021/04/30/ssa_for_ncg_part2.html"><![CDATA[<h1 id="ssa-based-live-range-discovery"><abbr title="Static Single Assignment">SSA</abbr> based Live Range Discovery</h1>

<p>In the <a href="/2021/04/27/ssa_for_ncg_part1.html">first part</a>, I explained the motivation
to bring <abbr title="Static Single Assignment">SSA</abbr>-transformation to <abbr title="Glasgow Haskell Compiler">GHC</abbr>’s <abbr title="GHC's Native Code Generator">NCG</abbr>.
Here, I want to look at the implementation challenges, decisions and results.</p>

<h1 id="ssa-in-the-backend"><abbr title="Static Single Assignment">SSA</abbr> in the Backend</h1>

<p>I’ve used pseudo-code in the first part, but generally, you’ll have some intermediate representation (<abbr title="Immediate Representation">IR</abbr>) in your compiler, which is in <abbr title="Static Single Assignment">SSA</abbr>.
For example, a three address code (TAC), where each instruction represents an operation,
taking two <em>input</em> arguments and one <em>output</em> argument, e.g., <code class="language-plaintext highlighter-rouge">IADD x, y, z</code> -&gt; <code class="language-plaintext highlighter-rouge">z = x + y</code>.</p>

<p>Modern compilers usually use multiple <abbr title="Immediate Representations">IRs</abbr>, adapted to different compilation phases and tasks.
They may or may not be in <abbr title="Static Single Assignment">SSA</abbr>.
<abbr title="Glasgow Haskell Compiler">GHC</abbr> has been around for a while and has several compilation phases and <abbr title="Immediate Representations">IRs</abbr>.
I won’t describe them here in detail<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, but they are Core, STG, C–.
C– is a low-level, imperative language with an explicit stack.
<abbr title="GHC's Native Code Generator">NCG</abbr> performs instruction selection on C– and spits out machine instructions for the selected
platform.
So at this point, we’re not dealing with an <abbr title="Immediate Representation">IR</abbr> anymore<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p><img src="/assets/posts/ssa-ncg/GHC-Pipeline.png" alt="GHC's Intermediate Representations" /></p>

<p>There are actually quite a few challenges when trying to implement <abbr title="Static Single Assignment">SSA</abbr>-form on machine instructions.</p>

<h2 id="pre-colored-registers">Pre-colored Registers</h2>

<p>Sometimes, the <abbr title="Instruction Set Architecture">ISA</abbr> or <abbr title="Application Binary Interface">ABI</abbr> requires you to use certain registers in specific places.
For example, the x86_64 calling convention requires the passing of function arguments in
specific registers.
Or think about special purpose registers, like the x86_64 stack registers <code class="language-plaintext highlighter-rouge">RBP</code> and <code class="language-plaintext highlighter-rouge">RSP</code>.</p>

<p>Instruction selection already emits these physical register references where necessary.
Obviously, we can’t promote these to <abbr title="Static Single Assignment">SSA</abbr> variables and start renaming them willy-nilly.
In this case, i.e., for live range discovery, we can simply get a way with ignoring them all together, since we are not moving any code<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>.
(FYI, this will be a common theme in the following subsections.)</p>

<h2 id="modifying-and-2-address-instructions">Modifying and 2-Address Instructions</h2>

<p>Most real world ISAs have the annoying property of not being neat, regular and simple.
x86 has many instructions that modify an operand (i.e., in <strong>and</strong> out operands).
Let’s say <code class="language-plaintext highlighter-rouge">%v1</code> denotes a virtual register number 1, then <code class="language-plaintext highlighter-rouge">inc %v1</code> <em>increments</em> <code class="language-plaintext highlighter-rouge">%v1</code>,
or <code class="language-plaintext highlighter-rouge">v1 := v1 + 1</code>.
Another example is the two-address addition instruction: <code class="language-plaintext highlighter-rouge">add %v1, %v2</code> is <code class="language-plaintext highlighter-rouge">%v2 = %v1 + %v2</code>.</p>

<p>This is clearly not in <abbr title="Static Single Assignment">SSA</abbr>, as we are producing a value but we can’t assign a new name!
One may introduce an intermediate representation to handle this case, constraining the
in-out operand pair together somehow - but again, in our use case, we can ignore this!</p>

<p>If we only care about live ranges having unique <abbr title="Virtual Register">vreg</abbr> names, this is OK because the in-out operand
pair belongs together anyway. There is no way we could assign different registers here.</p>

<h2 id="conditional-instructions">Conditional Instructions</h2>

<p>Some architectures have <a href="https://en.wikipedia.org/wiki/Predication_(computer_architecture)">conditional (or predicated) instructions</a>, which will only execute,
if a specific condition is met, i.e., normally some status bits must be set in a status register.
For example, x86_64 offers the <code class="language-plaintext highlighter-rouge">cmov</code>, or conditional move instruction.
As an example, <code class="language-plaintext highlighter-rouge">CMOVE %v1, %v2</code> is equal to <code class="language-plaintext highlighter-rouge">if (x == y) { v2 := v1 }</code>.</p>

<p>32-Bit ARM can basically make every instruction predicated, whereas AARCH64 dialed that down a bit.</p>

<p>I’m not going to discuss their benefits or drawbacks, but since <abbr title="GHC's Native Code Generator">NCG</abbr> supports architectures with these instructions, we need to take them into account.
Again, I’m choosing the most simple route. I consider them non-kill definitions and don’t rename their target.</p>

<h2 id="further-reading">Further Reading</h2>

<p>If you’d like to read more about these challenges, then check-out the <a href="http://ssabook.gforge.inria.fr/latest/book.pdf"><abbr title="Static Single Assignment">SSA</abbr> Book</a> and <a href="https://doi.org/10.1007/978-3-642-54807-9_1">“Using the <abbr title="Static Single Assignment">SSA</abbr>-Form in a Code Generator”</a> by Benoît Dupont de Dinechin.</p>

<h1 id="implementation">Implementation</h1>

<p>Let’s get down to business. The ticket tracking the implementation can be found <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/19453">here</a>.</p>

<h2 id="overview">Overview</h2>

<p>The general workflow, including the new <abbr title="Static Single Assignment">SSA</abbr> transformation, is as follows and can be found in <code class="language-plaintext highlighter-rouge">CmmToAsm.hs</code>:</p>

<p>Instruction Selection -&gt; Liveness Analysis -&gt; <abbr title="Static Single Assignment">SSA</abbr> Construction -&gt; <abbr title="Static Single Assignment">SSA</abbr> Destruction -&gt; Register Allocation</p>

<p>For construction, I employed the classic Cytron et al. algorithm<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> and destruction handled in the simplified fashion outlined in the first part.
I’m constructing <a href="https://en.wikipedia.org/wiki/Static_single_assignment_form#Pruned_SSA">pruned-<abbr title="Static Single Assignment">SSA</abbr></a>, i.e., only insert φ-nodes for values that are actually live and used.
This yields fewer φ-nodes and only “productive” ones, that I can use to find all the webs.
But to get that information, I’ve plugged the <abbr title="Static Single Assignment">SSA</abbr>-steps after the existing Liveness Analysis.
That is a classic data-flow analysis, i.e., a fixed-point algorithm.</p>

<h2 id="modelling-data">Modelling Data</h2>

<p>Since I didn’t want to rewrite large parts of the code generator, I had to stay close to the original data types in a way.</p>

<p>I’m greatly simplifying here, but basically, after liveness analysis, a procedure is list of strongly connected components (SCCs) of basic blocks:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[SCC (LiveBasicBlock instr)]
</code></pre></div></div>

<p>We have our Live<sub>In</sub>-Sets, i.e., sets of vregs live on the entry of a basic block, in the main procedure structure (and we need those to place only live φ-functions).
The <code class="language-plaintext highlighter-rouge">LiveBasicBlock</code>s contain the ID (or label) of the block and a list of instructions with liveness information (which vregs are read/written/modified, are born/die).
<a href="https://hackage.haskell.org/package/containers-0.6.4.1/docs/Data-Graph.html#t:SCC">SCCs</a> are either acyclic, i.e., just one block, or they are <code class="language-plaintext highlighter-rouge">CyclicSCC</code>s, containing a list of blocks.
The cyclic SCCs are the top-level loops in a procedure (and may contain more loops).</p>

<p>I’m not really interested in the SCC structure, as I need the Control Flow Graph (<abbr title="Control Flow Graph">CFG</abbr>) anyway, as it is more complete and lets me access all the connections directly, without having to navigate lists and find jumps “manually”.
N.B., the <abbr title="Control Flow Graph">CFG</abbr> in the backend is currently only supported for x86_64, that’s why I can’t support SPARC or PowerPC. I’m not sure what the status for the new AARCH64 support is.</p>

<p>For the construction algorithm, I need random access, so I’m putting everything into a map.
But I need to be able to rebuild the exact same SCC-based structure after destruction, otherwise I can’t reuse the rest of the backend.
To achieve that, I’m wrapping each block with information telling me, which SCC it belongs to
and I’m using a “deterministic map”, which preserves iteration order:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type BlockLookupTable instr
    = UniqDFM BlockId (SccBits (SSABasicBlock instr))

data SccBits a
    = AcyclicBit a | CyclicBit Int a

data PhiFun = PhiF RegId RegId [RegId]
          -- ^ oldId newId args
          
data SSABasicBlock instr
    = SSABB [PhiFun] !(LiveBasicBlock instr)
</code></pre></div></div>

<p>For example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[A -&gt; B -&gt; [C -&gt; D -&gt; E] -&gt; F -&gt; [G -&gt; H]]
</code></pre></div></div>

<p>turns into:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[A: A, B: B, C: 1 C, D: 1 D, E: 1 E, F: F, G: 2 G, H: 2 H]
</code></pre></div></div>

<h2 id="construction">Construction</h2>

<p>I don’t want to go into great detail here, as better descriptions of the Cytron et al. algorithm can be found in many compiler textbooks (e.g., “Engineering a Compiler”) or online.
There may also be better algorithms around (see “Conclusion”).</p>

<p>The gist is, you need to compute the <a href="https://en.wikipedia.org/wiki/Dominator_(graph_theory)">dominance frontiers</a> to know where to place φ-functions and then you need to start renaming definitions in a depth first pre-order walk over the <abbr title="Control Flow Graph">CFG</abbr>.</p>

<p>One node <em>d</em> in a directed graph is said to <em>dominate</em> a node <em>n</em>, if every path from the start node to <em>n</em> must go through <em>d</em>.
Every node <em>d</em> dominates itself, but <em>d</em> is said to <em>strictly dominate</em> <em>n</em> if <em>d</em> dominates <em>n</em> and <em>d</em> ≠ <em>n</em>.
The <em>dominance frontier</em> is the set of nodes, that <em>d</em> <em>just</em> doesn’t dominate, i.e., if <em>d</em> dominates an immediate predecessor of <em>n</em>, but <strong>does not</strong> strictly dominate <em>n</em> itself, it is in the dominance frontier.</p>

<p>Looking at the graph below, we can see that <em>b</em> dominates both <em>c</em>, <em>d</em> and <em>e</em> - to reach them, you must go through <em>b</em>.
But <em>c</em> and <em>d</em> do <strong>not</strong> dominate <em>e</em> (only themselves). <em>e</em> is in the dominance frontier of <em>c</em> and of <em>d</em> and a block, where we may have to place a φ-node.
Looking at the graph, we can intuitively see that, as two conflicting variable definitions from <em>c</em> and <em>d</em> would reach <em>e</em> and we’d need to reconcile them.</p>

<p><img src="/assets/posts/ssa-ncg/dom-cfg.png" alt="A control flow graph" /></p>

<p>Whether we <em>actually</em> need a φ-function here, depends on whether there <em>really</em> was a live variable at that point in the original program. If we bother to check that, we get <em>pruned-<abbr title="Static Single Assignment">SSA</abbr></em>.
Otherwise it would still be called <em>minimal-<abbr title="Static Single Assignment">SSA</abbr></em>, as that only requires that we place φs at join points and not <em>everywhere</em> (which would lead to very pointless and inefficient <em>maximal <abbr title="Static Single Assignment">SSA</abbr></em>).</p>

<p>For the renaming part, you need to manage some state and stacks of current names for the current “level” of the <abbr title="Control Flow Graph">CFG</abbr> you are on.
This has actually proven to be the most expensive part of the whole algorithm.</p>

<p>If you are interested in details, check out the relevant chapters in “Engineering a Compiler”,
<a href="https://gitlab.haskell.org/cptwunderlich/ghc/-/blob/wip/bmaurer/asm-ssa/compiler/GHC/CmmToAsm/SSA.hs">the code</a> or my <a href="/downloads/maurer-thesis-ssa-for-ghc-29.03.2021-final.pdf">bachelor’s thesis</a>.</p>

<h1 id="evaluation">Evaluation</h1>

<p>To evaluate my changes, I let them loose on <abbr title="Glasgow Haskell Compiler">GHC</abbr>’s nofib benchmark suite, looking both at spill statistics and perf numbers.
I compared both the linear scan and the graph coloring allocators with and without <abbr title="Static Single Assignment">SSA</abbr> transformation.</p>

<p>Graph coloring register allocators use a heuristic to decide, which live range to spill once no more free registers are available.
<code class="language-plaintext highlighter-rouge">-fregs-graph</code> uses a very simple one - it just spills the longest live range.
This works surprisingly well (I tested it against some other ones, before my <abbr title="Static Single Assignment">SSA</abbr> implementation), but my hunch is, that this has something to do with vregs representing disjoint live ranges, making them longer on average.
Therefore, I also implemented a simple Chaitin-style spill heuristic.
Looking at more sophisticated spill heuristics in combination with <abbr title="Static Single Assignment">SSA</abbr>-transformation may be worthwhile.</p>

<h2 id="unique-vregs">Unique vregs</h2>

<p>The point was to verify my theory, that most programs contain disjoint live ranges with the same <abbr title="Virtual Register">vreg</abbr> name.
The median increase in unique <abbr title="Virtual Register">vreg</abbr> names, across all benchmarks, is 5.44%, with the single largest increase being 21.04%.
I looked at the results for the <code class="language-plaintext highlighter-rouge">real</code> group in detail and all programs showed an increase, except for the tiny programs in <code class="language-plaintext highlighter-rouge">real/eff</code>.</p>

<h2 id="spills---the-good">Spills - The Good</h2>

<p>Spills are both loads and stores. But register-register moves (reg-reg moves) are also noteworthy.
Even though they are a metric used in papers, their cost seems to have gone down quite a bit over the last decades.
Most modern desktop CPUs contain a much larger register file internally, than just the <em>architectural</em> registers (16 for x86_64).
So they can apply <em>register renaming</em> in their execution pipeline.
It’s like switching the label in a shelf, instead of moving the merchandise lying there.</p>

<p>I’ve also added SPILLS*, where I am excluding <em>never spilling</em> programs.
Since I’m looking at just the relative changes in spills, programs that spilled zero times across all runs only distort the picture.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th style="text-align: center">graph-ssa</th>
      <th style="text-align: center"> </th>
      <th style="text-align: center"> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td> </td>
      <td style="text-align: center">Spills</td>
      <td style="text-align: center">Spills*</td>
      <td style="text-align: center">reg-reg moves</td>
    </tr>
    <tr>
      <td>Median</td>
      <td style="text-align: center">0%</td>
      <td style="text-align: center">-20.00%</td>
      <td style="text-align: center">-5.40%</td>
    </tr>
    <tr>
      <td> </td>
      <td style="text-align: center"><strong>graph-chaitin-ssa</strong></td>
      <td style="text-align: center"> </td>
      <td style="text-align: center"> </td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td>Median</td>
      <td style="text-align: center">Spills</td>
      <td style="text-align: center">Spills*</td>
      <td style="text-align: center">reg-reg moves</td>
    </tr>
    <tr>
      <td> </td>
      <td style="text-align: center">0%</td>
      <td style="text-align: center">-24.54%</td>
      <td style="text-align: center">-5.67%</td>
    </tr>
  </tbody>
</table>

<p>The changes for the linear scan allocator are less impressive:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th style="text-align: center">linear-ssa</th>
      <th style="text-align: center"> </th>
      <th style="text-align: center"> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td> </td>
      <td style="text-align: center">spills</td>
      <td style="text-align: center">spills*</td>
      <td style="text-align: center">reg-reg moves</td>
    </tr>
    <tr>
      <td>Median</td>
      <td style="text-align: center">0%</td>
      <td style="text-align: center">-1.09%</td>
      <td style="text-align: center">0%</td>
    </tr>
  </tbody>
</table>

<h2 id="runtime---the-bad">Runtime - The Bad</h2>

<p>OK, so reducing spills is great and all, but what really matters are actually executed instructions.
After all, you could remove all spills from rarely executed straight line code and it wouldn’t add up to anything, compared to a hot loop containing spill code.</p>

<p>The results here are not overwhelming.
I’ve added all three columns to the same table, but the graph-* columns are measured against <code class="language-plaintext highlighter-rouge">-fregs-graph</code> baseline, whereas ‘linear-ssa’ is measured against the linear scan allocator baseline.
The numbers are relative changes in CPU cycles as reported by <code class="language-plaintext highlighter-rouge">perf</code>.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th style="text-align: center">graph-ssa</th>
      <th style="text-align: center">graph-chaitin-ssa</th>
      <th style="text-align: center">linear-ssa</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Geo. mean</td>
      <td style="text-align: center">-0.47%</td>
      <td style="text-align: center">-0.74%</td>
      <td style="text-align: center">0.20%</td>
    </tr>
    <tr>
      <td>Median</td>
      <td style="text-align: center">-0.31%</td>
      <td style="text-align: center">-0.39%</td>
      <td style="text-align: center">0.08%</td>
    </tr>
    <tr>
      <td>Weighted Avg.</td>
      <td style="text-align: center">-0.96%</td>
      <td style="text-align: center">-1.10%</td>
      <td style="text-align: center">0%</td>
    </tr>
  </tbody>
</table>

<p>So what does this mean? Nofib-compare gives you the geometric mean.
I wanted to explore some other averages, because there is, unfortunately, a <em>huge</em> difference in runtime of the benchmark programs.
That is not intentional, they are supposed to have similar lengths, but they drift over time.
I included the weighted average (weighted by fraction of total runtime), because there are many programs that run for a few milliseconds on one end of the spectrum and one benchmark takes <em>58 seconds</em> to complete on my machine.
You just can’t compare that. The short program is so much more sensitive to interferences and 5% change of 200ms vs 58000ms can’t be lumped together, IMHO.</p>

<p>Alright, so what does that leave us with?
If the results are correct, we might expect around 1% improvement for <code class="language-plaintext highlighter-rouge">-fregs-graph</code> and basically nothing for linear scan.
Depending on the cost, I’d take 1%, since for compiler engineers working on mature compilers, 1-2% is already a win.
I tried to drill down a bit in my thesis to explain some of the results, but I’m not a 100% sure.
A hand full of results weren’t really stable across runs. Some seem to be due to higher cache misses (spill code placement and even changes in code layout can have that effect).
Generally, I think that there are still so many things that can be improved in <code class="language-plaintext highlighter-rouge">-fregs-graph</code>, but live range renumbering seems to be a prerequisite anyway.</p>

<p>So what about linear scan? I’m less familiar with that algorithm and code, but I have a hunch.
Linear scan will make allocation decisions going through the code and insert “fix-up” code/blocks when assigned registers have to be changed.
If I understand that correctly, you are not constrained to assign only one real register to a given <abbr title="Virtual Register">vreg</abbr> and most of the fix-up code will be reg-reg moves (but spills are needed too).
That would mean, that renumbering just isn’t such an issue to begin with and since reg-reg moves are <em>mostly</em> quite cheap, even the cases where it would lead to more code are not so bad.</p>

<p>If you are interested in the raw numbers, they can be found <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/19453#note_343326">in the ticket</a> and a more lengthy discussion of the results can be found in my thesis.</p>

<h2 id="compile-times---the-ugly">Compile times - The Ugly</h2>

<p>OK, I said I would take a speedup of 1%, but only at an adequate cost.
You see, I knew this wouldn’t be fast. We are doing strictly more work.
The only gains would be fewer iterations of register allocation (for <code class="language-plaintext highlighter-rouge">-fregs-graph</code> only) and possibly a speedup by a faster compiler compiled with that new optimization.
I’ve also used pretty basic algorithms and I only tuned them ever so slightly.
(Plus I’m not an experience Haskell developer and I have no intuition on how to write well performing Haskell.)</p>

<p>Alright, so, the slowdown I have observed compiling Cabal was almost… 30%.
That is absolutely terrible, I’m not going to lie.
I got some feedback on my code and tried a few things, but it barely made a dent.</p>

<p>But fret not, not all is lost.</p>

<h1 id="conclusion">Conclusion</h1>

<p><code class="language-plaintext highlighter-rouge">-fregs-graph</code> could need some love, there is no renumbering step and <abbr title="Static Single Assignment">SSA</abbr> transformation not only could take care of that, but it could also enable future optimizations.</p>

<p>My implementation (hopefully) shows, that there is some room for this, but that the improvement is not guaranteed to be large and cost must be low.</p>

<p><code class="language-plaintext highlighter-rouge">-fregs-graph</code> itself could see better results with a different spill heuristic (possibly) and some other improvements (coloring for spill slots? memory addressing instead of stores/loads?).</p>

<p>There are a few possible optimizations for my <abbr title="Static Single Assignment">SSA</abbr> transformation pass.
But several people have let me know, that a better, more modern algorithm exists<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>.
I’m looking into implementing that algorithm and placing it <em>before</em> liveness analysis.
Then I can do that on <abbr title="Static Single Assignment">SSA</abbr>-form directly, where I don’t need to run analyses in a loop until a fixed-point is reach, due to the <abbr title="Static Single Assignment">SSA</abbr> properties (so that’s supposed to be faster).
But the current liveness analysis also removes some dead code as well - so I just need to take a look at the current code and the papers and make sure that I produce correct code.</p>

<p>What excites me quite a bit more though, is the possibility of writing a new graph-based register allocator that operates on <abbr title="Static Single Assignment">SSA</abbr> directly.
Work on bringing register allocation to <abbr title="Static Single Assignment">SSA</abbr> form has been done and the discovery of some interesting properties made in the last two decades.<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup>
So my next big project will be a new graph coloring register allocator on <abbr title="Static Single Assignment">SSA</abbr>-form for <abbr title="Glasgow Haskell Compiler">GHC</abbr>!</p>

<p>If you spot any mistakes, omissions or want to provide feedback, comments, questions - you can reach me on <a href="https://twitter.com/cptwunderlich">Twitter</a>, or via mail with my username at gmail.</p>

<p><img src="https://visitor-badge.glitch.me/badge?page_id=cptwunderlich.ssa4ncg2-2021" alt="readers" /></p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>I recommend <a href="https://github.com/takenobu-hs/haskell-ghc-reading-guide">Takenobu’s <abbr title="Glasgow Haskell Compiler">GHC</abbr> Reading Guide</a> for an overview. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Well, there are still a few meta-instructions, like SPILL and LOAD, but all-in-all it’s pretty close to assembly. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>I think one could promote them to a distinct class of <abbr title="Static Single Assignment">SSA</abbr> variables and store a mapping to the original register. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p>The description in “Engineering a Compiler” is great, as per usual. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p><a href="https://link.springer.com/chapter/10.1007%2F978-3-642-37051-9_6">Braun et al. - “Simple and Efficient Construction of Static Single Assignment Form”</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p>See Hack06 for graph coloring on <abbr title="Static Single Assignment">SSA</abbr> and Wimmer&amp;Franz2010 for linear scan on <abbr title="Static Single Assignment">SSA</abbr> <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Benjamin Maurer</name></author><category term="Haskell" /><category term="GHC" /><category term="compilers" /><category term="ssa" /><category term="register_allocation" /><category term="programming" /><summary type="html"><![CDATA[SSA based Live Range Discovery]]></summary></entry><entry><title type="html">SSA transformation for GHC’s native code generator (Part 1)</title><link href="http://www.benjaminmaurer.at/2021/04/27/ssa_for_ncg_part1.html" rel="alternate" type="text/html" title="SSA transformation for GHC’s native code generator (Part 1)" /><published>2021-04-27T00:00:00+00:00</published><updated>2021-04-27T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2021/04/27/ssa_for_ncg_part1</id><content type="html" xml:base="http://www.benjaminmaurer.at/2021/04/27/ssa_for_ncg_part1.html"><![CDATA[<h1 id="improving-the-graph-coloring-register-allocator">Improving the Graph Coloring Register Allocator</h1>

<p>For my first big project on <abbr title="Glasgow Haskell Compiler">GHC</abbr>, I wanted to try and improve the Graph Coloring Register allocator in <abbr title="GHC's Native Code Generator">NCG</abbr> (<abbr title="Glasgow Haskell Compiler">GHC</abbr>’s Native Code Generator), aka <code class="language-plaintext highlighter-rouge">-fregs-graph</code>.</p>

<p>When code generators emit instructions, they usually use an unlimited number of <em>virtual registers</em> (vregs) and map those to <em>physical registers</em> (or real regs),
possibly after changing the code around with optimizations.
This register allocation step is generally one of the last ones and extremely important for performance.
Registers are a scarce resource and memory access is orders of magnitude slower.</p>

<p>Two of the dominant paradigms for register allocation are <em>Graph Coloring</em><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> based and <em>Linear Scan</em><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> register allocators.
These have been around since the eighties, respectively nineties, but are still highly relevant and in wide use.
Generally speaking, graph coloring based approaches are supposed to yield better quality code, but take more time and memory,
whereas linear scan is faster, at a cost of quality.
<abbr title="Glasgow Haskell Compiler">GHC</abbr> currently only uses a (very good) linear scan based allocator, since <code class="language-plaintext highlighter-rouge">-fregs-graph</code> has been suffering from <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/7679">bad performance since ca. 2013</a>.</p>

<p>So looking at <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/16243">AndreasK’s improvement ideas</a>, I chose to try <em>live range splitting</em>.</p>

<h1 id="live-ranges-and-graph-coloring">Live Ranges and Graph Coloring</h1>

<p>I’m borrowing the definition of <em>live range</em> from Cooper &amp; Torczon’s “Engineering a Compiler”, chapter 13:</p>

<blockquote>
  <p>A single live range consists of a set of definitions and uses that are related to each other because their values flow together.
That is, a live range contains a set of definitions and a set of uses.</p>
</blockquote>

<p>Since “range” sounds so “linear”, I somewhat prefer the term <em>webs</em> over <em>live ranges</em>, as these are webs of intersecting def-use chains.</p>

<p>Basically, we want to assign each live range one physical register, but we generally have fewer real registers than live ranges.
We can assign two live ranges to the same physical register, if they never “overlap”.
This “overlapping” is called <em>interference</em> and two <abbr title="Live Ranges">LRs</abbr> <em>interfere</em> if they are ever live at the same point in the program.
We construct an undirected graph, the <em>interference graph</em>, where each vertex is a live range and each edge an interference.
Calculating precise liveness information and constructing the interference graph isn’t cheap, by the way.</p>

<p>How does this help assigning registers? Using the interference graph, we can formulate a <a href="https://en.wikipedia.org/wiki/Graph_coloring">Graph Coloring</a> problem,
i.e., we want to color each vertex in such a way, that two connected vertices have different colors.
Physical registers are our colors and since we have limited registers, we are looking for a <em>k-coloring</em>, where <em>k</em> is the number of registers.</p>

<p>Not all programs will be k-colorable, so we may have to <em>spill</em>, i.e., put an <abbr title="Live Range">LR</abbr> in memory, by performing a <em>store</em> after each definition
and a <em>load</em> before each use. Then we can remove that <abbr title="Live Range">LR</abbr> from the interference graph and try again<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>.</p>

<p><img src="/assets/posts/ssa-ncg/coloring.png" alt="Phases of a Chaitin-Briggs Allocator" /></p>

<p>I’ve ignored many things here:
<em>Coalescing</em> is the process of merging non-interfering, copy related live ranges together.
I will talk later about <em>renumbering</em>.</p>

<h2 id="live-range-splitting">Live Range Splitting</h2>

<p>In the ticket linked above, AndreasK has observed, that live ranges are spilled, even though they may be fit into <em>liveness holes</em> and a coloring could be found, by splitting the <abbr title="Live Range">LR</abbr>.
What does this mean? Let’s look at the following pseudo-code:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x &lt;- 1 # def x
y &lt;- 1 # def y
loop {
    y &lt;- y + 1  # use y
}

loop {
    # use x
}
</code></pre></div></div>

<p>Imagine for a moment this code makes sense (or would you rather stare at real assembly?).
If we had only two registers and our heuristic decides to <em>spill</em> either x or y, we’d have an additional <em>load</em> and a <em>store</em> in each loop.
At this point you may say “hold up, there are no loops in Haskell”, or “Why not put the load before the loop and the store after it?”.
Since we’re working on machine instructions at this stage in the compiler, loops do exist - in the form of jumps between blocks.
Choosing which <abbr title="Live Ranges">LRs</abbr> to spill and spill code placement are subjects in their own right. Let’s just say that this example is simplified
and that <code class="language-plaintext highlighter-rouge">-fregs-graph</code> places the spill code right around the instructions, later cleaning up unnecessary ones.</p>

<p>I jumped on this and tried to implement <em>Passive Live Range Splitting</em>, by <a href="https://doi.org/10.1007/BFb0026430">Cooper and Simpson</a>.
This algorithm is supposed to figure out, that we can split x like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x &lt;- 1 # def x
y &lt;- 1 # def y
STORE x
loop {
    y &lt;- y + 1  # use y
}

LOAD x

loop {
    # use x
}
</code></pre></div></div>

<p>The paper looked simple and like a great solution, so <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/19274">I went ahead with it.</a></p>

<h2 id="jumping-the-gun">Jumping the Gun</h2>

<p>I wasn’t familiar with the code base (or the algorithm) and did some learning by doing.
I’ll give you the quick run down of my revelation:</p>

<p>In my description of live ranges, I made it sound like we are assigning registers to live ranges.
That isn’t quite correct. There is no explicit modelling of live ranges (“webs”) in <abbr title="Glasgow Haskell Compiler">GHC</abbr> (and probably in most compilers?).
We are operating on vregs and <strong>those are mapped</strong> to physical registers.</p>

<p>Remember that “renumbering” step in the diagram earlier? This is actually about <em>live range discovery</em>.
This whole coloring process is repeated. Like I noted before, <em>spilling</em> technically creates tiny live ranges
and <code class="language-plaintext highlighter-rouge">-fregs-graph</code> renames them on-the-fly.
To split live ranges, inserting stores and loads is not enough, you have to rename (“renumber”) the vregs in the instructions,
to reflect the new live ranges!
But <code class="language-plaintext highlighter-rouge">-fregs-graph</code> doesn’t have a renumbering phase.
While analyzing <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/8048">this simple reproducing example program</a>, it dawned on me.
I saw something similar to this in assembly:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
  def x
  use x
  def x
  use x
}
...
{
  def x
  use x
}
</code></pre></div></div>

<p>There were no branches with different definitions of <em>x</em>. In fact, <em>x</em> was redefined in the same basic block,
redefined and used in a later block.
Those are disjoint live ranges, but by having the same <abbr title="Virtual Register">vreg</abbr> name, they are constrained to be assigned to the same physical register!
We don’t need live range splitting, we need live range discovery!<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>
I falsely assumed that <abbr title="Virtual Register">vreg</abbr> = live range.<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup></p>

<h2 id="things-going-sideways">Things going Sideways</h2>

<p>I briefly and desperately tried to create some makeshift renumbering for my split <abbr title="Live Ranges">LRs</abbr>, but it was no use.
Figuring out where the new live ranges are and how to name them is <strong>hard</strong>, even though you technically only have to
look “before” your inserted store and “after” the inserted load. But in the presence of control flow (branches and loops), it’s not that simple:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def x
STORE x
if (..) {
  use y
} else {
  LOAD x'
}
use x
</code></pre></div></div>

<p>Which x should we use after the branches join? This code is wrong and we either need to place a <code class="language-plaintext highlighter-rouge">LOAD x'</code> into the if-block,
or possibly a copy <code class="language-plaintext highlighter-rouge">x' -&gt; x</code> in the else branch.</p>

<p>To do that, I’d need to build a <a href="https://en.wikipedia.org/wiki/Reaching_definition">reaching definition analysis</a> anyway and then some.</p>

<h1 id="discovering-live-ranges">Discovering Live Ranges</h1>

<p>So I decided to address the problem at hand by implementing a “renumbering” phase.</p>

<p>The “classic” way of doing this, is by performing data-flow analysis to build explicit def-use chains.
Basically, we want to find all <abbr title="Virtual Register">vreg</abbr> definitions, create a list for each of them and add all the positions in the program
where this definition was used.
The data-flow analysis to get the reaching definitions is generally performed by a fixed-point algorithm.
Straight line code is simple, but for loops, you have to iterate until your data-flow facts no longer change (i.e., the fixed-point is reached).
This due to the fact, that information from the loop body can flow back to the loop head.</p>

<p>Once you have your def-use chains, i.e., <em>n</em> lists for each <abbr title="Live Range">LR</abbr>, you’ll want to perform pairwise intersection tests for all lists (with the same <abbr title="Virtual Register">vreg</abbr>).
There are probably ways to optimize this, but this takes a lot of time and space!</p>

<p>In fact, it seems like this is not the way to do it anymore. E.g., looking at “Engineering a Compiler”, after giving an overview of the problem it says:</p>

<blockquote>
  <p>Conversion of the code into ssa form simplifies the construction of live ranges; thus, we will assume that the allocator operates on ssa form.</p>
</blockquote>

<p>Even Briggs in 1994 wrote, that their compiler uses <abbr title="Static Single Assignment">SSA</abbr> instead of the “classical” way that Chaitin used.</p>

<h1 id="ssa---what--why"><abbr title="Static Single Assignment">SSA</abbr> - What &amp; Why</h1>

<p>What is <abbr title="Static Single Assignment">SSA</abbr> and how does it help us?
An intermediate representation is in Single Static Assignment form, if it conforms to a simple property:</p>

<blockquote>
  <p>Each name is only defined once, respectively, each definition introduces a new name</p>
</blockquote>

<p>This has many nice implications, simplifies data-flow analysis and even enables new optimizations<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup>.
Any use of an <abbr title="Static Single Assignment">SSA</abbr>-variable <code class="language-plaintext highlighter-rouge">x</code> is <em>dominated</em> by its definition, i.e., any path from the start of
the control flow graph of the program to the use has to go execute that definition - and there is only one definition.
Def-use chains are no longer necessary, each definition has to come from a straight line of predecessors, be within the same basic block, or defined by a φ-function at the beginning of a block or come from</p>

<p>What is a φ-function (or φ-node, “phi-function”)?
Let’s say we have a variable <code class="language-plaintext highlighter-rouge">x</code> that is redefined several times.
Each time, we update an index to create a new name, i.e., x<sub>0</sub>, x<sub>1</sub>, …
What if you have two different definitions of <code class="language-plaintext highlighter-rouge">x</code> reaching your basic block?
Which name do you have to choose?
This is where φ-functions come into play. Think of them as magically “selecting”
the right name, depending on where the control flow came from and defining a new name for
the selected value: x<sub>2</sub> = φ(x<sub>0</sub>, x<sub>1</sub>)
Semantically, these are considered to be executed as parallel copies, all at once,
at the beginning of the block, before the first instruction.</p>

<p>Here some code, which is <strong>not</strong> in <abbr title="Static Single Assignment">SSA</abbr>-form:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x := 0
if (...) {
    x := x + 1
} else {
    x := x + 2
}
y := x
</code></pre></div></div>

<p>…and transformed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x_0 := 0
if (...) {
    x_1 := x_0 + 1
} else {
    x_2 := x_0 + 2
}
x_3 = φ(x_1, x_2)
y := x_3
</code></pre></div></div>

<h2 id="ssa-destruction-and-live-range-discovery"><abbr title="Static Single Assignment">SSA</abbr> Destruction and Live Range Discovery</h2>

<p>Naturally, we can’t leave the code like this. CPU’s simply don’t have a φ instruction,
we need to get rid of them.</p>

<p>The process of transforming a program in <abbr title="Static Single Assignment">SSA</abbr>-form out-of-<abbr title="Static Single Assignment">SSA</abbr> (thus resolving all φ-functions)
is sometimes called <em><abbr title="Static Single Assignment">SSA</abbr> Destruction</em>.
There is quite a bit of literature on this and it gets complicated if you want fast and correct
<abbr title="Static Single Assignment">SSA</abbr> destruction.</p>

<p>But for our case, things are simpler. For now, all we want is to rename our live ranges,
so that each <abbr title="Virtual Register">vreg</abbr> represents a single, disjoint live range.
Sreedhar et al.<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup> noted the distinction between Conventional <abbr title="Static Single Assignment">SSA</abbr> (CSSA) and
Transformed <abbr title="Static Single Assignment">SSA</abbr> (TSSA). A program is in CSSA right after <abbr title="Static Single Assignment">SSA</abbr> transformation (or after repair)
and in TSSA once any program transformations have moved, removed or added code.
The difference is, that the φ arguments in CSSA do not <em>interfere</em> - whereas in TSSA they <em>might</em>.
Resolving φ-functions with interfering arguments requires the insertion of copies and
to keep your program fast, you will want to figure out <em>which ones</em> you need and which ones
you can get rid of.
For CSSA, you simply gather all names connected by φ-functions, using a <a href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure">union-find (disjoint-set union)</a>,
then assigning one name to each disjoint set.
Voilà, you’re done!</p>

<h1 id="further-reading">Further Reading</h1>

<p>Cooper &amp; Torczon’s “Engineering a Compiler” is one of my favorite textbooks on compilers and
contains lots of information on register allocation and <abbr title="Static Single Assignment">SSA</abbr>.</p>

<p>The (unfortunately unpublished) <a href="http://ssabook.gforge.inria.fr/latest/book.pdf">“<abbr title="Static Single Assignment">SSA</abbr> Book”</a>, by France’s INRIA, is a real treasure trove and shouldn’t be missed.</p>

<p>For a more exhaustive bibliography, check out <a href="http://www.dcs.gla.ac.uk/~jsinger/ssa.html">Jeremy Singer’s <abbr title="Static Single Assignment">SSA</abbr> Bibliography</a>.</p>

<h1 id="conclusion">Conclusion</h1>

<p>To summarize, in order to improve <abbr title="Glasgow Haskell Compiler">GHC</abbr>’s graph coloring register allocator,
I wanted to implement <em>passive live range splitting</em>, but discovered that several disjoint
live ranges may bear the same <abbr title="Virtual Register">vreg</abbr> name.
I’ve described what <abbr title="Static Single Assignment">SSA</abbr> is and how it may solve the problem.</p>

<p>In the next part, I’ll describe how I implemented <abbr title="Static Single Assignment">SSA</abbr>-transformation in <abbr title="Glasgow Haskell Compiler">GHC</abbr>
and what the results were.</p>

<p>If you spot any mistakes, omissions or want to provide feedback, comments, questions - you can reach me on <a href="https://twitter.com/cptwunderlich">Twitter</a>, or via mail with my username at gmail.</p>

<p><img src="https://visitor-badge.glitch.me/badge?page_id=cptwunderlich.ssa4ncg1-2021" alt="readers" /></p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://doi.org/10.1016/0096-0551(81)90048-5">Chaitin81</a>, improved by <a href="https://doi.org/10.1145/177492.177575">Briggs94</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://dl.acm.org/doi/10.1145/330249.330250">Poletto99</a>. Note that this algorithm is generally extended in such a way, that it isn’t really <em>linear</em>. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>Technically, this breaks the <abbr title="Live Range">LR</abbr> up into many tiny <abbr title="Live Ranges">LRs</abbr>, which still can cause interferences. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p>Confusingly, the literature seems to use <em>live range splitting</em> for both things, I prefer <em>live range discovery</em> to simply rename disjoint live ranges. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p>What do we learn? Always test your assumptions, i.e., check yourself before you wreck yourself! <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p>E.g., Sparse Conditional Constant Propagation <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:7" role="doc-endnote">
      <p><a href="https://doi.org/10.1007/3-540-48294-6_13">SreedharJGS99 - “Translating out of static single assignment form.”</a> <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Benjamin Maurer</name></author><category term="Haskell" /><category term="GHC" /><category term="compilers" /><category term="ssa" /><category term="register_allocation" /><category term="programming" /><summary type="html"><![CDATA[Improving the Graph Coloring Register Allocator]]></summary></entry><entry><title type="html">Hacking on GHC - First Steps</title><link href="http://www.benjaminmaurer.at/2021/04/21/ghc-hacking-first-steps.html" rel="alternate" type="text/html" title="Hacking on GHC - First Steps" /><published>2021-04-21T00:00:00+00:00</published><updated>2021-04-21T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2021/04/21/ghc-hacking-first-steps</id><content type="html" xml:base="http://www.benjaminmaurer.at/2021/04/21/ghc-hacking-first-steps.html"><![CDATA[<h1 id="hacking-on-ghc---getting-started">Hacking on GHC - Getting Started</h1>

<h2 id="intro">Intro</h2>

<p>For quite a long time I’ve been interested in compilers and to deepen my superficial knowledge of Haskell. Since I’m a hands-on learner, the latter requires an interesting project.
Getting started with contributing to an existing compiler on the other hand, is a daunting task, as these are usually large and complex projects.</p>

<p>As I was searching for a suitable project, I found <a href="https://andreaspk.github.io/posts/2019-08-25-Opinion%20piece%20on%20GHC%20backends.html">AndreasK’s blog post on GHC backends</a>. Digging deeper, I read his article on GHC’s <a href="https://en.wikipedia.org/wiki/Register_allocation#Graph-coloring_allocation">Graph Coloring Register Allocator</a> and a ticket with <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/16243">improvement ideas for -fregs-graph</a>.</p>

<p>Since I’m very interested in code generation and I’ve learned a bit about register allocation before, I thought that’d be a perfect place to start!</p>

<p>You can find some other (older) blog posts on how to get started in the <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/contributing#advice">GHC Wiki</a>, but I encountered many issues along the way.
Especially since some things are in a bit of a transition phase, e.g., the Make-base build vs. Hadrian-build.
That’s why I’ve decided to write about my experience - maybe someone will find the solution to a problem here or get motivated to start hacking on GHC!</p>

<p>Note that this is written from a Ubuntu Linux on x86_64 perspective.</p>

<h2 id="set-up">Set-Up</h2>

<p>First things first. You need a very recent version of GHC and other dependencies to build the latest GHC. The packages in your distribution’s repository may be way to old (GHC 9.1 requires at least 8.10.x, AFAIK).
Luckily, there is a <a href="https://launchpad.net/~hvr/+archive/ubuntu/ghc">PPA by Herbert V. Riedel</a> - the page also links to sources for Debian Stretch, Mac OS and WSL repositories.
Otherwise you might want to look at <a href="https://www.haskell.org/ghcup/">GHC Up</a>.</p>

<p>The following commands will add the PPA and install everything needed from the repositories (note that I’m not choosing GHC 9, as there are still some things incompatible with it, e.g., Haskell Language Server):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo add-apt-repository ppa:hvr/ghc
sudo apt update
sudo apt install build-essential autoconf git ghc-8.10.4 cabal-install-3.4
</code></pre></div></div>

<p>And now to checkout out the multi-module Git project into the current folder:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone --recurse-submodules https://gitlab.haskell.org/ghc/ghc.git
</code></pre></div></div>

<p>Add GHC/Cabal to your path:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo -e '# For GHC\nPATH="/opt/ghc/bin:$PATH"' &gt;&gt; ~/.profile
source ~/.profile
</code></pre></div></div>

<p>Now we need to install some Haskell packages, namely Happy &amp; Alex (lexer and parser generators):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cabal update
cabal install happy
cabal install alex
# Add '/home/&lt;username&gt;/.cabal/bin' to your ~/.profile
</code></pre></div></div>

<p>Don’t forget to add the path to .cabal/bin to your PATH in .profile and source it!
Check the versions to make sure everything is working:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cabal --version
ghc --version
alex --version
happy --version
</code></pre></div></div>

<p>For building the docs you’ll need Sphinx:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install python3-sphinx
</code></pre></div></div>

<p>If you want to use/work on the LLVM-backend, you’ll also need to install the right LLVM development packages.
Check the latest release notes to see which LLVM versions are supported.</p>

<h3 id="ide">IDE</h3>

<p>Now, I know that the “true Scotsmen” use emacs, or <em>maybe</em> vi, but despite having programmed for many years, I never gotten over that initial learning bump. That time investment just doesn’t seem justifiable to me. I prefer an IDE or at least a rich code editor.</p>

<p>VS Code is a popular and robust choice for this, so that’s what I’m using for Haskell.
Install VS Code, e.g., via the Ubuntu store, or download it from <a href="https://code.visualstudio.com/download">here</a>.</p>

<p>There are plenty of infos out there on how to install and configure VS Code, so I’ll stick to the Haskell specifics.
You’ll only need to install one extension:
Go to File -&gt; Preferences -&gt; Extensions and search for “Haskell”. You’ll find “Haskell - Haskell language support powered by…”, or alternatively, here the <a href="https://marketplace.visualstudio.com/items?itemName=haskell.haskell">direct link</a>.
This will also install the required extension “Haskell Syntax Highlighting”.</p>

<p>I can’t stress enough just how great the <a href="https://github.com/haskell/haskell-language-server">Haskell Language Server</a> is.
When I started, I tried manually compiling <em>ghcide</em> etc. and could barely get it to work. From the first release of Haskell LS, I could see and feel the improvements with every release.
Give it a try, even with emacs or vim.</p>

<p>In case Haskell LS still ends up having difficulties, it can help to hit <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> and search for “Restart Haskell LSP Server” and run that.</p>

<p>Another very useful command is “Trim Trailing Whitespace” - GHC’s CI has a linter that will fail your MR if you have trailing whitespace!
You can run the lint rules locally with <code class="language-plaintext highlighter-rouge">./hadrian/build lint:compiler</code> or <code class="language-plaintext highlighter-rouge">lint:base</code>, but you will need <code class="language-plaintext highlighter-rouge">hlint</code> on your PATH!</p>

<p>Opening the project with VS Code is pretty straight forward - just go to File -&gt; Open Folder and open your checkout directory of GHC.</p>

<h3 id="hlint">HLint</h3>

<p>Speaking of <a href="https://github.com/ndmitchell/hlint">hlint</a> - you can simply install it with cabal.
You might want to add your own .hlint.yaml to a subdirectory in GHC and add or ignore some rules.</p>

<h3 id="git">Git</h3>

<p>GHC’s Git project contains many submodules. Sometimes, when you want to get a branch completely up-to-date with upstream,
you’ll want to <a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules#_pulling_upstream_changes_from_the_project_remote">update all submodules recursively</a>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git pull --recurse-submodules
</code></pre></div></div>

<h2 id="build--test">Build &amp; Test</h2>

<p>Many of the things I’m writing here can be found on the nifty cheatsheet <a href="https://ghc.dev/">ghc.dev</a> - make sure to check it out.</p>

<p>But I’m getting ahead of myself. Let’s start with the basics and change into the GHC directory with your favorite terminal emulator (e.g., in VS Code).
Be aware that building GHC takes quite some computing resources and time, depending on the chosen optimizations.</p>

<p>Make sure to read the <a href="https://gitlab.haskell.org/ghc/ghc/-/tree/master/hadrian">Hadrian README</a>.
Basically, there are different build “Flavours” with different optimizations or additional configuration (e.g., profiling builds).
You can find an overview of the flavours <a href="https://gitlab.haskell.org/ghc/ghc/-/blob/master/hadrian/doc/flavours.md">here</a>.
GHC compilation is done in stages. Confusingly, sometimes you’ll see <em>stage0</em> and <em>stage1</em>, other times it starts with <em>stage1</em>. Anyway, the first stage is the bootstrap compiler, compiled with the GHC on your path. The next stage is compiled with the bootstrap compiler, containing all the latest GHC changes.</p>

<p>Before your first compile (and whenever you upgraded your system GHC, change to a very different branch or the like), run <code class="language-plaintext highlighter-rouge">./boot &amp;&amp; ./configure</code>, which configures the build with all your paths and tool versions.</p>

<p>Running <code class="language-plaintext highlighter-rouge">./hadrian/build -j --flavour=Quick</code> will build in parallel (<code class="language-plaintext highlighter-rouge">-j</code>) and produce a “quick” build (<code class="language-plaintext highlighter-rouge">-O0</code>).
Note that you can use <code class="language-plaintext highlighter-rouge">--freeze1</code> to avoid rebuilding the bootstrap compiler (if you haven’t changed anything relevant).</p>

<p>Hadrian has a clean command (<code class="language-plaintext highlighter-rouge">hadrian/build clean</code>), there is also <code class="language-plaintext highlighter-rouge">hadrian/ghci</code> to load GHC into a GHCi session and you can run the hlint rules with <code class="language-plaintext highlighter-rouge">hadrian/build lint:base</code> and <code class="language-plaintext highlighter-rouge">hadrian/build lint:compiler</code>.</p>

<p>After your build has finished, verify it by running <code class="language-plaintext highlighter-rouge">./_build/stage1/bin/ghc --version</code>.</p>

<p>To run GHC’s test suite, just run <code class="language-plaintext highlighter-rouge">./hadrian/build test</code> (but you might want to pass a flavour and other options) and check out testsuite/README.md for more options.</p>

<p>Although you should check out the build Flavours for yourself to find all the useful ones, like “quick” and “perf”,
there is a good <a href="https://mail.haskell.org/pipermail/ghc-devs/2021-May/019915.html">productivity tip from Matthew Pickering</a>, a flavour combination that
should pass almost the whole test suite, but reduces re-compile times:
<code class="language-plaintext highlighter-rouge">./hadrian/build --flavour=default+no_profiled_libs+omit_pragmas --freeze1 -j</code>
(adding <code class="language-plaintext highlighter-rouge">test</code> to that incantation if you want to run the test suite)</p>

<h3 id="read">Read</h3>

<p>Reading the READMEs of <a href="https://gitlab.haskell.org/ghc/ghc">GHC</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/tree/master/hadrian">Hadrian</a> and <a href="https://ghc.dev/">ghc.dev</a> gives you some quick and hands-on infos and commands.</p>

<p>To get the big picture view of GHC, there are also quite a few resources around!</p>

<p><a href="https://github.com/takenobu-hs/haskell-ghc-reading-guide">Takenobu’s GHC reading guide </a> is highly recommended, as well as their <a href="https://github.com/takenobu-hs/haskell-ghc-illustrated">GHC illustrated</a>.</p>

<p>Stephen Diehl also wrote about GHC, <a href="https://www.stephendiehl.com/posts/ghc_01.html">this is the first of a three-part</a> blog post series.
Be aware that some of the folder/module structures have changed, since that was written in 2016.</p>

<p>The Haskell Wiki is a double edges sword. While there is lots of extremely useful information, much of it is out-of-date and sometimes it’s hard to tell them apart.
Either way, you’ll want to look at the <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary">GHC Commentary</a> and the <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/reading-list">reading list</a>, which contains papers and other theoretical sources.</p>

<h2 id="get-connected">Get connected!</h2>

<p>Now that you can compile GHC and have some reading material, you want to get in touch with the community.</p>

<p>Get yourself a <a href="https://gitlab.haskell.org/">Gitlab account</a>, so you can participate on tickets and merge requests.
For the latter, you might want to create a fork of GHC for your account and add that as a <a href="https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes">git remote</a> locally.</p>

<p>Subscribe to the <a href="http://www.haskell.org/mailman/listinfo/ghc-devs">GHC mailing list</a>, to stay informed and get new ideas for projects!</p>

<p>AFAIK, most of the communication happens on IRC, so pop in at <a href="https://kiwiirc.com/nextclient/irc.libera.chat/#ghc">#GHC on libera.chat</a> - I have to say, people on their have been very friendly and extremely helpful!
There is also a <a href="https://kiwiirc.com/nextclient/chat.freenode.net/#Haskell-docs">#Haskell-docs</a> channel, where you can find support for your fervor to make Haskell documentation <em>excellent</em>.</p>

<p>You might also want to check out this Wiki page for <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/contributing#advice">new contributors</a>.</p>

<h2 id="what-to-work-on">What to work on?</h2>

<p>This is probably the hardest part. It very much depends on your knowledge and interests.
If you have an area of interest, search for that on the bug tracker or ask around on IRC.</p>

<p>Making GHC compile times <strong>faster</strong>, even by a tiny bit, or reducing memory consumption, will always be welcomed by the community.
If you have any experience with LLVM, I’m sure that there are also lots of ways to improve and speed-up the LLVM-backend.</p>

<p>Documentation is also <em>vital</em> and you can contribute by fixing mistakes, clarifying or adding descriptions.
One really simple and fast way to dip your toes into GHC development is this ticket on documenting yet <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/18641">undocumented command line flags</a>.
All you need is <code class="language-plaintext highlighter-rouge">grep</code> and some detective work.</p>

<h2 id="developers-life">Developer’s Life</h2>

<p>Usually, developing not only means writing code and compiling it, but debugging, profiling, benchmarking.
I wanted to touch on these topics here too, briefly, to help you start out.</p>

<h3 id="debugging">Debugging</h3>

<p>Let’s say you found yourself a project and you’re working hard at it.
Sooner or later, you’ll need to debug things. Unfortunately, there aren’t an awful lot of resources on this.</p>

<p>As mentioned above, there is a way to load GHC into GHCi. To be honest, I haven’t used this yet, as it didn’t seem to practical for working on the code generator.</p>

<p>This <a href="https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/flags.html#compiler-debugging-options">reference of debug flags</a> got quite a lot of use though.
You can dump intermediate steps along the way to figure out, where things went awry.</p>

<p>In lieu of a proper debugger, GHC.Driver.Ppr with it’s <code class="language-plaintext highlighter-rouge">pprTrace</code> and friends - where <code class="language-plaintext highlighter-rouge">ppr</code> stands for “pretty print”. GHC uses the <code class="language-plaintext highlighter-rouge">SDoc</code> type for string representations of data structures. I.e., this is the good old “printf-debugging”.
The compiler needs to be built with <code class="language-plaintext highlighter-rouge">-DDEBUG</code>, e.g., the <a href="https://gitlab.haskell.org/ghc/ghc/blob/master/hadrian/doc/flavours.md">devel1 flavour</a> and you can get additional output using the flag <code class="language-plaintext highlighter-rouge">-dppr-debug</code>.</p>

<p>When you have to debug a crashing output binary, you’ll also want to use GDB and possibly the reverse debugger <a href="https://rr-project.org/">rr</a>.</p>

<p>In some cases I have used ad-hoc scripts to visualize or search for interesting data in my traces.
Banging my head against the desk and crying profusely have not proven efficient techniques, despite my repeated tries.</p>

<h3 id="profiling">Profiling</h3>

<p>To enable <a href="https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/profiling.html">cost center profiling</a>, you’ll have to compile GHC and libs with profiling support.
Hadrian offers <a href="https://gitlab.haskell.org/ghc/ghc/-/blob/master/hadrian/doc/flavours.md#flavour-transformers">Flavour Transformers</a> for that.
Note the remark for the <code class="language-plaintext highlighter-rouge">profiled_ghc</code> transformer - you’ll want to also use <code class="language-plaintext highlighter-rouge">no_dynamic_ghc</code> and the flavour <em>“Quick”</em> won’t cut it.
E.g., use something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./hadrian/build -j --flavour="default+profiled_ghc+no_dynamic_ghc"
</code></pre></div></div>

<p>You can then use the RTS flags, like <a href="https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/runtime_control.html#rts-flag--xc">+RTX -xc</a>.</p>

<p>Check out the above linked GHC documentation for more on profiling and make sure to install Matthew Pickering’s <a href="https://mpickering.github.io/eventlog2html/">eventlog2html</a> for some graphical representation of profiling eventlogs.</p>

<p>Here just quickly two recipes I found myself using quite a bit:</p>

<p>Since GHC is quite big and I was working on a single module, it made sense to restrict the output to that module, using <code class="language-plaintext highlighter-rouge">-hm</code>.
The <code class="language-plaintext highlighter-rouge">-hy</code> option will give you a heap profile broken down by type and <code class="language-plaintext highlighter-rouge">-hc</code> breaks down time profiles by cost-center stack.</p>

<p>Here the type example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ghc -O2 Main.hs +RTS -hm"GHC.CmmToAsm.SSA" -hy -l-au
</code></pre></div></div>

<p>And cost-centers:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ghc -O2 Main.hs +RTS -hm"GHC.CmmToAsm.SSA" -hc -l-au
</code></pre></div></div>

<p>Using eventlog2html to visualize it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/ben/.cabal/bin/eventlog2html ghc.eventlog --bands 100 --include-trace-events &amp;&amp; firefox ghc.eventlog.html
</code></pre></div></div>

<h3 id="benchmarking">Benchmarking</h3>

<p>GHC’s <a href="https://gitlab.haskell.org/ghc/nofib">nofib benchmark suite</a> come with a whole slew of of benchmarks.</p>

<p>While there is a submodule in the GHC tree, I’ve been advised to create a separate checkout of nofib.
Like GHC, it has an old Make-based build and a new Shake-based one. I’ll only describe the latter here.</p>

<p>To start a full run of all benchmarks, simply use the <code class="language-plaintext highlighter-rouge">nofib-run</code> tool, like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Optional `cabal update`
cabal new-run -- nofib-run --compiler=/absolute/path/to/your/ghc --compiler-arg="-O2" --output=my-test
</code></pre></div></div>

<p>Note that the path to your GHC, used for compiling the tests, has to be an absolute path!
You can add any number of compiler args using the <code class="language-plaintext highlighter-rouge">--compiler-arg</code> flag.
<code class="language-plaintext highlighter-rouge">--output</code> is the name of the result folder.
To run tests “t”-times, use the <code class="language-plaintext highlighter-rouge">-t</code> switch.
There is a <code class="language-plaintext highlighter-rouge">-j</code> option for parallel runs, but this only makes sense if you want to stress test your compiler
to find e.g. crashes, as parallelization makes runtimes less deterministic and reproducible.
Refer to <code class="language-plaintext highlighter-rouge">cabal new-run -- nofib-run --help</code> for other options.</p>

<p>The Make-build only runs certain benchmark groups by default, AFAIK omitting <code class="language-plaintext highlighter-rouge">gc</code> and some other.
Using Shake, it will run <strong>all</strong> of them though. I haven’t figured out how to get the same behavior for both,
but you can simply specify a list of tests to run.</p>

<p>All tests come with three different “speed” settings: SLOW, NORMAL, FAST
This is supposed to enable benchmarking with different runtimes and also help normalize runtimes across benchmarks.
That being said, runtimes have become quite disparate…</p>

<p>Results from different runs can be compared with <code class="language-plaintext highlighter-rouge">nofib-compare</code>, e.g., to compare baseline to your optimization:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cabal new-run -- nofib-compare ./_make/baseline ./_make/my_opt
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">nofib-compare</code> also supports different output formats (CSV, ascii, markdown, latex).</p>

<p>For some serious measurements, you might want to install <code class="language-plaintext highlighter-rouge">perf</code>, which should be part of the <code class="language-plaintext highlighter-rouge">linux-tools-generic</code> package (or the specific one for your kernel).
That way, you get data from your CPUs hardware counters, which is more “objective” than pure wall-time.
To (temporarily) allow access to more CPU events, you have to allow that: <code class="language-plaintext highlighter-rouge">echo "0" | sudo tee /proc/sys/kernel/perf_event_paranoid</code>
Cache misses are not part of the default event set used by nofib - for some reason - but you can include them explicitly with these
arguments to nofib-run: <code class="language-plaintext highlighter-rouge">--perf --perf-arg="-ecache-misses,cycles,instructions"</code></p>

<p>Benchmarking is generally an arcane art. You’ll want to limit any interferences, like programs running in background
and you’ll <strong>definitely</strong> want to deactivate CPU frequency scaling and on-demand overclocking (“turbo boost”) - otherwise you’ll never have reproducible results.</p>

<p>To set the “performance” CPU governor:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo cpupower frequency-set -g performance
</code></pre></div></div>

<p>(Temporarily) deactivating “turbo boost”:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "0" | sudo tee /sys/devices/system/cpu/cpufreq/boost
</code></pre></div></div>

<p>(only tested this with my AMD chip, but should work for all CPUs. <a href="https://www.kernel.org/doc/Documentation/cpu-freq/boost.txt">See docs</a>)</p>

<p>Last but not least, nofib may sometimes break with the latest changes from GHC head.
Currently I can’t use the latest GHC release (9.0.1) for nofib-run, so I have to use 8.10.x.
Sometimes packages may become incompatible, but there is a hackage overlay with pre-releases, called <a href="https://gitlab.haskell.org/ghc/head.hackage">head.hackage</a>.</p>

<p>Nofib-run now has an option to use head.hackage directly.
Update the packages first with <code class="language-plaintext highlighter-rouge">cabal v2-update --project-file=nofib.head head.hackage.ghc.haskell.org</code>,
then simply pass the <code class="language-plaintext highlighter-rouge">--head</code> flag to <code class="language-plaintext highlighter-rouge">nofib-run</code>.
Also see nofib/shake/README.mkd.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I hope this provided a gentle introduction to GHC development for you all and that some of you will contribute to this great project.
Maybe this saves someone time that I spent scratching my head.</p>

<p>If you spot any mistakes, omissions or want to provide feedback, comments, questions - you can reach me on <a href="https://twitter.com/cptwunderlich">Twitter</a>, or via mail with my username at gmail.</p>

<h2 id="updates">Updates</h2>

<p>I’ll try to keep this somewhat up-to-date, but things sometimes move fast.</p>

<p>??.??.???? - Removed description of Hadrian’s <code class="language-plaintext highlighter-rouge">-c</code> option, bc. I was made aware of problems with it and that calling <code class="language-plaintext highlighter-rouge">./boot &amp;&amp; ./configure</code> explicitly is preferable.</p>

<p>16.07.2021 - Added mention of test suite and mpickerings productivity tip, also nofib-run’s <code class="language-plaintext highlighter-rouge">--head</code> option.</p>

<p>24.03.2022 - Mentioned that you need <code class="language-plaintext highlighter-rouge">-DDEBUG</code> to see <code class="language-plaintext highlighter-rouge">pprTrace</code> messages.</p>

<p><img src="https://visitor-badge.glitch.me/badge?page_id=cptwunderlich.hackingonghc2021" alt="readers" /></p>]]></content><author><name>Benjamin Maurer</name></author><category term="Haskell" /><category term="GHC" /><category term="compilers" /><category term="programming" /><summary type="html"><![CDATA[Hacking on GHC - Getting Started]]></summary></entry><entry><title type="html">(GER) Antisemitische Straftaten in Deutschland 2020</title><link href="http://www.benjaminmaurer.at/2021/02/13/antisemitismus-de-2020.html" rel="alternate" type="text/html" title="(GER) Antisemitische Straftaten in Deutschland 2020" /><published>2021-02-13T00:00:00+00:00</published><updated>2021-02-13T00:00:00+00:00</updated><id>http://www.benjaminmaurer.at/2021/02/13/antisemitismus-de-2020</id><content type="html" xml:base="http://www.benjaminmaurer.at/2021/02/13/antisemitismus-de-2020.html"><![CDATA[<!DOCTYPE html>

<!-- 
    Copyright (c) Benjamin Maurer 2021
    Twitter: @cptwunderlich
    Github: https://github.com/cptwunderlich
-->

<html lang="de">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <title>Antisemitische Straftaten in Deutschland 2020</title>

    <style>
        .chart {
            height: 350px;
        }
    </style>
  </head>

  <body>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    
    <h2>Worum es geht</h2>

    <p>Nachdem jemand auf Twitter einen "Der Spiegel" link gepostet hatte,
    mit wirklich schlechten Datenvisualisierungen zu antisemtischen Straftaten in Deutschland,
    dachte ich mir - das geht doch besser.</p>
    
    <p>Also hier - hoffentlich - lesbarere Tortendiagramme, in denen auch alle Kategorien unterschieden werden, sowie eine Aufschlüsselung nach Bundesländern.</p>

    <p>Sollte jemand so einen Datensatz f&uuml;r &Ouml;sterreich kennen, lasst es mich bitte wissen!</p>

    <p>
        <span style="background-color: #FFD300;">Achtung: Ein moderner Webbrowser wird benötigt! Z.B. Internet Explorer wird <b>nicht</b> unterstützt!</span>
    </p>

    <p>F&uuml;r die Richtigkeit der Daten wird keine Haftung &uuml;bernommen!</p>

    <p>Quelle sind Daten veröffentlicht von <a href="https://www.petrapau.de/19_bundestag/dok/down/2020_zf_antisemitische_straftaten.pdf">MdB Petra Pau.</a></p>

    <p>Ich hab &uuml;brigens keinen Google API Key, also wenn die Karte unten nicht l&auml;dt, haben sie mir vermutlich den Hahn abgedreht :))</p>

    <h3>Gesamt</h3>

    <p>Gesamtzahl der gemeldeten Antisemitischen Straftaten, inklusive nicht zugeordneter Nachmeldungen bis 31.12.2020.</p>

    <div id="pie_totals_chart" class="chart"></div>
        
    <h3>Nur Zugeordnete</h3>

    <p>Nur zugeordnete Straftaten, d.h. ohne Nachmeldungen.</p>

    <div id="pie_totals_assessed_chart" class="chart"></div>

    <h3>Nur Gewaltstraftaten</h3>

    <p>Hierzu wurden 21 Verletzte (29 mit Nachmeldungen) gemeldet.</p>

    <div id="pie_violence_chart" class="chart"></div>

    <h3>Nach Bundesland</h3>

    <p>Aufschlüsselung aller Straftaten nach Bundesland.</p>

    <div id="map_chart" class="map"></div>
    
    <script type="text/javascript">
        google.charts.load('current', {
            'packages':['corechart', 'geochart'],
        });
        google.charts.setOnLoadCallback(drawAll);

        function drawAll() {
            drawTotals();
            drawAssessed();
            drawViolent();
            drawMap();
        };

        const red = '#CD2800';
        const green = '#109618';
        const violet = '#990099';
        const yellow = '#ff9900';
        const blue = '#3366cc';
        const teal = '#0099c6';

        function drawMap() {
            const statesSlice = states.map(xs => xs.slice(0, 3));
            const options = {
                backgroundColor: '#F8F8F8',
                region: "DE",
                resolution: "provinces"
            };
            const data = google.visualization.arrayToDataTable(statesSlice);

            let geochart = new google.visualization.GeoChart(document.getElementById('map_chart'));
            geochart.draw(data, options);
        }

        function drawTotals() {
            // Totals
            const totalsData = google.visualization.arrayToDataTable(totals);
            const options = {
                title: 'Antisemitische Straftaten 2020 Gesamt (inkl. Nachmeldungen)',
                backgroundColor: '#F8F8F8',
                slices: [ { color: red }, { color: green }, { color: violet },
                    { color: yellow }, { color: blue }, { color: teal } ]
            };
            let totalsChart = new google.visualization.PieChart(document.getElementById('pie_totals_chart'));
            totalsChart.draw(totalsData, options);
        }

        function drawAssessed() {
            // No additions
            const noAdd = totals.slice(0, totals.length-1);
            const options = {
                title: 'Antisemitische Straftaten 2020 Gesamt',
                backgroundColor: '#F8F8F8',
                slices: [ { color: red }, { color: green }, { color: violet },
                    { color: yellow }, { color: blue } ]
            };
            const noAddData = google.visualization.arrayToDataTable(noAdd);
            let noAddChart = new google.visualization.PieChart(document.getElementById('pie_totals_assessed_chart'));
            noAddChart.draw(noAddData, options);
        }

        function drawViolent() {
            // Violent felonies
            const violenceData = google.visualization.arrayToDataTable(violence);
            const options = {
                title: 'Antisemitische Gewaltstraftaten 2020',
                backgroundColor: '#F8F8F8',
                slices: [ { color: red }, { color: violet },
                    { color: yellow }, { color: blue } ]
            };
            let violenceChart = new google.visualization.PieChart(document.getElementById('pie_violence_chart'));
            violenceChart.draw(violenceData, options);
        }

        const totals = [
            ['PMK', 'Anzahl'],
            ['Rechts', 1247],
            ['Links', 9],
            ['Ausländische Ideologie', 18],
            ['Religiöse Ideologie', 20],
            ['Nicht zugeordnet', 39],
            ['Nachgemeldet (nicht zugeordnet)', 942]
        ];

        const violence = [
            ['PMK', 'Anzahl'],
            ['Rechts', 27],
            ['Links', 0],
            ['Ausländische Ideologie', 1],
            ['Religiöse Ideologie', 1],
            ['Nicht zugeordnet', 3]
        ];

        const states = [
            ['Bundesland', 'Straftaten Gesamt', 'Rechts', 'Links', 'Ausländische Ideologie', 'Religiöse Ideologie', 'Nicht zugeordnet'],
            ['DE-BB', 100, 95, 0, 2, 1, 2],
            ['DE-BE', 256, 238, 3, 6, 3, 6],
            ['DE-BW', 74, 67, 0, 0, 3, 4], 
            ['DE-BY', 209, 197, 1, 3, 1, 7], 
            ['DE-HB', 18, 17, 0, 0, 1, 0], 
            ['DE-HE', 51, 50, 0, 0, 1, 0], 
            ['DE-HH', 25, 20, 0, 0, 2, 3], 
            ['DE-MV', 57, 48, 0, 0, 5, 4], 
            ['DE-NI', 127, 120, 0, 0, 5, 2], 
            ['DE-NW', 127, 118, 4, 3, 0, 2], 
            ['DE-RP', 44, 40, 0, 0, 0, 4], 
            ['DE-SH', 27, 25, 0, 2, 0, 0], 
            ['DE-SL', 11, 10, 0, 0, 0, 1], 
            ['DE-SN', 107, 98, 0, 2, 2, 5], 
            ['DE-ST', 55, 55, 0, 0, 0, 0],
            ['DE-TH', 50, 49, 1, 0, 0, 0]
        ];
    </script>
  </body>
</html>]]></content><author><name>Benjamin Maurer</name></author><category term="antisemitism" /><category term="german" /><summary type="html"><![CDATA[]]></summary></entry></feed>