<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/assets/xsl/feed.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Tommy McMichen</title>
    <description>Personal website for Tommy McMichen</description>
    <link>https://mcmichen.cc</link>
    <atom:link href="https://mcmichen.cc/feed.xml" rel="self" type="application/rss+xml" />
    <language>en-us</language>
    
    
      <item>
        <title>Automatic Data Enumeration for Fast Collections</title>
        <description>&lt;p&gt;This post is based on a &lt;a href=&quot;/files/papers/ADE_CGO_2026.pdf&quot;&gt;paper&lt;/a&gt; of the same name, published at CGO 2026.&lt;/p&gt;
&lt;p&gt;Data collections are everywhere!
They provide a powerful abstraction to organize data, simplifying software development and maintenance.
However, choosing how we &lt;em&gt;implement&lt;/em&gt; each collection in our program is critical for both performance and memory usage.&lt;/p&gt;
&lt;p&gt;While general-purpose data collections (the ones in the C++ STL, Abseil, etc.) provide drop-in replacements for quick performance tuning, the real value comes from &lt;em&gt;specialized&lt;/em&gt; implementations.
Specialized implementations (bitsets, prefix trees, bloom filters) provide superior performance and memory usage compared to their general-purpose counterparts.
However, they require additional constraints on the kind of data stored, and the methods used to access them.&lt;/p&gt;
&lt;p&gt;For example, let&#39;s look at bitsets.
In this domain, other implementations pale in comparison, as shown in the speedup table below.
However, a bitset requires dense (or better yet, contiguous), integer keys.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Insert&lt;/th&gt;
&lt;th&gt;Remove&lt;/th&gt;
&lt;th&gt;Union&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;std::unordered_set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;absl::flat_hash_set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.61&lt;/td&gt;
&lt;td&gt;0.40&lt;/td&gt;
&lt;td&gt;1.71&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;boost::dynamic_bitset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9.08&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.24&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5817.38&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Those are some pretty nice performance boosts, and if my set is dense enough we&#39;ll get good memory savings too.
But, what if I&#39;m in a domain that doesn&#39;t have the necessary guarantees to use a bitset?
Is there any hope for the folks processing non-integer data types, or sparse domains?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The good news:&lt;/em&gt; &lt;strong&gt;There is.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The bad news:&lt;/em&gt; &lt;strong&gt;It&#39;s not free.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Data Enumeration&lt;/h3&gt;
&lt;p&gt;If we don&#39;t have inherent data properties guaranteed by our domain to rely on, we can instead &lt;strong&gt;engineer the desired property&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Take the following code, which iterates over a list of strings (&lt;code&gt;items&lt;/code&gt;) and prints unique items by tracking duplicates in a set (&lt;code&gt;seen&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;has&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to use a &lt;code&gt;bitset&lt;/code&gt; instead of a &lt;code&gt;set&lt;/code&gt;, we can do a bit of transformation (shown below).
First, we&#39;ll assign unique identifiers to each item and maintain a bidirectional mapping (&lt;code&gt;enc&lt;/code&gt; and &lt;code&gt;dec&lt;/code&gt;) to convert between the ID and the actual data.
Then, we convert the data stored in our input array to use IDs (&lt;code&gt;items&lt;/code&gt;).
Now that we are iterating over IDs (which we&#39;ve assigned to be contiguous), we can convert &lt;code&gt;seen&lt;/code&gt; into a bitset.
Finally, we need to patch up any use that requires the original (the &lt;code&gt;print&lt;/code&gt; statement) by decoding the identifier.
Et voilà!&lt;/p&gt;
&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;enc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
dec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bitset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;has&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        item &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dec&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;ve successfully converted our program to use a bitset, instead of a set.
Now, we can reap the performance and memory benefits!
Additionally, we can perform comparisons between our items much faster by using their ID instead of the string.&lt;/p&gt;
&lt;p&gt;However, we&#39;ve gotten ourselves into a bit of a pickle now by applying this manually.
I have to juggle my IDs and values everywhere in the program.
Additionally, I need to make &lt;code&gt;enc&lt;/code&gt; and &lt;code&gt;dec&lt;/code&gt; available anywhere that I need to translate between IDs and values.
Furthermore, I&#39;m left with a bit of a performance headache figuring out if I should use IDs or values in different parts of my program.
Yeesh, this sounds like the job for a compiler!&lt;/p&gt;
&lt;h3&gt;Automatic Data Enumeration&lt;/h3&gt;
&lt;p&gt;Instead of performing data enumeration manually, I propose that we do it automatically.
Looking at the example above, the transformation itself is rather mechanical.
We just need the proper substrate to implement it.
LLVM is a bit too low-level, and there&#39;s no existing MLIR dialect for this stuff, but I&#39;ve heard of a cool new compiler IR on the block: &lt;a href=&quot;/memoir&quot;&gt;MEMOIR&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;MEMOIR is nice here because it preserves high-level semantics about data collections, which we&#39;ll need to transform how we store our data.
Additionally, its SSA form makes the analysis we need very easy.
Sounds like the &lt;em&gt;perfect&lt;/em&gt; substrate to implement &lt;strong&gt;Automatic Data Enumeration (ADE)&lt;/strong&gt;.
I won&#39;t get into all the nitty gritty about &lt;em&gt;how&lt;/em&gt; we mechanize the data enumeration transformation here, but I will give the high-level overview.&lt;/p&gt;
&lt;p&gt;Fundamentally, ADE transforms the program to build an &lt;em&gt;on-the-fly&lt;/em&gt; enumeration (the bidirectional mapping from IDs to values).
This means that whenever you encode a value for the first time, it will be assigned a unique identifier.
ADE is responsible for determining where we should use IDs instead of values, and then inserting translations using the enumeration.
As you would expect, this introduces a lot of &lt;em&gt;redundant translations&lt;/em&gt;, which can be eliminated:&lt;/p&gt;
&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;enum_A &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bitset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    id_1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; enc&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enum_A&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;has&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id_1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        id_2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; enc&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enum_A&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# redundant, replace id_2 with id_1&lt;/span&gt;
        seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id_2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eliminating redundant translations is the main performance driver of ADE, so we introduce a few transformations that introduces more redundancy.
One of these is sharing (shown below), where we have two sets share the same enumeration.
Sharing has the added benefit of amortizing the cost of constructing the enumeration.&lt;/p&gt;
&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;enum_A &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bitset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
seen_twice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bitset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    id_1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; enc&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enum_A&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    id_2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; enc&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enum_A&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# redundant, replace id_2 with id_1&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;has&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id_1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id_1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; seen_twice&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;has&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id_2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        id_3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; enc&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enum_A&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        seen_twice&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id_3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# redundant, replace id_3 with id_1&lt;/span&gt;
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are more optimization, with full details available in Section 3 of the &lt;a href=&quot;/files/papers/ADE_CGO_2026.pdf&quot;&gt;paper&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Evaluation&lt;/h3&gt;
&lt;p&gt;So that&#39;s all great, but how about the performance?
In short, ADE provides significant performance improvements in the majority of our benchmarks.
While ADE incurs an increase in memory usage for a few cases, we find that the majority of benchmarks experience no memory explosion, with some seeing significant memory savings!
For a more detailed evaluation on both Intel and ARM machines, along with comparisons to Abseil swiss tables, see Section 5 of the &lt;a href=&quot;/files/papers/ADE_CGO_2026.pdf&quot;&gt;paper&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/assets/images/ADE-speedup-Intel.png&quot; loading=&quot;lazy&quot;&gt;
&lt;figcaption&gt;Whole-program speedup of ADE over std::unordered_set.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/assets/images/ADE-maxrss-Intel.png&quot; loading=&quot;lazy&quot;&gt;
&lt;figcaption&gt;Maximum resident set size of ADE over std::unordered_set.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;Tuning&lt;/h3&gt;
&lt;p&gt;In addition to fully automatic ADE, we provide ways for users to guide the optimization.
This lets you enable/disable enumeration for a collection, and prevent/force sharing between collections.
By overriding the static cost model, users can fine tune data enumeration for their specific application.&lt;/p&gt;
&lt;p&gt;We did a brief case study for LLVM Andersen-style points-to analysis (PTA).
In short, we identified a case where sharing with a specific collection was detrimental to performance.
The full details and exploration are in Section 5, RQ4 of the &lt;a href=&quot;/files/papers/ADE_CGO_2026.pdf&quot;&gt;paper&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By injecting a single &lt;code&gt;noshare&lt;/code&gt; directive, ADE achieved a speedup of &lt;em&gt;78x&lt;/em&gt; (13.7x over fully automatic ADE).
In addition to the performance gains, memory usage (max resident set size) was reduced by &lt;em&gt;71%&lt;/em&gt; (compared to 49% reduction with fully automatic ADE).&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Automatic Data Enumeration provides a fully automatic, transparent solution to one class of memory optimization in the compiler.
With ADE we are able to achieve significant performance improvements without the need for developer input, though tuning can unlock further savings.
Thanks to MEMOIR, the &lt;a href=&quot;https://github.com/arcana-lab/memoir&quot;&gt;implementation&lt;/a&gt; is straightforward (and &lt;em&gt;fun!&lt;/em&gt;).
I believe that data enumeration is just one of many memory optimizations that can be automated by the compiler, and I hope for a future where developers can trust the compiler to handle most of them.&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;For more information, see the &lt;a href=&quot;/files/papers/ADE_CGO_2026.pdf&quot;&gt;paper&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-tex&quot;&gt;&lt;code class=&quot;language-tex&quot;&gt;@inproceedings&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;MEMOIR-ADE:McMichen_Campanoni:2026,
    title=&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Automatic Data Enumeration for Fast Collections&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    authors=&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;McMichen, Tommy and Campanoni, Simone&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    booktitle=&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;CGO&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
    year=&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;2026&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;,
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To see how we implemented ADE in the MEMOIR compiler, see the &lt;a href=&quot;https://github.com/arcana-lab/memoir&quot;&gt;open-source repository&lt;/a&gt;.&lt;/p&gt;
</description>
        <link>https://mcmichen.cc/posts/automatic-data-enumeration/</link>
        <guid>https://mcmichen.cc/posts/automatic-data-enumeration/</guid>
        <pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate>
      </item>
    
      <item>
        <title>Running Out-of-Tree LLVM Passes at LTO</title>
        <description>&lt;p&gt;I had a long time trying to find the proper way to run LLVM pass plugins at LTO.
There were a lot of times where I found a solution and it turned out to be flimsy and break under some circumstances, or not fully support all the features I needed.
This post gives your my solution and concludes with some thoughts about &lt;em&gt;why&lt;/em&gt; this solution works.
If anyone knows that I am correct/wrong please confirm/correct me.
Otherwise, take the explanation with a grain of salt, I have not extensively tested it.&lt;/p&gt;
&lt;h2&gt;My Solution&lt;/h2&gt;
&lt;p&gt;In the examples, I will use a hypothetical LLVM pass plugin where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyPlugin.so&lt;/code&gt; is the shared object containing the LLVM pass plugin.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MyPass&lt;/code&gt; is the name of a pass in the plugin (registered with the new pass manager).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--my-flag&lt;/code&gt; is a compiler flag that is registered in the plugin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A typical invocation of this pass using &lt;code&gt;opt&lt;/code&gt; would look like:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;opt -load-pass-plugin&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MyPlugin.so &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;-passes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;MyPass&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    --my-flag &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, if you want to run this pass under the linker, it would look a little different:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ld.lld --load-pass-plugin&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MyPlugin.so &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
       --lto-newpm-passes&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;MyPass&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
       &lt;span class=&quot;token parameter variable&quot;&gt;-mllvm&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-load&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MyPlugin.so &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
       &lt;span class=&quot;token parameter variable&quot;&gt;-mllvm&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;--my-flag &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above solution comes from an &lt;code&gt;lld&lt;/code&gt; test: https://github.com/llvm/llvm-project/blob/main/lld/test/ELF/lto/ltopasses-extension.ll&lt;/p&gt;
&lt;p&gt;So now, let&#39;s do the same thing for &lt;code&gt;clang&lt;/code&gt; with LTO enabled:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;clang &lt;span class=&quot;token parameter variable&quot;&gt;-flto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;full -fuse-ld&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;lld &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
      -Wl,--load-pass-plugin&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MyPlugin.so &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
      -Wl,--lto-newpm-passes&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;MyPass&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
      -Wl,-mllvm&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-load&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;MyPlugin.so &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
      -Wl,-mllvm&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;--my-flag &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;My Understanding&lt;/h2&gt;
&lt;p&gt;The first &lt;code&gt;-load-pass-plugin=MyPlugin.so&lt;/code&gt; loads your pass plugin with lld, which runs pipeline parsing on &lt;code&gt;--lto-newpm-passes=&#39;MyPass&#39;&lt;/code&gt; to construct the &lt;code&gt;llvm::PassBuilder&lt;/code&gt;.
So, if you did not load your plugin, this would result in an error during parsing.&lt;/p&gt;
&lt;p&gt;The second &lt;code&gt;-mllvm=-load=MyPlugin.so&lt;/code&gt; is passed to the actual invocation of the LLVM optimizer, making your pass plugin available internally.
From my debugging, you only need this &lt;code&gt;-load&lt;/code&gt; to populate your flags (e.g., &lt;code&gt;--my-flag&lt;/code&gt;), the first &lt;code&gt;-load-pass-plugin&lt;/code&gt; is sufficient to run your pass without flags.&lt;/p&gt;
&lt;p&gt;I ran a couple of tests to back up these claims:&lt;/p&gt;
&lt;p&gt;Omitting the first &lt;code&gt;-load-pass-plugin=MyPlugin.so&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;LLVM ERROR: unable to parse pass pipeline description &lt;span class=&quot;token string&quot;&gt;&#39;MyPass&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; unknown pass name &lt;span class=&quot;token string&quot;&gt;&#39;MyPass&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Omitting the second &lt;code&gt;-mllvm=-load=MyPlugin.so&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ld.lld: error: --mllvm: ld.lld: Unknown &lt;span class=&quot;token builtin class-name&quot;&gt;command&lt;/span&gt; line argument &lt;span class=&quot;token string&quot;&gt;&#39;--my-flag&#39;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Concluding Remarks&lt;/h2&gt;
&lt;p&gt;LLVM&#39;s new pass manager is very {un,under}documented, I will try to share my own experiences with it here when I learn something new.
If you similarly get something to work, it would be great if you could share it with the community!
I have found a surprising lack of community notes (blog posts, mailing lists, etc.) about the new pass manager, which is a little concerning.
There are a lot of &amp;quot;weird&amp;quot; LLVM use cases and a critical mass of documentation is one way we can get around individually debugging the same mechanism ad infinitum.&lt;/p&gt;
</description>
        <link>https://mcmichen.cc/posts/llvm-lto-custom-pass/</link>
        <guid>https://mcmichen.cc/posts/llvm-lto-custom-pass/</guid>
        <pubDate>Wed, 14 Jan 2026 00:00:00 GMT</pubDate>
      </item>
    
      <item>
        <title>Private Fork of Git Repo</title>
        <description>&lt;p&gt;I find myself creating a private fork of public repositories rather frequently.
There are a variety of benefits to this over just create a public fork and working there, but that&#39;s not what this post is about.
I have found two solutions to this problem, which I will go over in this post.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;git-private-fork&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The first solution works when making a private fork of any git repository:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Clone the version control data of the public repository.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone &lt;span class=&quot;token parameter variable&quot;&gt;--bare&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PUBLIC_REPO}&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PUBLIC_REPO_DIR}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Enter the cloned directory&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PUBLIC_REPO_DIR}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Push an exact copy of the git repository.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push &lt;span class=&quot;token parameter variable&quot;&gt;--mirror&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PRIVATE_REPO}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Leave the cloned directory&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;popd&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Clean up.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PUBLIC_REPO_DIR}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone &lt;span class=&quot;token variable&quot;&gt;${PRIVATE_REPO}&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PRIVATE_REPO_DIR}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${SET_UPSTREAM+x}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;pushd&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PRIVATE_REPO_DIR}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; upstream &lt;span class=&quot;token variable&quot;&gt;${PUBLIC_REPO}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote set-url &lt;span class=&quot;token parameter variable&quot;&gt;--push&lt;/span&gt; upstream DISABLE
    &lt;span class=&quot;token function&quot;&gt;popd&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I will usually go ahead and set the public repo as my upstream too:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; upstream &lt;span class=&quot;token variable&quot;&gt;${PUBLIC_REPO}&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote set-url &lt;span class=&quot;token parameter variable&quot;&gt;--push&lt;/span&gt; upstream DISABLE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find this solution with some other little improvements at &lt;a href=&quot;https://github.com/tommymcm/git-tools/&quot;&gt;github.com/tommymcm/git-tools/&lt;/a&gt;.
Feel free to open any issues/PRs there.&lt;/p&gt;
&lt;h2&gt;GitHub Import&lt;/h2&gt;
&lt;p&gt;There is one known issue though, which comes up when forking rather large repositories (like &lt;code&gt;llvm/llvm-project&lt;/code&gt;).
For large repositories, you may hit single-push limits (2GiB on GitHub).
I have toyed around with making a general-purpose solution in &lt;code&gt;git-private-fork&lt;/code&gt;, but I couldn&#39;t ever get one that handled all the edge cases (rate-limits, size-limits, granularity).&lt;/p&gt;
&lt;p&gt;Instead of fixing that, I typically just fallback to importing the repository on GitHub.
Disclaimer, that I don&#39;t know of a solution for other hosts like gitlab or codeberg because I don&#39;t use them.
I&#39;d assume they have a similar feature though.&lt;/p&gt;
&lt;p&gt;To create your private fork by importing, go to &lt;a href=&quot;https://github.com/new/import&quot;&gt;github.com/new/import&lt;/a&gt;.
It&#39;s self explanatory.&lt;/p&gt;
&lt;p&gt;Disclaimer, this is a pretty slow process for large repositories.
However, it&#39;s the perfect thing to run while you go grab lunch, or write a blog post.&lt;/p&gt;
&lt;h2&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I&#39;d like to thank &lt;a href=&quot;https://gist.github.com/0xjac&quot;&gt;0xjac&lt;/a&gt; and &lt;a href=&quot;https://gist.github.com/ConfoundingVariables&quot;&gt;ConfoundingVariables&lt;/a&gt; on GitHub for providing the original solutions in a &lt;a href=&quot;https://gist.github.com/0xjac/85097472043b697ab57ba1b1c7530274&quot;&gt;Gist&lt;/a&gt; and the &lt;a href=&quot;https://gist.github.com/0xjac/85097472043b697ab57ba1b1c7530274?permalink_comment_id=4717207#gistcomment-4717207&quot;&gt;comments&lt;/a&gt;.&lt;/p&gt;
</description>
        <link>https://mcmichen.cc/posts/github-private-fork/</link>
        <guid>https://mcmichen.cc/posts/github-private-fork/</guid>
        <pubDate>Wed, 14 Jan 2026 00:00:00 GMT</pubDate>
      </item>
    
      <item>
        <title>Deploying Eleventy site with GitHub Actions</title>
        <description>&lt;p&gt;I recently moved my website from hand-written HTML over to &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy&lt;/a&gt;.
It&#39;s been really nice to work with, the transition process is smooth, and their template system is intuitive.
I&#39;m now able to generate all of my web content from a single source of JSON files! &lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; You can find the source code &lt;a href=&quot;https://www.github.com/tommymcm/materials&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;After finishing up my port, I was interested in automate the process of publishing changes, which is what this post is about.
I originally did this work with two repos because I wanted to have the materials (unpublished papers, course materials, etc.) not be public.
Since then, I moved over to a public repo to avoid hitting any GitHub Action limits&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;sup&gt;2&lt;/sup&gt; I am a penny pincher.&lt;/span&gt;&lt;/span&gt;
and use a private fork to hold uinpublished items.&lt;/p&gt;
&lt;p&gt;Here&#39;s the step-by-step process that I took:&lt;/p&gt;
&lt;h3&gt;1. Create a Personal Access Token (PAT)&lt;/h3&gt;
&lt;p&gt;First, you need to create a token that allows the private repo to push to your GitHub Pages repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Generate new token (classic)&amp;quot;&lt;/li&gt;
&lt;li&gt;Give it a name like &amp;quot;Eleventy Deploy&amp;quot;&lt;/li&gt;
&lt;li&gt;Select the repo scope (this gives full control of private repositories)&lt;/li&gt;
&lt;li&gt;Generate and copy the token (you won&#39;t see it again!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Add the Token to Your Private Repo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Go to your private repo&#39;s Settings → Secrets and variables → Actions&lt;/li&gt;
&lt;li&gt;Click &amp;quot;New repository secret&amp;quot;&lt;/li&gt;
&lt;li&gt;Name it PAGES_DEPLOY_TOKEN&lt;/li&gt;
&lt;li&gt;Paste your personal access token&lt;/li&gt;
&lt;li&gt;Save it&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Create the GitHub Action Workflow&lt;/h2&gt;
&lt;p&gt;In your private repo, create .github/workflows/deploy.yml:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build and Deploy to GitHub Pages

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; main  &lt;span class=&quot;token comment&quot;&gt;# or whatever your default branch is&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;build-and-deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout private repo
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4
      
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup bun
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; oven&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sh/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;bun@v2

      &lt;span class=&quot;token comment&quot;&gt;# bun is fun! if you disagree, you can use node:&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;# - name: Setup Node.js  &lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#   uses: actions/setup-node@v4&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#   with:&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#     node-version: &#39;20&#39;  # or your preferred version&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#     cache: &#39;npm&#39;&lt;/span&gt;
      
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install dependencies
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bun install
      
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build Eleventy site
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bun run eleventy
      
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy to GitHub Pages repo
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; peaceiris/actions&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages@v3
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;personal_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $
          &lt;span class=&quot;token key atrule&quot;&gt;external_repository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; you/you.github.io  &lt;span class=&quot;token comment&quot;&gt;# TODO: your pages repo&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; main  &lt;span class=&quot;token comment&quot;&gt;# or gh-pages, depending on your setup&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./_site  &lt;span class=&quot;token comment&quot;&gt;# Eleventy&#39;s default output directory&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;cname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yourdomain.com  &lt;span class=&quot;token comment&quot;&gt;# TODO: custom domain (optional)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Configure Your GitHub Pages Repo&lt;/h3&gt;
&lt;p&gt;Make sure your GitHub Pages repository is set to publish from the branch you specified (usually &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;gh-pages&lt;/code&gt;) in the repository settings.&lt;/p&gt;
&lt;p&gt;That&#39;s it! Now when you push to your repo, it will automatically build your Eleventy site and deploy it to your GitHub Pages repo.&lt;/p&gt;
</description>
        <link>https://mcmichen.cc/posts/eleventy-github-workflow/</link>
        <guid>https://mcmichen.cc/posts/eleventy-github-workflow/</guid>
        <pubDate>Wed, 17 Dec 2025 00:00:00 GMT</pubDate>
      </item>
    
  </channel>
</rss>