<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PyPy (Posts about toy-optimizer)</title><link>https://www.pypy.org/</link><description></description><atom:link href="https://www.pypy.org/categories/toy-optimizer.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:pypy-dev@pypy.org"&gt;The PyPy Team&lt;/a&gt; </copyright><lastBuildDate>Wed, 30 Sep 2026 20:34:16 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Load and store forwarding in the Toy Optimizer</title><link>https://www.pypy.org/posts/2025/12/toy-load-store.html</link><dc:creator>Max Bernstein</dc:creator><description>&lt;p&gt;This is a &lt;a href="https://bernsteinbear.com/blog/toy-load-store/" rel="canonical"&gt;cross-post&lt;/a&gt; from Max Bernstein from his blog where he writes
about programming languages, compilers, optimizations, virtual machines.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A long, long time ago (two years!) &lt;a href="https://cfbolz.de/"&gt;CF Bolz-Tereick&lt;/a&gt; and I made a &lt;a href="https://www.youtube.com/watch?v=w-UHg0yOPSE"&gt;video
about load/store forwarding&lt;/a&gt; and an accompanying &lt;a href="https://gist.github.com/tekknolagi/4e3fa26d350f6d3b39ede40d372b97fe"&gt;GitHub Gist&lt;/a&gt;
about load/store forwarding (also called load elimination) in the Toy Optimizer. I
said I would write a blog post about it, but never found the time—it got lost
amid a sea of large life changes.&lt;/p&gt;
&lt;p&gt;It's a neat idea: do an abstract interpretation over the trace, modeling the
heap at compile-time, eliminating redundant loads and stores. That means it's
possible to optimize traces like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;into traces like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(where &lt;code&gt;load(v0, 5)&lt;/code&gt; is equivalent to &lt;code&gt;*(v0+5)&lt;/code&gt; in C syntax and &lt;code&gt;store(v0, 6,
123)&lt;/code&gt; is equvialent to &lt;code&gt;*(v0+6)=123&lt;/code&gt; in C syntax)&lt;/p&gt;
&lt;p&gt;This indicates that we were able to eliminate two redundant loads by keeping
around information about previous loads and stores. Let's get to work making
this possible.&lt;/p&gt;
&lt;h3 id="the-usual-infrastructure"&gt;The usual infrastructure&lt;/h3&gt;
&lt;p&gt;We'll start off with the usual infrastructure from the &lt;a href="https://pypy.org/categories/toy-optimizer.html"&gt;Toy
Optimizer series&lt;/a&gt;: a very stringly-typed representation of a
&lt;a href="https://gist.github.com/tekknolagi/4e3fa26d350f6d3b39ede40d372b97fe#file-port-py-L4-L112"&gt;trace-based SSA IR&lt;/a&gt; and a union-find rewrite mechanism.&lt;/p&gt;
&lt;p&gt;This means we can start writing some new optimization pass and our first test:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO: copy an optimized version of bb into opt_bb&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_two_loads&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = load(var0, 0)&lt;/span&gt;
&lt;span class="s2"&gt;var2 = escape(var1)&lt;/span&gt;
&lt;span class="s2"&gt;var3 = escape(var1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test is asserting that we can remove duplicate loads. Why load twice if we
can cache the result? Let's make that happen.&lt;/p&gt;
&lt;h3 id="caching-loads"&gt;Caching loads&lt;/h3&gt;
&lt;p&gt;To do this, we'll model the the heap at compile-time. When I say "model", I
mean that we will have an imprecise but correct abstract representation of the
heap: we don't (and can't) have knowledge of every value, but we can know for
sure that some addresses have certain values.&lt;/p&gt;
&lt;p&gt;For example, if we have observed a load from object &lt;em&gt;O&lt;/em&gt; at offset &lt;em&gt;8&lt;/em&gt; &lt;code&gt;v0 =
load(O, 8)&lt;/code&gt;, we know that the SSA value &lt;code&gt;v0&lt;/code&gt; is at &lt;code&gt;heap[(O, 8)]&lt;/code&gt;. That sounds
tautological, but it's not. Future loads can make use of this information.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Stores things we know about the heap at... compile-time.&lt;/span&gt;
    &lt;span class="c1"&gt;# Key: an object and an offset pair acting as a heap address&lt;/span&gt;
    &lt;span class="c1"&gt;# Value: a previous SSA value we know exists at that address&lt;/span&gt;
    &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;load_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This pass records information about loads and uses the result of a previous
cached load operation if available. We treat the pair of (SSA value, offset) as
an address into our abstract heap.&lt;/p&gt;
&lt;p&gt;That's great! If you run our simple test, it should now pass. But what happens
if we store into that address before the second load? Oops...&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_store_to_same_object_offset_invalidates_load&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = load(var0, 0)&lt;/span&gt;
&lt;span class="s2"&gt;var2 = store(var0, 0, 5)&lt;/span&gt;
&lt;span class="s2"&gt;var3 = load(var0, 0)&lt;/span&gt;
&lt;span class="s2"&gt;var4 = escape(var1)&lt;/span&gt;
&lt;span class="s2"&gt;var5 = escape(var3)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test fails because we are incorrectly keeping around &lt;code&gt;var1&lt;/code&gt; in our
abstract heap. We need to get rid of it and not replace &lt;code&gt;var3&lt;/code&gt; with &lt;code&gt;var1&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="invalidating-cached-loads"&gt;Invalidating cached loads&lt;/h3&gt;
&lt;p&gt;So it turns out we have to also model stores in order to cache loads correctly.
One valid, albeit aggressive, way to do that is to throw away all the
information we know at each store operation:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# ...&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That makes our test pass—yay!—but at great cost. It means any store
operation mucks up redundant loads. In our world where we frequently read from
and write to objects, this is what we call a huge bummer.&lt;/p&gt;
&lt;p&gt;For example, a store to offset 4 on some object should never interfere with a
load from a different offset on the same object&lt;sup id="fnref:size"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2025/12/toy-load-store.html#fn:size"&gt;1&lt;/a&gt;&lt;/sup&gt;. We should be able to
keep our load from offset 0 cached here:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_store_to_same_object_different_offset_does_not_invalidate_load&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = load(var0, 0)&lt;/span&gt;
&lt;span class="s2"&gt;var2 = store(var0, 4, 5)&lt;/span&gt;
&lt;span class="s2"&gt;var3 = escape(var1)&lt;/span&gt;
&lt;span class="s2"&gt;var4 = escape(var1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We could try instead checking if our specific (object, offset) pair is in the
heap and only removing cached information about that offset and that object.
That would definitely help!&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;load_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;load_info&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# ...&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It makes our test pass, too, which is great news.&lt;/p&gt;
&lt;p&gt;Unfortunately, this runs into problems due to aliasing: it's entirely possible
that our compile-time heap could contain a pair &lt;code&gt;(v0, 0)&lt;/code&gt; and a pair &lt;code&gt;(v1, 0)&lt;/code&gt; where &lt;code&gt;v0&lt;/code&gt;
and &lt;code&gt;v1&lt;/code&gt; are the same object (but not known to the optimizer). Then we might
run into a situation where we incorrectly cache loads because the optimizer
doesn't know our abstract addresses &lt;code&gt;(v0, 0)&lt;/code&gt; and &lt;code&gt;(v1, 0)&lt;/code&gt; are actually the
same pointer at run-time.&lt;/p&gt;
&lt;p&gt;This means that we are breaking abstract interpretation rules: our abstract
interpreter has to correctly model &lt;em&gt;all&lt;/em&gt; possible outcomes at run-time. This
means to me that we should instead pick some tactic in-between clearing all
information (correct but over-eager) and clearing only exact matches of
object+offset (incorrect).&lt;/p&gt;
&lt;p&gt;The term that will help us here is called an &lt;em&gt;alias class&lt;/em&gt;. It is a name for a
way to efficiently partition objects in your abstract heap into completely
disjoint sets. Writes to any object in one class never affect objects in
another class.&lt;/p&gt;
&lt;p&gt;Our very scrappy alias classes will be just based on the offset: each offset is
a different alias class. If we write to any object at offset K, we have to
invalidate all of our compile-time offset K knowledge—even if it's for
another object. This is a nice middle ground, and it's possible because our
(made up) object system guarantees that distinct objects do not overlap, and
also that we are not writing out-of-bounds.&lt;sup id="fnref:tbaa"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2025/12/toy-load-store.html#fn:tbaa"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;So let's remove all of the entries from &lt;code&gt;compile_time_heap&lt;/code&gt; where the offset
matches the offset in the current &lt;code&gt;store&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# ...&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Great! Now our test passes.&lt;/p&gt;
&lt;p&gt;This concludes the load optimization section of the post. We have modeled
enough of loads and stores that we can eliminate redundant loads. Very cool.
But we can go further.&lt;/p&gt;
&lt;h3 id="caching-stores"&gt;Caching stores&lt;/h3&gt;
&lt;p&gt;Stores don't just invalidate information. They also give us new information!
Any time we see an operation of the form &lt;code&gt;v1 = store(v0, 8, 5)&lt;/code&gt; we also learn
that &lt;code&gt;load(v0, 8) == 5&lt;/code&gt;! Until it gets invalidated, anyway.&lt;/p&gt;
&lt;p&gt;For example, in this test, we can eliminate the load from &lt;code&gt;var0&lt;/code&gt; at offset 0:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_load_after_store_removed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = store(var0, 0, 5)&lt;/span&gt;
&lt;span class="s2"&gt;var2 = load(var0, 1)&lt;/span&gt;
&lt;span class="s2"&gt;var3 = escape(5)&lt;/span&gt;
&lt;span class="s2"&gt;var4 = escape(var2)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Making that work is thankfully not very hard; we need only add that new
information to the compile-time heap after removing all the
potentially-aliased info:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;# ... as before ...&lt;/span&gt;
            &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;new_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_value&lt;/span&gt;  &lt;span class="c1"&gt;# NEW!&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# ...&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes the test pass. It makes another test fail, but only
because—oops—we now know more. You can delete the old test because the new
test supersedes it.&lt;/p&gt;
&lt;p&gt;Now, note that we are not removing the store. This is because we have nothing
in our optimizer that keeps track of what might have observed the side-effects
of the store. What if the object got &lt;code&gt;escape&lt;/code&gt;d? Or someone did a load later on?
We would only be able to remove the store (&lt;code&gt;continue&lt;/code&gt;) if we could guarantee it
was not observable.&lt;/p&gt;
&lt;p&gt;In our current framework, this only happens in one case: someone is doing a
store of the exact same value that already exists in our compile-time heap.
That is, either the same constant, or the same SSA value. If we see this, then
we can completely skip the second store instruction.&lt;/p&gt;
&lt;p&gt;Here's a test case for that, where we have gained information from the load
instruction that we can then use to get rid of the store instruction:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_load_then_store&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = load(var0, 0)&lt;/span&gt;
&lt;span class="s2"&gt;var2 = escape(var1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's make it pass. To do that, first we'll make an equality function that
works for both constants and operations. Constants are equal if their values
are equal, and operations are equal if they are the identical (by
address/pointer) operation.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a partial equality: if two operations are not equal under &lt;code&gt;eq_value&lt;/code&gt;,
it doesn't mean that they are different, only that we don't know that they are
the same.&lt;/p&gt;
&lt;p&gt;Then, after that, we need only check if the current value in the compile-time
heap is the same as the value being stored in. If it is, wonderful. No need to
store. &lt;code&gt;continue&lt;/code&gt; and don't append the operation to &lt;code&gt;opt_bb&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;store_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;current_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;new_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# NEW!&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;# ... as before ...&lt;/span&gt;
            &lt;span class="c1"&gt;# ...&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;load_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;load_info&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;compile_time_heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;load_info&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes our load-then-store pass and it also makes other tests pass too,
like eliminating a store after another store!&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_store_after_store&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = store(var0, 0, 5)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately, this only works if the values—constants or SSA values—are
known to be the same. If we store &lt;em&gt;different&lt;/em&gt; values, we can't optimize. In the
live stream, we left this an exercise for the viewer:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xfail&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_exercise_for_the_reader&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_load_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;var1 = store(var0, 0, 7)&lt;/span&gt;
&lt;span class="s2"&gt;var2 = escape(7)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We would only be able to optimize this away if we had some notion of a store
being &lt;em&gt;dead&lt;/em&gt;. In this case, that is a store in which the value is never read
before being overwritten.&lt;/p&gt;
&lt;h3 id="removing-dead-stores"&gt;Removing dead stores&lt;/h3&gt;
&lt;p&gt;TODO, I suppose. I have not gotten this far yet. If I get around to it, I will
come back and update the post.&lt;/p&gt;
&lt;h3 id="in-the-real-world"&gt;In the real world&lt;/h3&gt;
&lt;p&gt;This small optimization pass may seem silly or fiddly—when would we ever see
something like this in a real IR?—but it's pretty useful. Here's the Ruby
code that got me thinking about it again some years later for ZJIT:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;C&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;CRuby has a shape system and ZJIT makes use of it, so we end up optimizing this
code (if it's monomorphic) into a series of shape checks and stores. The HIR
might end up looking something like the mess below, where I've annotated the
shape guards (can be thought of as loads) and stores with asterisks:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="cp"&gt;# ...&lt;/span&gt;
&lt;span class="n"&gt;bb2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v6&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;BasicObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Fixnum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GuardType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v32&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GuardShape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x400000&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoreField&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="mh"&gt;@0x10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v10&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;WriteBarrier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v10&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v35&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CShape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x40008e&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CShape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x40008e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoreField&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_shape_id&lt;/span&gt;&lt;span class="mh"&gt;@0x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v35&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Fixnum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v37&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GuardType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v38&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GuardShape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x40008e&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoreField&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="mh"&gt;@0x18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v16&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;WriteBarrier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v16&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v41&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CShape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x40008f&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CShape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x40008f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoreField&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_shape_id&lt;/span&gt;&lt;span class="mh"&gt;@0x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v41&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Fixnum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v43&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GuardType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v44&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;HeapBasicObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GuardShape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x40008f&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoreField&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="mh"&gt;@0x20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v22&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;WriteBarrier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v22&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;v47&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CShape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x400090&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CShape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x400090&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoreField&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_shape_id&lt;/span&gt;&lt;span class="mh"&gt;@0x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v47&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;CheckInterrupts&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v22&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we had store-load forwarding in ZJIT, we could get rid of the intermediate
shape guards; they would know the shape from the previous &lt;code&gt;StoreField&lt;/code&gt;
instruction. If we had dead store elimination, we could get rid of the
intermediate shape writes; they are never read. (And the repeated type guards
to check if it's a heap object still are just silly and need to get removed
eventually.)&lt;/p&gt;
&lt;p&gt;This is on the roadmap and will make object initialization even faster than it
is right now.&lt;/p&gt;
&lt;h3 id="wrapping-up"&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;Thanks for reading the text version of the video that CF and I made a while
back. Now you know how to do load/store elimination on traces.&lt;/p&gt;
&lt;p&gt;I think this does not need too much extra work to get it going on full CFGs; a
block is pretty much the same as a trace, so you can do a block-local version
without much fuss. If you want to go global, you need dominator information and
gen-kill sets.&lt;/p&gt;
&lt;p&gt;Maybe I will touch on this in a future post...&lt;/p&gt;
&lt;h3 id="thank-you"&gt;Thank you&lt;/h3&gt;
&lt;p&gt;Thank you to CF, who walked me through this live on a stream two years ago!
This blog post wouldn't be possible without you.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:size"&gt;
&lt;p&gt;In this toy optimizer example, we are assuming that all reads and writes
are the same size and different offsets don't overlap at all. This is often
the case for managed runtimes, where object fields are pointer-sized and
all reads/writes are pointed aligned. &lt;a class="footnote-backref" href="https://www.pypy.org/posts/2025/12/toy-load-store.html#fnref:size" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:tbaa"&gt;
&lt;p&gt;We could do better. If we had type information, we could also use that
to make alias classes. Writes to a List will never overlap with writes to a
Map, for example. This requires your compiler to have strict aliasing—if
you can freely cast between types, as in C, then this tactic goes out the
window.&lt;/p&gt;
&lt;p&gt;This is called &lt;a href="https://www.pypy.org/assets/img/tbaa.pdf"&gt;Type-based alias analysis&lt;/a&gt; (PDF). &lt;a class="footnote-backref" href="https://www.pypy.org/posts/2025/12/toy-load-store.html#fnref:tbaa" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>toy-optimizer</category><guid>https://www.pypy.org/posts/2025/12/toy-load-store.html</guid><pubDate>Wed, 24 Dec 2025 23:00:00 GMT</pubDate></item><item><title>Doing the Prospero-Challenge in RPython</title><link>https://www.pypy.org/posts/2025/04/prospero-in-rpython.html</link><dc:creator>CF Bolz-Tereick</dc:creator><description>&lt;p&gt;Recently I had a lot of fun playing with the &lt;a href="https://www.mattkeeter.com/projects/prospero/"&gt;Prospero
Challenge&lt;/a&gt; by &lt;a href="https://www.mattkeeter.com/"&gt;Matt
Keeter&lt;/a&gt;. The challenge is to render a 1024x1024 image of
a quote from The Tempest by Shakespeare. The input is a mathematical formula
with 7866 operations, which is evaluated once per pixel.&lt;/p&gt;
&lt;p&gt;What made the challenge particularly enticing for me personally was the fact
that the formula is basically a trace in
&lt;a href="https://en.wikipedia.org/wiki/Static_single-assignment_form"&gt;SSA-form&lt;/a&gt; – a
linear sequence of operations, where every variable is assigned exactly once.
The challenge is to evaluate the formula as fast as possible. I tried a number
of ideas how to speed up execution and will talk about them in this somewhat
meandering post. Most of it follows Matt's implementation
&lt;a href="https://github.com/mkeeter/fidget"&gt;Fidget&lt;/a&gt; very closely. There are two points
of difference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I tried to add more peephole optimizations, but they didn't end up helping
  much.&lt;/li&gt;
&lt;li&gt;I implemented a "demanded information" optimization that removes a lot of
  operations by only keeping the sign of the result. This optimization ended up
  being useful.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of the prototyping in this post was done in RPython (a statically typable
subset of Python2, that can be compiled to C), but I later rewrote the program
in C to get better performance. All the code &lt;a href="https://github.com/cfbolz/pyfidget/"&gt;can be found on
Github&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="input-program"&gt;Input program&lt;/h3&gt;
&lt;p&gt;The input program is a sequence of operations, like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;_0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.95&lt;/span&gt;
&lt;span class="n"&gt;_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="n"&gt;_2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.13008&lt;/span&gt;
&lt;span class="n"&gt;_3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_2&lt;/span&gt;
&lt;span class="n"&gt;_4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_3&lt;/span&gt;
&lt;span class="n"&gt;_5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.675&lt;/span&gt;
&lt;span class="n"&gt;_6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_3&lt;/span&gt;
&lt;span class="n"&gt;_7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_6&lt;/span&gt;
&lt;span class="n"&gt;_8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_7&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first column is the name of the result variable, the second column is the
operation, and the rest are the arguments to the operation. &lt;code&gt;var-x&lt;/code&gt; is a
special operation that returns the x-coordinate of the pixel being rendered,
and equivalently for &lt;code&gt;var-y&lt;/code&gt; the y-coordinate. The sign of the result gives the
color of the pixel, the absolute value is not important.&lt;/p&gt;
&lt;h3 id="a-baseline-interpreter"&gt;A baseline interpreter&lt;/h3&gt;
&lt;p&gt;To run the program, I first parse them and replace the register names with
indexes, to avoid any dictionary lookups at runtime.
Then I implemented a simple interpreter for the SSA-form
input program. The interpreter is a simple register machine, where every
operation is executed in order. The result of the operation is stored into a
list of results, and the next operation is executed. This was the slow baseline
implementation of the interpreter but it's very useful to compare against the optimized
versions.&lt;/p&gt;
&lt;p&gt;This is roughly what the code looks like&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DirectFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run_floats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setxyz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setxyz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;
        &lt;span class="n"&gt;num_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;floatvalues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;num_ops&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_ops&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_func_and_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;consts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;farg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;farg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;farg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;farg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;farg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;farg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;farg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;farg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num_ops&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Running the naive interpreter on the prospero image file is super slow, since
it performs 7866 * 1024 * 1024 float operations, plus the interpretation overhead.&lt;/p&gt;
&lt;h3 id="using-quadtrees-to-render-the-picture"&gt;Using Quadtrees to render the picture&lt;/h3&gt;
&lt;p&gt;The approach that Matt describes in his really excellent
&lt;a href="https://www.youtube.com/watch?v=UxGxsGnbyJ4"&gt;talk&lt;/a&gt; is to use
&lt;a href="https://en.wikipedia.org/wiki/Quadtree"&gt;quadtrees&lt;/a&gt;: recursively subdivide the
image into quadrants, and evaluate the formula in each quadrant. For every
quadrant you can simplify the formula by doing a range analysis. After a few
recursion steps, the formula becomes significantly smaller, often only a few
hundred or a few dozen operations.&lt;/p&gt;
&lt;p&gt;At the bottom of the recursion you either reach a square where the range
analysis reveals that the sign for all pixels is determined, then you can fill
in all the pixels of the quadrant. Or you can evaluate the (now much simpler)
formula in the quadrant by executing it for every pixel.&lt;/p&gt;
&lt;p&gt;This is an interesting use case of JIT compiler/optimization techniques,
requiring the optimizer itself to execute really quickly since it is an essential
part of the performance of the algorithm. The optimizer runs literally hundreds
of times to render a single image. If the algorithm is used for 3D models
it becomes even more crucial.&lt;/p&gt;
&lt;h3 id="writing-a-simple-optimizer"&gt;Writing a simple optimizer&lt;/h3&gt;
&lt;p&gt;Implementing the quadtree recursion is straightforward. Since the program has
no control flow the optimizer is very simple to write. I've written a couple of
blog posts on how to easily write optimizers for linear sequences of
operations, and I'm using the approach described in these &lt;a href="https://pypy.org/categories/toy-optimizer.html"&gt;Toy
Optimizer&lt;/a&gt; posts. The interval
analysis is basically an &lt;a href="https://pypy.org/posts/2024/08/toy-knownbits.html"&gt;abstract
interpretation&lt;/a&gt; of the
operations. The optimizer does a sequential forward pass over the input
program. For every operation, the output interval is computed. The optimizer
also performs optimizations based on the computed intervals, which helps in
reducing the number of operations executed (I'll talk about this further down).&lt;/p&gt;
&lt;p&gt;Here's a sketch of the Python code that does the optimization:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Optimizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;
        &lt;span class="n"&gt;num_operations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ProgramBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_operations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IntervalFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# old index -&amp;gt; new index&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opreplacements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;num_operations&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_replacement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opreplacements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;newop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;newconst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="c1"&gt;#self.seen_consts[value] = const&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setxyz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;numops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numops&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;newop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_optimize_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opreplacements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newop&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opreplacements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;numops&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_optimize_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;
        &lt;span class="n"&gt;intervalframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;
        &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_func_and_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minx&lt;/span&gt;
            &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxx&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;miny&lt;/span&gt;
            &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxy&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minz&lt;/span&gt;
            &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxz&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;consts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newconst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_replacement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_replacement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;arg0minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;arg0maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;arg1minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;arg1maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newop&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opt_neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# peephole rules go here, see below&lt;/span&gt;
        &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@symmetric&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opt_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1maximum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# peephole rules go here, see below&lt;/span&gt;
        &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The resulting optimized traces are then simply interpreted at the bottom of the
quadtree recursion. Matt talks about also generating machine code from them,
but when I tried to use PyPy's JIT for that it was way too slow at
producing machine code.&lt;/p&gt;
&lt;h3 id="testing-soundness-of-the-interval-abstract-domain"&gt;Testing soundness of the interval abstract domain&lt;/h3&gt;
&lt;p&gt;To make sure that my interval computation in the optimizer is correct, I
implemented a hypothesis-based property based test. It checks the abstract
transfer functions of the interval domain for soundness. It does so by
generating random concrete input values for an operation and random intervals that
surround the random concrete values, then performs the concrete operation to
get the concrete output, and finally checks that the abstract transfer function applied
to the input intervals gives an interval that contains the concrete output.&lt;/p&gt;
&lt;p&gt;For example, the random test for the &lt;code&gt;square&lt;/code&gt; operation would look like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;hypothesis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;assume&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pyfidget.vm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;IntervalFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DirectFrame&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;math&lt;/span&gt;

&lt;span class="n"&gt;regular_floats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allow_nan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allow_infinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;make_range_and_contained_float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

&lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DirectFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;intervalframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IntervalFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;range_and_contained_float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;builds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;make_range_and_contained_float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_floats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_floats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_floats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rmax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isnan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isnan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rmax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rmin&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;rmax&lt;/span&gt;


&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;range_and_contained_float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
    &lt;span class="n"&gt;rmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rmax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rmax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test generates a random float &lt;code&gt;b&lt;/code&gt;, and two other floats &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; such
that the interval &lt;code&gt;[a, c]&lt;/code&gt; contains &lt;code&gt;b&lt;/code&gt;. The test then checks that the result
of the &lt;code&gt;square&lt;/code&gt; operation on &lt;code&gt;b&lt;/code&gt; is contained in the interval &lt;code&gt;[rmin, rmax]&lt;/code&gt;
returned by the abstract transfer function for the &lt;code&gt;square&lt;/code&gt; operation.&lt;/p&gt;
&lt;h3 id="peephole-rewrites"&gt;Peephole rewrites&lt;/h3&gt;
&lt;p&gt;The only optimization that Matt does in his implementation is a peephole
optimization rule that removes &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; operations where the intervals
of the arguments don't overlap. In that case, the optimizer statically can know
which of the arguments will be the result of the operation. I implemented this
peephole optimization in my implementation as well, but I also added a few more
peephole optimizations that I thought would be useful.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Optimizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opt_neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# new: add peephole rule --x =&amp;gt; x&lt;/span&gt;
        &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_func_and_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg0arg0&lt;/span&gt;
        &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_neg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@symmetric&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opt_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1maximum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Matt's peephole rule&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arg1minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="c1"&gt;# we can use the intervals to decide which argument will be returned&lt;/span&gt;
        &lt;span class="c1"&gt;# new one by me: min(x, x) =&amp;gt; x &lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;
        &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_func_and_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalframe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1maximum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, it turns out that all my attempts at adding other peephole
optimization rules were not very useful. Most rules never fired, and the ones
that did only had a small effect on the performance of the program. The only
peephole optimization that I found to be useful was the one that Matt describes
in his talk. Matt's &lt;code&gt;min&lt;/code&gt;/&lt;code&gt;max&lt;/code&gt; optimization were 96% of all rewrites that my
peephole optimizer applied for the &lt;code&gt;prospero.vm&lt;/code&gt; input. The remaining 4% of
rewrites were (the percentages are of that 4%):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;--x =&amp;gt; x                          4.65%
(-x)**2 =&amp;gt; x ** 2                 0.99%
min(x, x) =&amp;gt; x                   20.86%
min(x, min(x, y)) =&amp;gt;  min(x, y)  52.87%
max(x, x) =&amp;gt; x                   16.40%
max(x, max(x, y)) =&amp;gt; max(x, y)    4.23%
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the end it turned out that having these extra optimization rules made the
total runtime of the system go up. Checking for the rewrites isn't free, and
since they apply so rarely they don't pay for their own cost in terms of
improved performance.&lt;/p&gt;
&lt;p&gt;There are some further rules that I tried that never fired at all:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;a &lt;span class="gs"&gt;* 0 =&amp;gt; 0&lt;/span&gt;
&lt;span class="gs"&gt;a *&lt;/span&gt; 1 =&amp;gt; a
a &lt;span class="gs"&gt;* a =&amp;gt; a *&lt;/span&gt;* 2
a &lt;span class="gs"&gt;* -1 =&amp;gt; -a&lt;/span&gt;
&lt;span class="gs"&gt;a + 0 =&amp;gt; a&lt;/span&gt;
&lt;span class="gs"&gt;a - 0 =&amp;gt; a&lt;/span&gt;
&lt;span class="gs"&gt;x - x =&amp;gt; 0&lt;/span&gt;
&lt;span class="gs"&gt;abs(known positive number x) =&amp;gt; x&lt;/span&gt;
&lt;span class="gs"&gt;abs(known negative number x) =&amp;gt; -x&lt;/span&gt;
&lt;span class="gs"&gt;abs(-x) =&amp;gt; abs(x)&lt;/span&gt;
&lt;span class="gs"&gt;(-x) *&lt;/span&gt;* 2 =&amp;gt; x ** 2
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This investigation is clearly way too focused on a single program and should be
re-done with a larger set of example inputs, if this were an actually serious
implementation.&lt;/p&gt;
&lt;h3 id="demanded-information-optimization"&gt;Demanded Information Optimization&lt;/h3&gt;
&lt;p&gt;LLVM has an static analysis pass called 'demanded bits'. It is a backwards analysis that
allows you to determine which bits of a value are actually used in the final
result. This information can then be used in peephole optimizations. For
example, if you have an expression that computes a value, but only the last
byte of that value is used in the final result, you can optimize the expression
to only compute the last byte.&lt;/p&gt;
&lt;p&gt;Here's an example. Let's say we first byte-swap a 64-bit int, and then mask off the last byte:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;byteswap_then_mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byteswap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, the "demanded bits" of the &lt;code&gt;byteswap(a)&lt;/code&gt; expression are
&lt;code&gt;0b0...011111111&lt;/code&gt;, which inversely means that we don't care about the upper 56
bits. Therefore the whole expression can be optimized to &lt;code&gt;a &amp;gt;&amp;gt; 56&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the Prospero challenge, we can observe that for the resulting pixel values, the value of
the result is not used at all, only its sign. Essentially, every program ends
implicitly with a &lt;code&gt;sign&lt;/code&gt; operation that returns &lt;code&gt;0.0&lt;/code&gt; for negative values and
&lt;code&gt;1.0&lt;/code&gt; for positive values. For clarity, I will show this &lt;code&gt;sign&lt;/code&gt; operation in
the rest of the section, even if it's not actually in the real code.&lt;/p&gt;
&lt;p&gt;This makes it possible to simplify certain min/max
operations further. Here is an example of a program, together with the
intervals of the variables:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# [0.1, 1]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# [-1, 1]&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# [-1, 1]&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This program can be optimized to:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because that expression has the same result as the original expression: if &lt;code&gt;x &amp;gt;
0.1&lt;/code&gt;, for the result of &lt;code&gt;min(x, y)&lt;/code&gt; to be negative then &lt;code&gt;y&lt;/code&gt; needs to be negative.&lt;/p&gt;
&lt;p&gt;Another, more complex, example is this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# [1, 100]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# [-10, 10]&lt;/span&gt;
&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# [-100, 100]&lt;/span&gt;
&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# [-10, 10]&lt;/span&gt;
&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# [-10, 100]&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which can be optimized to this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;
&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is because the sign of &lt;code&gt;min(x, y)&lt;/code&gt; is the same as the sign of &lt;code&gt;y&lt;/code&gt; if &lt;code&gt;x &amp;gt;
0&lt;/code&gt;, and the sign of &lt;code&gt;max(z, min(x, y))&lt;/code&gt; is thus the same as the sign of &lt;code&gt;max(z,
y)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To implement this optimization, I do a backwards pass over the program after
the peephole optimization forward pass. For every &lt;code&gt;min&lt;/code&gt; call I encounter, where
one of the arguments is positive, I can optimize the &lt;code&gt;min&lt;/code&gt; call away and
replace it with the other argument. For &lt;code&gt;max&lt;/code&gt; calls I simplify their arguments
recursively.&lt;/p&gt;
&lt;p&gt;The code looks roughly like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;work_backwards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minvalues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxvalues&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_func_and_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;narg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;narg0&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;narg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;narg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;narg1&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;narg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;minvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;minvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;narg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;narg0&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;narg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;narg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;narg1&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;resultops&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;narg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;demand_sign_simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In my experiment, this optimization lets me remove 25% of all operations in
prospero, at the various levels of my octree. I'll briefly look at performance
results further down.&lt;/p&gt;
&lt;h3 id="further-ideas-about-the-demanded-sign-simplification"&gt;Further ideas about the demanded sign simplification&lt;/h3&gt;
&lt;p&gt;There is another idea how to short-circuit the evaluation of expressions that I
tried briefly but didn't pursue to the end. Let's go back to the first example
of the previous subsection, but with different intervals:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# [-1, 1]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# [-1, 1]&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# [-1, 1]&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can't use the "demanded sign" trick in the optimizer, because neither
&lt;code&gt;x&lt;/code&gt; nor &lt;code&gt;y&lt;/code&gt; are known positive. However, during &lt;em&gt;execution&lt;/em&gt; of the program, if
&lt;code&gt;x&lt;/code&gt; turns out to be negative we can end the execution of this trace
immediately, since we know that the result must be negative.&lt;/p&gt;
&lt;p&gt;So I experimented with adding &lt;code&gt;return_early_if_neg&lt;/code&gt; flags to all operations
with this property. The interpreter then checks whether the flag is set on an
operation and if the result is negative, it stops the execution of the program
early:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;return_early_if_neg&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;return_early_if_neg&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="k"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This looked pretty promising, but it's also a trade-off because the cost of
checking the flag and the value isn't zero. Here's a sketch to the change in the interpreter:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DirectFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;
        &lt;span class="n"&gt;num_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;floatvalues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;num_ops&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_ops&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="o"&gt;...&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;var_x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
            &lt;span class="o"&gt;...&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should_return_if_neg&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
            &lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;floatvalues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num_ops&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I implemented this in the RPython
version, but didn't end up porting it to C, because it interferes with SIMD.&lt;/p&gt;
&lt;h3 id="dead-code-elimination"&gt;Dead code elimination&lt;/h3&gt;
&lt;p&gt;Matt performs dead code elimination in his implementation by doing a single
backwards pass over the program. This is a very simple and effective
optimization, and I implemented it in my implementation as well. The dead code
elimination pass is very simple: It starts by marking the result operation as
used. Then it goes backwards over the program. If the current operation is
used, its arguments are marked as used as well. Afterwards, all the operations
that are not marked as used are removed from the program. The PyPy JIT actually
performs dead code elimination on traces in exactly the same way (and I don't
think we ever explained how this works on the blog), so I thought it was worth
mentioning.&lt;/p&gt;
&lt;p&gt;Matt also performs register allocation as part of the backwards pass, but I
didn't implement it because I wasn't too interested in that aspect.&lt;/p&gt;
&lt;h3 id="random-testing-of-the-optimizer"&gt;Random testing of the optimizer&lt;/h3&gt;
&lt;p&gt;To make sure I didn't break anything in the optimizer, I implemented a
test that generates random input programs and checks that the output of the
optimizer is equivalent to the input program. The test generates random
operations, random intervals for the operations and a random input value within
that interval. It then runs the optimizer on the input program and checks that
the output program has the same result as the input program. This is again
implemented with &lt;code&gt;hypothesis&lt;/code&gt;. Hypothesis' test case minimization feature is
super useful for finding optimizer bugs. It's just not fun to analyze a problem
on a many-thousand-operation input file, but Hypothesis often generated reduced
test cases that were only a few operations long.&lt;/p&gt;
&lt;h3 id="visualizing-programs"&gt;Visualizing programs&lt;/h3&gt;
&lt;p&gt;It's actually surprisingly annoying to visualize &lt;code&gt;prospero.vm&lt;/code&gt; well, because
it's quite a bit too large to just feed it into Graphviz. I made the problem
slightly easier by grouping several operations together, where only the first
operation in a group is used as the argument for more than one operation
further in the program. This made it slightly more manageable for Graphviz. But
it still wasn't a big enough improvement to be able to visualize all of
&lt;code&gt;prospero.vm&lt;/code&gt; in its unoptimized form at the top of the octree.&lt;/p&gt;
&lt;p&gt;Here's a visualization of the optimized &lt;code&gt;prospero.vm&lt;/code&gt; at one of the octree
levels:&lt;/p&gt;
&lt;p&gt;&lt;img alt="graph visualization of a part of the input program" src="https://www.pypy.org/images/2025-image-prospero-dataflow.png"&gt;&lt;/p&gt;
&lt;p&gt;The result is on top, every node points to its arguments. The &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;
operations form a kind of "spine" of the expression tree, because they are
unions and intersection in the constructive solid geometry sense.&lt;/p&gt;
&lt;p&gt;I also wrote a function to visualize the octree recursion itself, the output
looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="graph visualization of the octree recursion, zoomed out" src="https://www.pypy.org/images/2025-image-octree-zoomed-out.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="graph visualization of the octree recursion, zoomed in" src="https://www.pypy.org/images/2025-image-octree-zoomed-in.png"&gt;&lt;/p&gt;
&lt;p&gt;Green nodes are where the interval analysis determined that the output must be
entirely outside the shape. Yellow nodes are where the octree recursion
bottomed out.&lt;/p&gt;
&lt;h3 id="c-implementation"&gt;C implementation&lt;/h3&gt;
&lt;p&gt;To achieve even faster performance, I decided to rewrite the implementation in
C. While RPython is great for prototyping, it can be challenging to control
low-level aspects of the code. The rewrite in C allowed me to experiment with
several techniques I had been curious about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.reverberate.org/2021/04/21/musttail-efficient-interpreters.html"&gt;&lt;code&gt;musttail&lt;/code&gt; optimization&lt;/a&gt; for the interpreter.&lt;/li&gt;
&lt;li&gt;SIMD (Single Instruction, Multiple Data): Using Clang's
  &lt;a href="https://clang.llvm.org/docs/LanguageExtensions.html#vectors-and-extended-vectors"&gt;&lt;code&gt;ext_vector_type&lt;/code&gt;&lt;/a&gt;, I process eight pixels at once using AVX (or some other
  SIMD magic that I don't properly understand).&lt;/li&gt;
&lt;li&gt;Efficient struct packing: I packed the operations struct into just 8
  bytes by limiting the maximum number of operations to 65,536, with the idea
  of making the optimizer faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn't rigorously study the performance impact of each of these techniques
individually, so it's possible that some of them might not have contributed
significantly. However, the rewrite was a fun exercise for me to explore these
techniques. The code can be found
&lt;a href="https://github.com/cfbolz/pyfidget/blob/main/pyfidget/experiments.c"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="testing-the-c-implementation"&gt;Testing the C implementation&lt;/h3&gt;
&lt;p&gt;At various points I had bugs in the C implementation, leading to a fun glitchy
version of prospero:&lt;/p&gt;
&lt;p&gt;&lt;img alt="glitchy prospero" src="https://www.pypy.org/images/2025-glitchy-prospero.png"&gt;&lt;/p&gt;
&lt;p&gt;To find these bugs, I used the same random testing approach as in the
RPython version. I generated random input programs as strings in Python and
checked that the output of the C implementation was equivalent to the output of
the RPython implementation (simply by calling out to the shell and reading the
generated image, then comparing pixels). This helped ensure that the C
implementation was
correct and didn't introduce any bugs. It was surprisingly tricky to get this
right, for reasons that I didn't expect. At lot of them are related to the fact
that in C I used &lt;code&gt;float&lt;/code&gt; and Python uses &lt;code&gt;double&lt;/code&gt; for its (Python) &lt;code&gt;float&lt;/code&gt;
type. This made the random tester find weird floating point corner cases where
rounding behaviour between the widths was different.&lt;/p&gt;
&lt;p&gt;I solved those by using &lt;code&gt;double&lt;/code&gt; in C when running the random tests by means of
an &lt;code&gt;IFDEF&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It's super fun to watch the random program generator produce random images, here are a few:&lt;/p&gt;
&lt;iframe width="560" height="560" src="https://www.youtube.com/embed/VqU5n3zzOjc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3 id="performance"&gt;Performance&lt;/h3&gt;
&lt;p&gt;Some very rough performance results on my laptop (an AMD Ryzen 7 PRO 7840U with
32 GiB RAM running Ubuntu 24.04), comparing the RPython version, the C version
(with and without demanded info), and Fidget (in &lt;code&gt;vm&lt;/code&gt; mode, its JIT made things
worse for me), both for 1024x1024 and 4096x4096 images:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;1024x1024&lt;/th&gt;
&lt;th&gt;4096x4096&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RPython&lt;/td&gt;
&lt;td&gt;26.8ms&lt;/td&gt;
&lt;td&gt;75.0ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C (no demanded info)&lt;/td&gt;
&lt;td&gt;24.5ms&lt;/td&gt;
&lt;td&gt;45.0ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C (demanded info)&lt;/td&gt;
&lt;td&gt;18.0ms&lt;/td&gt;
&lt;td&gt;37.0ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fidget&lt;/td&gt;
&lt;td&gt;10.8ms&lt;/td&gt;
&lt;td&gt;57.8ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The demanded info seem to help quite a bit, which was nice to see.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;That's it! I had lots of fun with the challenge and have a whole bunch of other
ideas I want to try out, thanks Matt for this interesting puzzle.&lt;/p&gt;</description><category>toy-optimizer</category><guid>https://www.pypy.org/posts/2025/04/prospero-in-rpython.html</guid><pubDate>Wed, 09 Apr 2025 15:07:09 GMT</pubDate></item><item><title>A Knownbits Abstract Domain for the Toy Optimizer, Correctly</title><link>https://www.pypy.org/posts/2024/08/toy-knownbits.html</link><dc:creator>CF Bolz-Tereick</dc:creator><description>&lt;p&gt;After &lt;a href="https://bernsteinbear.com/blog/toy-abstract-interpretation/"&gt;Max' introduction to abstract interpretation for the toy optimizer&lt;/a&gt; in the
last post, I want to present a more complicated abstract domain in this post.
This abstract domain reasons about the individual bits of a variable in a trace.
Every bit can be either "known zero", "known one" or "unknown". The abstract
domain is useful for optimizing integer operations, particularly the bitwise operations.
The abstract domain follows quite closely the &lt;a href="https://github.com/torvalds/linux/blob/master/kernel/bpf/tnum.c"&gt;tristate abstract domain of the
eBPF verifier in the Linux
Kernel&lt;/a&gt;, as
described by the paper
&lt;a href="https://arxiv.org/abs/2105.05398"&gt;Sound, Precise, and Fast Abstract Interpretation with Tristate
Numbers&lt;/a&gt; by Harishankar Vishwanathan, Matan
Shachnai, Srinivas Narayana, and Santosh Nagarakatte.&lt;/p&gt;
&lt;p&gt;The presentation in this post will still be in the context of the
&lt;a href="https://www.pypy.org/categories/toy-optimizer"&gt;toy optimizer&lt;/a&gt;. We'll spend a significant part of
the post convincing ourselves that the abstract domain transfer functions that
we're writing are really correct, using both property-based testing and
automated proofs (again using Z3).&lt;/p&gt;
&lt;p&gt;PyPy has implemented and merged a more complicated version of the same abstract
domain for the "real" PyPy JIT. A more thorough explanation of that real world
implementation will follow.&lt;/p&gt;
&lt;p&gt;I'd like to thank Max Bernstein and Armin Rigo for lots of great feedback on
drafts of this post. The PyPy implementation was mainly done by Nico
Rittinghaus and me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Contents:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#motivation"&gt;Motivation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#the-knownbits-abstract-domain"&gt;The Knownbits Abstract Domain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#transfer-functions"&gt;Transfer Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#property-based-tests-with-hypothesis"&gt;Property-based Tests with Hypothesis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#when-are-transfer-functions-correct-how-do-we-test-them"&gt;When are Transfer Functions Correct? How do we test them?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#implementing-binary-transfer-functions"&gt;Implementing Binary Transfer Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#addition-and-subtraction"&gt;Addition and Subtraction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#proving-correctness-of-the-transfer-functions-with-z3"&gt;Proving correctness of the transfer functions with Z3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#cases-where-this-style-of-z3-proof-doesnt-work"&gt;Cases where this style of Z3 proof doesn't work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#making-statements-about-precision"&gt;Making Statements about Precision&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#using-the-abstract-domain-in-the-toy-optimizer-for-generalized-constant-folding"&gt;Using the Abstract Domain in the Toy Optimizer for Generalized Constant Folding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#using-the-knownbits-domain-for-conditional-peephole-rewrites"&gt;Using the KnownBits Domain for Conditional Peephole Rewrites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3 id="motivation"&gt;Motivation&lt;/h3&gt;
&lt;p&gt;In many programs that do bit-manipulation of integers, some of the bits of the
integer variables of the program can be statically known. Here's a simple
example:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
...
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;...
&lt;span class="k"&gt;else&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;...
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After the assignment &lt;code&gt;x = a | 1&lt;/code&gt;, we know that the lowest bit of &lt;code&gt;x&lt;/code&gt; must be &lt;code&gt;1&lt;/code&gt;
(the other bits are unknown) and an optimizer could remove the condition &lt;code&gt;x &amp;amp; 1&lt;/code&gt; by
constant-folding it to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another (more complicated) example is:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;assert i &amp;amp; 0b111 == 0 # check that i is a multiple of 8
j = i + 16
assert j &amp;amp; 0b111 == 0
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This kind of code could e.g. happen in a &lt;a href="https://docs.pydrofoil.org/en/latest/"&gt;CPU
emulator&lt;/a&gt;, where &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; are
integers that represent emulated pointers, and the &lt;code&gt;assert&lt;/code&gt;s are alignment
checks. The first assert implies that the lowest three bits of i must be &lt;code&gt;0&lt;/code&gt;.
Adding 16 to such a number produces a result where the lowest three bits are
again all &lt;code&gt;0&lt;/code&gt;, therefore the second assert is always true. So we would like a
compiler to remove the second assert.&lt;/p&gt;
&lt;p&gt;Both of these will optimizations are doable with the help of the knownbits
abstract domain that we'll discuss in the rest of the post.&lt;/p&gt;
&lt;h3 id="the-knownbits-abstract-domain"&gt;The Knownbits Abstract Domain&lt;/h3&gt;
&lt;p&gt;An abstract value of the knownbits domain needs to be able to store, for every
bit of an integer variable in a program, whether it is known 0, known 1, or
unknown. To represent
three different states, we need 2 bits, which we will call &lt;code&gt;one&lt;/code&gt; and &lt;code&gt;unknown&lt;/code&gt;.
Here's the encoding:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;one&lt;/th&gt;
&lt;th&gt;unknown&lt;/th&gt;
&lt;th style="text-align: right;"&gt;knownbit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td style="text-align: right;"&gt;?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td style="text-align: right;"&gt;illegal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;unknown&lt;/code&gt; bit is set if we don't know the value of the bit ("?"), the &lt;code&gt;one&lt;/code&gt;
bit is set if the bit is known to be a &lt;code&gt;1&lt;/code&gt;. Since two bits are enough to encode
four different states, but we only need three, the combination of a set &lt;code&gt;one&lt;/code&gt;
bit and a set &lt;code&gt;unknown&lt;/code&gt; is not allowed.&lt;/p&gt;
&lt;p&gt;We don't just want to encode a single bit, however. Instead, we want to do this
for all the bits of an integer variable. Therefore the instances of the abstract
domain get two integer fields &lt;code&gt;ones&lt;/code&gt; and &lt;code&gt;unknowns&lt;/code&gt;, where each pair of
corresponding bits encodes the knowledge about the corresponding bit of the
integer variable in the program.&lt;/p&gt;
&lt;p&gt;We can start implementing a Python class that works like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dataclasses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;__post_init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_well_formed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;is_well_formed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# a bit cannot be both 1 and unknown&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" Construct a KnownBits corresponding to a constant, where all bits&lt;/span&gt;
&lt;span class="sd"&gt;        are known."""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" Check if the KnownBits instance represents a constant. """&lt;/span&gt;
        &lt;span class="c1"&gt;# it's a constant if there are no unknowns&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also add some convenience properties. Sometimes it is easier to work
with an integer where all the &lt;em&gt;known&lt;/em&gt; bits are set, or one where the positions
of all the known zeros have a set bit:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;knowns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" return an integer where the known bits are set. """&lt;/span&gt;
        &lt;span class="c1"&gt;# the knowns are just the unknowns, inverted&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" return an integer where the places that are known zeros have a bit&lt;/span&gt;
&lt;span class="sd"&gt;        set. """&lt;/span&gt;
        &lt;span class="c1"&gt;# it's a 0 if it is known, but not 1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also, for debugging and for writing tests we want a way to print the known bits
in a human-readable form, and also to have a way to construct a &lt;code&gt;KnownBits&lt;/code&gt;
instance from a string. It's not important to understand the details of
&lt;code&gt;__str__&lt;/code&gt; or &lt;code&gt;from_str&lt;/code&gt; for the rest of the post, so I'm putting them into a fold:&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;code&gt;KnownBits&lt;/code&gt; from and to string conversions&lt;/summary&gt;


&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"KnownBits.from_constant(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"KnownBits(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
        &lt;span class="c1"&gt;# construct the string representation right to left&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="c1"&gt;# we leave off the leading known 0s&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# -1 has all bits set in two's complement, so the leading&lt;/span&gt;
                &lt;span class="c1"&gt;# bits are all 1&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# -1 has all bits set in two's complement, so the leading bits&lt;/span&gt;
                &lt;span class="c1"&gt;# are all ?&lt;/span&gt;
                &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" Construct a KnownBits instance that from a string. String can start&lt;/span&gt;
&lt;span class="sd"&gt;        with ...1 to mean that all higher bits are 1, or ...? to mean that all&lt;/span&gt;
&lt;span class="sd"&gt;        higher bits are unknown. Otherwise it is assumed that the higher bits&lt;/span&gt;
&lt;span class="sd"&gt;        are all 0. """&lt;/span&gt;
        &lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;startindex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"...?"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;startindex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"...1"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;startindex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startindex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'?'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;all_unknown&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" convenience constructor for the "all bits unknown" abstract value&lt;/span&gt;
&lt;span class="sd"&gt;        """&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"...?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;



&lt;/details&gt;

&lt;p&gt;And here's a &lt;a href="https://pytest.org"&gt;pytest&lt;/a&gt;-style unit test for &lt;code&gt;str&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_str&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'101'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mb"&gt;0b10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'1?1'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mb"&gt;0b1111&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mb"&gt;0b10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'...100?0'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mb"&gt;0b1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'...?1'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An instance of &lt;code&gt;KnownBits&lt;/code&gt; represents a set of integers, namely those that match
the known bits stored in the instance. We can write a method &lt;code&gt;contains&lt;/code&gt; that
takes a concrete &lt;code&gt;int&lt;/code&gt; value and returns &lt;code&gt;True&lt;/code&gt; if the value matches the
pattern of the known bits:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" Check whether the KnownBits instance contains the concrete integer&lt;/span&gt;
&lt;span class="sd"&gt;        `value`. """&lt;/span&gt;
        &lt;span class="c1"&gt;# check whether value matches the bit pattern. in the places where we&lt;/span&gt;
        &lt;span class="c1"&gt;# know the bits, the value must agree with ones.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and a test:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_contains&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1?1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mb"&gt;0b111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mb"&gt;0b101&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mb"&gt;0b110&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mb"&gt;0b011&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'...?1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# all odd numbers&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="transfer-functions"&gt;Transfer Functions&lt;/h3&gt;
&lt;p&gt;Now that we have implemented the basics of the &lt;code&gt;KnownBits&lt;/code&gt; class, we need to
start implementing the transfer functions. They are for computing what we know
about the &lt;em&gt;results&lt;/em&gt; of an operation, given the knowledge we have about the bits
of the arguments.&lt;/p&gt;
&lt;p&gt;We'll start with a simple unary operation, &lt;code&gt;invert(x)&lt;/code&gt; (which is &lt;code&gt;~x&lt;/code&gt; in Python
and C syntax), which flips all the bits of at integer. If we know some bits of
the arguments, we can compute the corresponding bits of the result. The unknown
bits remain unknown.&lt;/p&gt;
&lt;p&gt;Here's the code:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# self.zeros has bits set where the known 0s are in self&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And a unit-test:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_invert&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'01?01?01?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'...10?10?10?'&lt;/span&gt;

    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'...?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'...?'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Before we continue with further transfer functions, we'll think about
correctness of the transfer functions and build up some test infrastructure. To
test transfer functions, it's quite important to move being simple example-style
unit tests. The state-space for more complicated binary transfer functions is
extremely large and it's too easy to do something wrong in a corner case.
Therefore we'll look at property-based-test for &lt;code&gt;KnownBits&lt;/code&gt; next.&lt;/p&gt;
&lt;h3 id="property-based-tests-with-hypothesis"&gt;Property-based Tests with Hypothesis&lt;/h3&gt;
&lt;p&gt;We want to do property-based tests of &lt;code&gt;KnownBits&lt;/code&gt;, to try
make it less likely that we'll get a corner-case in the implementation wrong.
We'll use &lt;a href="https://hypothesis.readthedocs.io/en/latest/"&gt;Hypothesis&lt;/a&gt; for that.&lt;/p&gt;
&lt;p&gt;I can't give a decent introduction to Hypothesis here, but want to give a few
hints about the API. Hypothesis is a way to run unit tests with randomly
generated input. It provides &lt;em&gt;strategies&lt;/em&gt; to describe the data that the test
functions expects. Hypothesis provides primitive strategies (for things like
integers, strings, floats, etc) and ways to build composite strategies out of
the primitive ones.&lt;/p&gt;
&lt;p&gt;To be able to write the tests, we need to generate random &lt;code&gt;KnownBits&lt;/code&gt; instances,
and we also want an &lt;code&gt;int&lt;/code&gt; instance that is a member of the &lt;code&gt;KnownBits&lt;/code&gt; instance.
We generate tuples of &lt;code&gt;(KnownBits, int)&lt;/code&gt; together, to ensure this property.
We'll ask Hypothesis to generate us a random concrete &lt;code&gt;int&lt;/code&gt; as the concrete
value, and then we'll also generate a second random &lt;code&gt;int&lt;/code&gt; to use as the
&lt;code&gt;unknown&lt;/code&gt; masks (i.e. which bits of the concrete int we don't know in the
&lt;code&gt;KnownBits&lt;/code&gt; instance). Here's a function that takes two such ints and builds the
tuple:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;build_knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concrete_value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# to construct a valid KnownBits instance, we need to mask off the unknown&lt;/span&gt;
    &lt;span class="c1"&gt;# bits&lt;/span&gt;
    &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;concrete_value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;concrete_value&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can turn this function into a hypothesis strategy to generate input data
using the &lt;code&gt;strategies.builds&lt;/code&gt; function:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;hypothesis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;

&lt;span class="n"&gt;ints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;random_knownbits_and_contained_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;builds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;build_knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One important special case of &lt;code&gt;KnownBits&lt;/code&gt; are the constants, which contain only
a single concrete value. We'll also generate some of those specifically, and
then combine the &lt;code&gt;random_knownbits_and_contained_number&lt;/code&gt; strategy with it:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;constant_knownbits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;builds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;ints&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constant_knownbits&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;random_knownbits_and_contained_number&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can write the first property-based tests, for the &lt;code&gt;KnownBits.contains&lt;/code&gt;
method:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;@given&lt;/code&gt; decorator is used to tell Hypothesis which strategy to use to
generate random data for the test function. Hypothesis will run the test with a
number of random examples (100 by default). If it finds an error, it will try to
minimize the example needed that demonstrates the problem, to try to make it
easier to understand what is going wrong. It also saves all failing cases into
an example database and tries them again on subsequent runs.&lt;/p&gt;
&lt;p&gt;This test is as much a check for whether we got the strategies right as it is
for the logic in &lt;code&gt;KnownBits.contains&lt;/code&gt;. Here's an example output of random
concrete and abstract values that we are getting here:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="mf"&gt;110000011001101&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;???&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;
&lt;span class="mf"&gt;...1011011&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...1011011&lt;/span&gt;
&lt;span class="mf"&gt;...1001101110101000010010011111011&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...1001101110101000010010011111011&lt;/span&gt;
&lt;span class="mf"&gt;...1001101110101000010010011111011&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...100110111010100001&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;010&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;
&lt;span class="mf"&gt;1000001101111101001011010011111101000011000111011001011111101&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000001101111101001011010011111101000011000111011001011111101&lt;/span&gt;
&lt;span class="mf"&gt;1000001101111101001011010011111101000011000111011001011111101&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000001101111101001011010011111101000011000111&lt;/span&gt;&lt;span class="err"&gt;????&lt;/span&gt;&lt;span class="mf"&gt;01&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="err"&gt;?????&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;
&lt;span class="mf"&gt;1111100000010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1111100000010&lt;/span&gt;
&lt;span class="mf"&gt;1111100000010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;11111&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00000&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;
&lt;span class="mf"&gt;110110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;110110&lt;/span&gt;
&lt;span class="mf"&gt;110110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;????&lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;
&lt;span class="mf"&gt;110110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;
&lt;span class="mf"&gt;...100010111011111&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;100&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;10111&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;111&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;span class="mf"&gt;...1000100000110001&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00000&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;span class="mf"&gt;110000001110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0000000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;???&lt;/span&gt;&lt;span class="mf"&gt;0000&lt;/span&gt;&lt;span class="err"&gt;?????&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;???&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;01&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;
&lt;span class="mf"&gt;110000001110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;000000&lt;/span&gt;&lt;span class="err"&gt;???&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;
&lt;span class="mf"&gt;1011011010000001110101001111000010001001011101010010010001000000010101010010001101110101111111010101010010101100110000011110000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1011011010000001110101001111000010001001011101010010010001000000010101010010001101110101111111010101010010101100110000011110000&lt;/span&gt;
&lt;span class="mf"&gt;...1011010010010100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...1011010010010100&lt;/span&gt;
&lt;span class="mf"&gt;...1011111110110011&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...1011111110110011&lt;/span&gt;
&lt;span class="mf"&gt;101000011110110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;101000011&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;span class="mf"&gt;100101&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That looks suitably random, but we might want to bias our random numbers a
little bit towards common error values like small constants, powers of two, etc.
Like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;INTEGER_WIDTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="c1"&gt;# some small integers&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# powers of two&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INTEGER_WIDTH&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# powers of two - 1&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INTEGER_WIDTH&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# negative versions of what we have so far&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# bit-flipped versions of what we have so far&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# sort them (because hypothesis simplifies towards earlier elements in the list)&lt;/span&gt;
&lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;ints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sampled_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ints_special&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we get data like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="mf"&gt;1110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1110&lt;/span&gt;
&lt;span class="mf"&gt;...10000000000000000001&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...10000&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;0000&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;
&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;0000&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;
&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;span class="mf"&gt;...10101100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...10101100&lt;/span&gt;
&lt;span class="mf"&gt;110000000011001010111011111111111111011110010001001100110001011&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;101&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
&lt;span class="mf"&gt;110000000011001010111011111111111111011110010001001100110001011&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;00000000&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;???&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??????????????&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;????&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;00&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;
&lt;span class="mf"&gt;...1011111111111111111111111111&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="err"&gt;??&lt;/span&gt;
&lt;span class="mf"&gt;...1011111111111111111111111111&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??????????????????????????&lt;/span&gt;
&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;??????????????????????????&lt;/span&gt;
&lt;span class="mf"&gt;101101&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;101101&lt;/span&gt;
&lt;span class="mf"&gt;111111111111111111111111111111111111111111111&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;111111111111111111111111111111111111111111111&lt;/span&gt;
&lt;span class="mf"&gt;10111&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10111&lt;/span&gt;
&lt;span class="mf"&gt;...101100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...1&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;111011&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;
&lt;span class="mf"&gt;101000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;001010&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;
&lt;span class="mf"&gt;101000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="mf"&gt;000&lt;/span&gt;
&lt;span class="mf"&gt;110010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;110010&lt;/span&gt;
&lt;span class="mf"&gt;...100111&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...100111&lt;/span&gt;
&lt;span class="mf"&gt;1111011010010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1111011010010&lt;/span&gt;
&lt;span class="mf"&gt;...1000000000000000000000000000000000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...1000000000000000000000000000000000000&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also write a test that checks that the somewhat tricky logic in
&lt;code&gt;__str__&lt;/code&gt; and &lt;code&gt;from_str&lt;/code&gt; is correct, by making sure that the two functions
round-trip (ie converting a &lt;code&gt;KnownBits&lt;/code&gt; to a string and then back to a
&lt;code&gt;KnownBits&lt;/code&gt; instance produces the same abstract value).&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_str_roundtrips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let's actually apply this infrastructure to test &lt;code&gt;abstract_invert&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="when-are-transfer-functions-correct-how-do-we-test-them"&gt;When are Transfer Functions Correct? How do we test them?&lt;/h3&gt;
&lt;p&gt;Abstract values, i.e. instances of &lt;code&gt;KnownBits&lt;/code&gt; represent &lt;em&gt;sets&lt;/em&gt; of concrete
values. We want the transfer functions to compute &lt;em&gt;overapproximations&lt;/em&gt; of the
concrete values. So if we have an arbitrary abstract value &lt;code&gt;k&lt;/code&gt;, with a concrete
number &lt;code&gt;n&lt;/code&gt; that is a member of the abstract values (i.e.
&lt;code&gt;k.contains(n) == True&lt;/code&gt;) then the result of the concrete operation &lt;code&gt;op(n)&lt;/code&gt;
&lt;strong&gt;must&lt;/strong&gt; be a member of the result of the abstract operation &lt;code&gt;k.abstract_op()&lt;/code&gt;
(i.e. &lt;code&gt;k.abstract_op().contains(op(n)) == True&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Checking the correctness/overapproximation property is a good match for
hypothesis. Here's what the test for &lt;code&gt;abstract_invert&lt;/code&gt; looks like:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="c1"&gt;# compute the real result&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# compute the abstract result&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# the abstract result must contain the real result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the &lt;em&gt;only&lt;/em&gt; condition needed for &lt;code&gt;abstract_invert&lt;/code&gt; to be correct. If
&lt;code&gt;abstract_invert&lt;/code&gt; fulfils this property for every combination of abstract and
concrete value then &lt;code&gt;abstract_invert&lt;/code&gt; is correct. Note however, that this test
does not actually check whether &lt;code&gt;abstract_invert&lt;/code&gt; gives us precise results. A
correct (but imprecise) implementation of &lt;code&gt;abstract_invert&lt;/code&gt; would simply return
a completely unknown result, regardless of what is known about the input
&lt;code&gt;KnownBits&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The "proper" CS term for this notion of correctness is called &lt;em&gt;soundness&lt;/em&gt;. The
correctness condition on the transfer functions is called a &lt;em&gt;Galois
connection&lt;/em&gt;. I won't go into any mathematical/technical details here, but
wanted to at least mention the terms. I found &lt;a href="https://web.njit.edu/~mjk76/"&gt;Martin
Kellogg&lt;/a&gt;'s
&lt;a href="https://web.njit.edu/~mjk76/teaching/cs684-sp24/assets/lecture-12.pdf#34"&gt;slides&lt;/a&gt;
to be quite an approachable introduction to the Galois connection and how to
show soundness.&lt;/p&gt;
&lt;h3 id="implementing-binary-transfer-functions"&gt;Implementing Binary Transfer Functions&lt;/h3&gt;
&lt;p&gt;Now we have infrastructure in place for testing transfer functions with random
inputs. With that we can start thinking about the more complicated case, that of
binary operations. Let's start with the simpler ones, &lt;code&gt;and&lt;/code&gt; and &lt;code&gt;or&lt;/code&gt;. For &lt;code&gt;and&lt;/code&gt;,
we can know a &lt;code&gt;0&lt;/code&gt; bit in the result if either of the input bits are known &lt;code&gt;0&lt;/code&gt;;
or we can know a &lt;code&gt;1&lt;/code&gt; bit in the result if both input bits are known &lt;code&gt;1&lt;/code&gt;.
Otherwise the resulting bit is unknown. Let's look at all the combinations:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;and
input1: 000111???
input2: 01?01?01? 
result: 00001?0??
&lt;/pre&gt;&lt;/div&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abstract_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="c1"&gt;# known ones&lt;/span&gt;
        &lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here's an example unit-test and a property-based test for &lt;code&gt;and&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_and&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# test all combinations of 0, 1, ? in one example&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'01?01?01?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'000111???'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# should be: 0...00001?0??&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;   &lt;span class="s2"&gt;"1?0??"&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To implement &lt;code&gt;or&lt;/code&gt; is pretty similar. The result is known &lt;code&gt;1&lt;/code&gt; where either of the
inputs is &lt;code&gt;1&lt;/code&gt;. The result is known &lt;code&gt;0&lt;/code&gt; where both inputs are known &lt;code&gt;0&lt;/code&gt;, and &lt;code&gt;?&lt;/code&gt;
otherwise.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;or
input1: 000111???
input2: 01?01?01? 
result: 01?111?1?
&lt;/pre&gt;&lt;/div&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abstract_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
        &lt;span class="n"&gt;zeros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros&lt;/span&gt;
        &lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;zeros&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here's an example unit-test and a property-based test for &lt;code&gt;or&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_or&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'01?01?01?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'000111???'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# should be:  0...01?111?1?&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;   &lt;span class="s2"&gt;"1?111?1?"&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Implementing support for &lt;code&gt;abstract_xor&lt;/code&gt; is relatively simple, and left as an
exercise :-).&lt;/p&gt;
&lt;h3 id="addition-and-subtraction"&gt;Addition and Subtraction&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;invert&lt;/code&gt;, &lt;code&gt;and&lt;/code&gt;, and &lt;code&gt;or&lt;/code&gt; are relatively simple transfer functions to write,
because they compose over the individual bits of the integers. The arithmetic
functions &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;sub&lt;/code&gt; are significantly harder, because of carries and
borrows. Coming up with the formulas for them and gaining an intuitive
understanding is quite tricky and involves carefully going through a few
examples with pen and paper. When implementing this in PyPy, Nico and I didn't
come up with the implementation ourselves, but instead took them from the
&lt;a href="https://arxiv.org/abs/2105.05398"&gt;Tristate Numbers&lt;/a&gt; paper. Here's the code,
with example tests and hypothesis tests:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abstract_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;sum_ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
        &lt;span class="n"&gt;sum_unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
        &lt;span class="n"&gt;all_carries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum_ones&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sum_unknowns&lt;/span&gt;
        &lt;span class="n"&gt;ones_carries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;all_carries&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;sum_ones&lt;/span&gt;
        &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ones_carries&lt;/span&gt;
        &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum_ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abstract_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;diff_ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
        &lt;span class="n"&gt;val_borrows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff_ones&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff_ones&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;val_borrows&lt;/span&gt;
        &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;diff_ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_add&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0?10?10?10'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0???111000'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;   &lt;span class="s2"&gt;"?????01?10"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_sub&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0?10?10?10'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0???111000'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;   &lt;span class="s2"&gt;"...?11?10"&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;    &lt;span class="s1"&gt;'...1?10?10?10'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'...10000???111000'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;   &lt;span class="s2"&gt;"111?????11?10"&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we are in a pretty good situation, and have implemented abstract versions
for a bunch of important arithmetic and binary functions. What's also surprising
is that the implementation of all of the transfer functions is quite efficient.
We didn't have to write loops over the individual bits at all, instead we found
closed form expressions using primitive operations on the underlying integers
&lt;code&gt;ones&lt;/code&gt; and &lt;code&gt;unknowns&lt;/code&gt;. This means that computing the results of abstract
operations is quite efficient, which is important when using the abstract domain
in the context of a JIT compiler.&lt;/p&gt;
&lt;h3 id="proving-correctness-of-the-transfer-functions-with-z3"&gt;Proving correctness of the transfer functions with Z3&lt;/h3&gt;
&lt;p&gt;As one can probably tell from my recent posts, I've been thinking about
compiler correctness a lot. Getting the transfer functions absolutely
correct is really crucial, because a bug in them would lead to miscompilation of
Python code when the abstract domain is added to the JIT. While the randomized
tests are great, it's still entirely possible for them to miss bugs. The state
space for the arguments of a binary transfer function is &lt;code&gt;3**64 * 3**64&lt;/code&gt;, and if
only a small part of that contains wrong behaviour it would be really unlikely
for us to find it with random tests by chance. Therefore I was reluctant to
merge the PyPy branch that contained the new abstract domain for a long time.&lt;/p&gt;
&lt;p&gt;To increase our confidence in the correctness of the transfer functions further,
we can use Z3 to &lt;em&gt;prove&lt;/em&gt; their correctness, which gives us much stronger
guarantees (not 100%, obviously). In this subsection I will show how to do that.&lt;/p&gt;
&lt;p&gt;Here's an attempt to do this manually in the Python repl:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;z3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Solver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# like last blog post, proof by failing to find counterexamples&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsat&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# let's set up a z3 bitvector variable for an arbitrary concrete value&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'concrete_value'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;
&lt;span class="n"&gt;concrete_value&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# due to operator overloading we can manipulate z3 formulas&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;concrete_value&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; 
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# now z3 bitvector variables for the ones and zeros fields&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abstract_ones'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abstract_unknowns'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# we construct a KnownBits instance with the z3 variables&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# due to operator overloading we can call the methods on k1:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;
&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;abstract_unknowns&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;abstract_ones&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;
&lt;span class="n"&gt;abstract_unknowns&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# here's the correctness condition that we want to prove:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;concrete_value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;abstract_unknowns&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;
&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;abstract_unknowns&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;abstract_ones&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# let's try&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;stdin&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;stdin&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prove&lt;/span&gt;
&lt;span class="ne"&gt;AssertionError&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# it doesn't work! let's look at the counterexample to see why:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;abstract_unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;abstract_ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;concrete_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# we can build a KnownBits instance with the values in the&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# counterexample:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# concrete result&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;counter_example_k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;counter_example_k1&lt;/span&gt;
&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;counter_example_k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counter_example_k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;counter_example_k2&lt;/span&gt;
&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# let's check the failing condition&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;counter_example_k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What is the problem here? We didn't tell Z3 that &lt;code&gt;n1&lt;/code&gt; was supposed to be a
member of &lt;code&gt;k1&lt;/code&gt;. We can add this as a precondition to the solver, and then the
prove works:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; solver.add(k1.contains(n1))
&amp;gt;&amp;gt;&amp;gt;&amp;gt; prove(k2.contains(n2)) # works!
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is super cool! It's really a proof about the actual implementation, because
we call the implementation methods directly, and due to the operator overloading
that Z3 does we can be sure that we are actually checking a formula that
corresponds to the Python code. This eliminates one source of errors in formal
methods.&lt;/p&gt;
&lt;p&gt;Doing the proof manually on the Python REPL is kind of annoying though, and we
also would like to make sure that the proofs are re-done when we change the
code. What we would really like to do is writing the proofs as a unit-test that
we can run while developing and in CI. Doing this is possible, and the unit
tests that really perform proofs look pleasingly similar to the
Hypothesis-based ones.&lt;/p&gt;
&lt;p&gt;First we need to set up a bit of infrastructure:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;INTEGER_WIDTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INTEGER_WIDTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;BitVecVal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BitVecVal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INTEGER_WIDTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# instantiate a solver&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Solver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# a Z3 variable for the first concrete value&lt;/span&gt;
    &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# a KnownBits instances that uses Z3 variables as its ones and unknowns,&lt;/span&gt;
    &lt;span class="c1"&gt;# representing the first abstract value&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n1_ones"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n1_unkowns"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;# add the precondition to the solver that the concrete value n1 must be a&lt;/span&gt;
    &lt;span class="c1"&gt;# member of the abstract value k1&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# a Z3 variable for the second concrete value&lt;/span&gt;
    &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# a KnownBits instances for the second abstract value&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n2_ones"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n2_unkowns"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;# add the precondition linking n2 and k2 to the solver&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;z3res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;z3res&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;z3res&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sat&lt;/span&gt; &lt;span class="c1"&gt;# can't be timeout, we set no timeout&lt;/span&gt;
        &lt;span class="c1"&gt;# make the model with the counterexample global, to make inspecting the&lt;/span&gt;
        &lt;span class="c1"&gt;# bug easier when running pytest --pdb&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"n1=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, n2=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;counter_example_k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_signed_long&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                       &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_signed_long&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;counter_example_k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_signed_long&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                       &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_signed_long&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"k1=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counter_example_k1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, k2=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;counter_example_k2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"but &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="si"&gt;=}&lt;/span&gt;&lt;span class="s2"&gt; evaluates to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then we can write proof-unit-tests like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_abstract_invert&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_abstract_and&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_abstract_or&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_abstract_add&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_abstract_sub&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It's possible to write a bit more Python-metaprogramming-magic and unify the
Hypothesis and Z3 tests into the same test definition.&lt;sup id="fnref:proof_bitwidths"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#fn:proof_bitwidths"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id="cases-where-this-style-of-z3-proof-doesnt-work"&gt;Cases where this style of Z3 proof doesn't work&lt;/h3&gt;
&lt;p&gt;Unfortunately the approach described in the previous section only works for a
very small number of cases. It breaks down as soon as the &lt;code&gt;KnownBits&lt;/code&gt; methods
that we're calling contain any &lt;code&gt;if&lt;/code&gt; conditions (including hidden ones like
the short-circuiting &lt;code&gt;and&lt;/code&gt; and &lt;code&gt;or&lt;/code&gt; in Python). Let's look at an example and
implement &lt;code&gt;abstract_eq&lt;/code&gt;. &lt;code&gt;eq&lt;/code&gt; is supposed to be an operation that compares two
integers and returns &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt; if they are different or equal, respectively.
Implementing this in knownbits looks like this (with example and hypothesis
tests):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# the result is a 0, 1, or ?&lt;/span&gt;

        &lt;span class="c1"&gt;# if they are both the same constant, they must be equal&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# check whether we have known disagreeing bits, then we know the result&lt;/span&gt;
        &lt;span class="c1"&gt;# is 0&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_disagrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# an unknown boolean&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_disagrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# check whether the bits disagree in any place where both are known&lt;/span&gt;
        &lt;span class="n"&gt;both_known&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;both_known&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;both_known&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_eq&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'...?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'...?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'?'&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_hypothesis_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Trying to do the proof in the same style as before breaks:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;stdin&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"knownbits.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;246&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;abstract_eq&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_disagrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"venv/site-packages/z3/z3.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;381&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="fm"&gt;__bool__&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;Z3Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Symbolic expressions cannot be cast to concrete Boolean values."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z3types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Z3Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Symbolic&lt;/span&gt; &lt;span class="n"&gt;expressions&lt;/span&gt; &lt;span class="n"&gt;cannot&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;concrete&lt;/span&gt; &lt;span class="n"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We cannot call &lt;code&gt;abstract_eq&lt;/code&gt; on a &lt;code&gt;KnownBits&lt;/code&gt; with Z3 variables as fields,
because once we hit an &lt;code&gt;if&lt;/code&gt; statement, the whole approach of relying on the
operator overloading breaks down. Z3 doesn't actually parse the Python code or
anything advanced like that, we rather build an expression only by running the
code and letting the Z3 formulas build up.&lt;/p&gt;
&lt;p&gt;To still prove the correctness of &lt;code&gt;abstract_eq&lt;/code&gt; we need to manually transform
the control flow logic of the function into a Z3 formula that uses the &lt;code&gt;z3.If&lt;/code&gt;
expression, using a small helper function:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;z3_cond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trueval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;falseval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;If&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BitVecVal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trueval&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;BitVecVal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;falseval&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;z3_abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# follow the *logic* of abstract_eq, we can't call it due to the ifs in it&lt;/span&gt;
    &lt;span class="n"&gt;case1cond&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;case2cond&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_disagrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# ones is 1 in the first case, 0 otherwise&lt;/span&gt;
    &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_cond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case1cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# in the first two cases, unknowns is 0, 1 otherwise&lt;/span&gt;
    &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_cond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case1cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case2cond&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_abstract_eq_logic&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;n3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_cond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# concrete result&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This proof works. It is a lot less satisfying than the previous ones though,
because we could have done an error in the manual transcription from Python code
to Z3 formulas (there are possibly more heavy-handed approaches where we do
this transformation more automatically using e.g. the &lt;code&gt;ast&lt;/code&gt; module to analyze
the source code, but that's a much more complicated researchy project). To
lessen this problem somewhat we can factor out the parts of the logic that don't
have any conditions into small helper methods (like &lt;code&gt;_disagrees&lt;/code&gt; in this
example) and use them in the manual conversion of the code to Z3 formulas.&lt;sup id="fnref:tests_vs_proofs"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#fn:tests_vs_proofs"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The final condition that Z3 checks, btw, is this one:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;If(n1 == n2, 1, 0) &amp;amp;
~If(Or(And(n1_unkowns == 0,
           n2_unkowns == 0,
           n1_ones == n2_ones),
       n1_ones &amp;amp; ~n1_unkowns &amp;amp; ~n2_unkowns !=
       n2_ones &amp;amp; ~n1_unkowns &amp;amp; ~n2_unkowns),
    0, 1) ==
If(And(n1_unkowns == 0, n2_unkowns == 0, n1_ones == n2_ones),
   1, 0)
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="making-statements-about-precision"&gt;Making Statements about Precision&lt;/h3&gt;
&lt;p&gt;So far we have only used Z3 to prove statements about correctness, i.e. that
our abstract operations overapproximate what can happen with concrete values.
While proving this property is essential if we want to avoid miscompilation,
correctness alone is not a very strong constraint on the implementation of our
abstract transfer functions. We could simply return &lt;code&gt;Knownbits.unknowns()&lt;/code&gt; for
every &lt;code&gt;abstract_*&lt;/code&gt; method and the resulting overapproximation would be correct,
but useless in practice.&lt;/p&gt;
&lt;p&gt;It's much harder to make statements about whether the transfer functions are
maximally precise. There are two aspects of precision I want to discuss in this
section, however.&lt;/p&gt;
&lt;p&gt;The first aspect is that we would really like it if the transfer functions
compute the maximally precise results for singleton sets. If all abstract
arguments of an operations are constants, i.e. contain only a single concrete
element, then we know that the resulting set also has only a single element. We
can prove that all our transfer functions have this property:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_z3_prove_constant_folding&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_invert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                     &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                     &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                     &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                     &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_abstract_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                     &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Proving with Z3 that the transfer functions are maximally precise for
non-constant arguments seems to be relatively hard. I tried a few completely
rigorous approaches and failed. The paper &lt;a href="https://arxiv.org/pdf/2105.05398"&gt;Sound, Precise, and Fast Abstract
Interpretation with Tristate Numbers&lt;/a&gt;
contains an optimality proof for the transfer functions of addition and
subtraction, so we can be certain that they are as precise as is
possible.&lt;/p&gt;
&lt;p&gt;I still want to show an approach for trying to find concrete examples of
abstract values that are less precise than they could be, using a combination
of Hypothesis and Z3. The idea is to use hypothesis to pick random abstract
values. Then we compute the abstract result using our transfer function.
Afterwards we can ask Z3 to find us an abstract result that is better than the
one our transfer function produced. If Z3 finds a better abstract result, we
have a concrete example of imprecision for our transfer function. Those tests
aren't strict proofs, because they rely on generating random abstract values,
but they can still be valuable (not for the transfer functions in this blog
post, which are all optimal).&lt;/p&gt;
&lt;p&gt;Here is what the code looks like (this is a little bit bonus content, I'll not
explain the details and can only hope that the comments are somewhat helpful):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random_knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_knownbits_and_contained_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_check_precision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;
    &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;
    &lt;span class="c1"&gt;# apply transfer function&lt;/span&gt;
    &lt;span class="n"&gt;k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abstract_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;example_res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt;

    &lt;span class="c1"&gt;# try to find a better version of k3 with Z3&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Solver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'v1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'v2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ones'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;unknowns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BitVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'unknowns'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;better_k3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# we're trying to find an example for a better k3, so we use check, without&lt;/span&gt;
    &lt;span class="c1"&gt;# negation:&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;# better_k3 should be a valid knownbits instance&lt;/span&gt;
        &lt;span class="n"&gt;better_k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_well_formed&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="c1"&gt;# it should be better than k3, ie there are known bits in better_k3&lt;/span&gt;
        &lt;span class="c1"&gt;# that we don't have in k3&lt;/span&gt;
        &lt;span class="n"&gt;better_k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowns&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# now encode the correctness condition for better_k3 with a ForAll:&lt;/span&gt;
        &lt;span class="c1"&gt;# for all concrete values var1 and var2, it must hold that if&lt;/span&gt;
        &lt;span class="c1"&gt;# var1 is in k1 and var2 is in k2 it follows that var1 + var2 is in&lt;/span&gt;
        &lt;span class="c1"&gt;# better_k3&lt;/span&gt;
        &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;better_k3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
    &lt;span class="c1"&gt;# if this query is satisfiable, we have found a better result for the&lt;/span&gt;
    &lt;span class="c1"&gt;# abstract_add&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;rk3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_signed_long&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unknowns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_signed_long&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"better"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rk3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It does not actually fail for &lt;code&gt;abstract_add&lt;/code&gt; (nor the other abstract
functions). To see the test failing we can add some imprecision to the
implementation of &lt;code&gt;abstract_add&lt;/code&gt; to see Hypothesis and Z3 find examples of
values that are not optimally precise (for example by setting some bits
of &lt;code&gt;unknowns&lt;/code&gt; in the implementation of &lt;code&gt;abstract_add&lt;/code&gt; unconditionally).&lt;/p&gt;
&lt;h3 id="using-the-abstract-domain-in-the-toy-optimizer-for-generalized-constant-folding"&gt;Using the Abstract Domain in the Toy Optimizer for Generalized Constant Folding&lt;/h3&gt;
&lt;p&gt;Now after all this work we can finally actually use the knownbits abstract
domain in the toy optimizer. The code for this follows &lt;a href="https://bernsteinbear.com/blog/toy-abstract-interpretation/"&gt;Max' intro post about
abstract interpretation&lt;/a&gt;
quite closely.&lt;/p&gt;
&lt;p&gt;For completeness sake, in the fold there's the basic infrastructure classes
that make up the IR again (they are identical or at least extremely close to
the previous toy posts).&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;toy infrastructure&lt;/summary&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abstract"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;forwarded&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
            &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wraparg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;make_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wraparg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;make_op&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;varprefix&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"var"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;varnames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;varnames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# give the operation a name used while&lt;/span&gt;
        &lt;span class="c1"&gt;# printing:&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;varprefix&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;varnames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;
        &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;arg_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;strop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;



&lt;/details&gt;

&lt;p&gt;Now we can write some first tests, the first one simply checking constant
folding:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_constfold_two_ops&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;optvar1 = int_add(19, optvar0)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Calling the transfer functions on constant &lt;code&gt;KnownBits&lt;/code&gt; produces a constant
results, as we have seen. Therefore "regular" constant folding should hopefully
be achieved by optimizing with the &lt;code&gt;KnownBits&lt;/code&gt; abstract domain too.&lt;/p&gt;
&lt;p&gt;The next two tests are slightly more complicated and can't be optimized by
regular constant-folding. They follow the motivating examples from the start of
this blog post, a hundred years ago:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_constfold_via_knownbits&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;optvar1 = int_or(optvar0, 1)&lt;/span&gt;
&lt;span class="s2"&gt;optvar2 = dummy(1)"""&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_constfold_alignment_check&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;b111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# mask off the lowest three bits, thus var2 is aligned&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# add 16 to aligned quantity&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# check alignment of result&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;b111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# var5 should be const-folded to 1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;var6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;optvar1 = int_and(optvar0, -8)&lt;/span&gt;
&lt;span class="s2"&gt;optvar2 = int_add(optvar1, 16)&lt;/span&gt;
&lt;span class="s2"&gt;optvar3 = dummy(1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is &lt;code&gt;simplify&lt;/code&gt; to make these tests pass:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;unknown_transfer_functions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;abstract_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_unknown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;abstract_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# dict mapping Operation to KnownBits&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;knownbits_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;abstract_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# apply the transfer function on the abstract arguments&lt;/span&gt;
        &lt;span class="n"&gt;name_without_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeprefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"int_"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;method_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"abstract_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name_without_prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;transfer_function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknown_transfer_functions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;abstract_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;knownbits_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;abstract_res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abstract_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transfer_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;abstract_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# if the result is a constant, we optimize the operation away and make&lt;/span&gt;
        &lt;span class="c1"&gt;# it equal to the constant result&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;abstract_res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abstract_res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="c1"&gt;# otherwise emit the op&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code follows the approach from the previous blog post very closely. The
only difference is that we apply the transfer function &lt;em&gt;first&lt;/em&gt;, to be able to
detect whether the abstract domain can tell us that the result has to always be
a constant. This code makes all three tests pass.&lt;/p&gt;
&lt;h3 id="using-the-knownbits-domain-for-conditional-peephole-rewrites"&gt;Using the &lt;code&gt;KnownBits&lt;/code&gt; Domain for Conditional Peephole Rewrites&lt;/h3&gt;
&lt;p&gt;So far we are only using the &lt;code&gt;KnownBits&lt;/code&gt; domain to find out that certain
operations have to produce a constant. We can also use the &lt;code&gt;KnownBits&lt;/code&gt; domain
to check whether certain operation rewrites are correct. Let's use one of the
examples from the &lt;a href="https://www.pypy.org/posts/2024/07/mining-jit-traces-missing-optimizations-z3.html"&gt;Mining JIT traces for missing optimizations with
Z3&lt;/a&gt;
post, where Z3 found the inefficiency &lt;code&gt;(x &amp;lt;&amp;lt; 4) &amp;amp; -0xf == x &amp;lt;&amp;lt; 4&lt;/code&gt; in PyPy JIT
traces. We don't have shift operations, but we want to generalize this optimization
anyway. The general form of this rewrite is that under some circumstances &lt;code&gt;x &amp;amp;
y == x&lt;/code&gt;, and we can use the &lt;code&gt;KnownBits&lt;/code&gt; domain to detect situations where this
must be true.&lt;/p&gt;
&lt;p&gt;To understand &lt;em&gt;when&lt;/em&gt; &lt;code&gt;x &amp;amp; y == x&lt;/code&gt; is true, we can think about individual pairs of
bits &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. If &lt;code&gt;a == 0&lt;/code&gt;, then &lt;code&gt;a &amp;amp; b == 0 &amp;amp; b == 0 == a&lt;/code&gt;. If &lt;code&gt;b == 1&lt;/code&gt;
then &lt;code&gt;a &amp;amp; b == a &amp;amp; 1 == a&lt;/code&gt;. So if either &lt;code&gt;a == 0&lt;/code&gt; or &lt;code&gt;b == 1&lt;/code&gt; is true,
&lt;code&gt;a &amp;amp; b == a&lt;/code&gt; follows. And if either of these conditions is true for &lt;em&gt;all&lt;/em&gt; the
bits of &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, we can know that &lt;code&gt;x &amp;amp; y == x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can write a method on &lt;code&gt;KnownBits&lt;/code&gt; to check for this condition:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;is_and_identity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;""" Return True if n1 &amp;amp; n2 == n1 for any n1 in self and n2 in other.&lt;/span&gt;
&lt;span class="sd"&gt;        (or, equivalently, return True if n1 | n2 == n2)"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since my reasoning about this feels ripe for errors, let's check that our
understanding is correct with Z3:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_prove_is_and_identity&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z3_setup_variables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;prove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_and_identity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;n2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let's use this in the toy optimizer. Here are two tests for this rewrite:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_remove_redundant_and&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mb"&gt;0b1111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# mask off the lowest four bits&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# applying the same mask is not redundant&lt;/span&gt;
    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;optvar1 = int_and(optvar0, -16)&lt;/span&gt;
&lt;span class="s2"&gt;optvar2 = dummy(optvar1)"""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_remove_redundant_and_more_complex&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# var2 has bit pattern ????&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mb"&gt;0b1111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# var3 has bit pattern ...?1111&lt;/span&gt;
    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mb"&gt;0b1111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# var4 is just var2&lt;/span&gt;
    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;optvar1 = getarg(1)&lt;/span&gt;
&lt;span class="s2"&gt;optvar2 = int_and(optvar0, 15)&lt;/span&gt;
&lt;span class="s2"&gt;optvar3 = int_or(optvar1, 15)&lt;/span&gt;
&lt;span class="s2"&gt;optvar4 = dummy(optvar2)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first test could also be made to pass by implementing a reassociation
optimization that turns &lt;code&gt;(x &amp;amp; c1) &amp;amp; c2&lt;/code&gt; into &lt;code&gt;x &amp;amp; (c1 &amp;amp; c2)&lt;/code&gt; and then constant-folds the second &lt;code&gt;and&lt;/code&gt;. But here we want to
use &lt;code&gt;KnownBits&lt;/code&gt; and conditionally rewrite &lt;code&gt;int_and&lt;/code&gt; to its first argument. So to make the tests pass,
we can change &lt;code&gt;simplify&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;abstract_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# dict mapping Operation to KnownBits&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;knownbits_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# apply the transfer function on the abstract arguments&lt;/span&gt;
        &lt;span class="n"&gt;name_without_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeprefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"int_"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;method_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"abstract_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name_without_prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;transfer_function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnownBits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unknown_transfer_functions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;abstract_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;knownbits_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;abstract_res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abstract_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transfer_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;abstract_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# if the result is a constant, we optimize the operation away and make&lt;/span&gt;
        &lt;span class="c1"&gt;# it equal to the constant result&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;abstract_res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_constant&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abstract_res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt; new code&lt;/span&gt;
        &lt;span class="c1"&gt;# conditionally rewrite int_and(x, y) to x&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"int_and"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abstract_args&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_and_identity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="c1"&gt;# &amp;gt;&amp;gt;&amp;gt;&amp;gt; end changes&lt;/span&gt;
        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And with that, the new tests pass as well. A real implementation would also
check the other argument order, but we leave that out for the sake of brevity.&lt;/p&gt;
&lt;p&gt;This rewrite also generalizes the &lt;a href="https://pypy.org/posts/2024/07/finding-simple-rewrite-rules-jit-z3.html"&gt;rewrites&lt;/a&gt; &lt;code&gt;int_and(0, x) -&amp;gt; 0&lt;/code&gt; and
&lt;code&gt;int_and(-1, x) -&amp;gt; x&lt;/code&gt;, let's add a test for those:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_remove_and_simple&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# == 0&lt;/span&gt;
    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# == -1&lt;/span&gt;
    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int_and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# == var1&lt;/span&gt;
    &lt;span class="n"&gt;var5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;span class="s2"&gt;optvar1 = getarg(1)&lt;/span&gt;
&lt;span class="s2"&gt;optvar2 = dummy(optvar1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test just passes. And that's it for this post!&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In this post we've seen the implementation, testing and proofs about a 'known
bits' abstract domain, as well as its use in the toy optimizer to generalize
constant folding, and to implement conditional peephole rewrites.&lt;/p&gt;
&lt;p&gt;In the next posts I'll write about the real implementation of a knownbits
domain in PyPy's JIT, its combination with the existing interval abstract
domain, how to deal with gaining information from conditions in the program,
and some lose ends.&lt;/p&gt;
&lt;p&gt;Sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/KnownBits.cpp"&gt;Known bits in LLVM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/kernel/bpf/tnum.c"&gt;Tristate numbers for known bits in Linux eBPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2105.05398"&gt;Sound, Precise, and Fast Abstract Interpretation with Tristate Numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://people.cs.rutgers.edu/~sn349/papers/agni-cav2023.pdf"&gt;Verifying the Veriﬁer: eBPF Range Analysis Veriﬁcation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dougallj.wordpress.com/2020/01/13/bit-twiddling-addition-with-unknown-bits/"&gt;Bit-Twiddling: Addition with Unknown
  Bits&lt;/a&gt;
  is a super readable blog post by Dougall J. I've taken the &lt;code&gt;ones&lt;/code&gt; and
  &lt;code&gt;unknowns&lt;/code&gt; naming from this post, which I find significantly clearer than
  &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;mask&lt;/code&gt;, which the Linux kernel uses.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bitmath.blogspot.com/"&gt;Bits, Math and Performance(?)&lt;/a&gt;, a fantastic
  blog by &lt;a href="https://mastodon.gamedev.place/@harold"&gt;Harold Aptroot&lt;/a&gt;. There are a
  lot of relevant posts about known bits, range analysis etc. Harold is also
  the author of &lt;a href="http://haroldbot.nl/"&gt;Haroldbot&lt;/a&gt;, a website that can be used
  for bitvector calculations, and also checks bitvector identities.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cea.hal.science/cea-01795779/document"&gt;Sharpening Constraint Programming approaches for Bit-Vector Theory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://users.cs.utah.edu/~regehr/papers/lctes06_2/fp019-regehr.pdf"&gt;Deriving Abstract Transfer Functions for Analyzing Embedded Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2105.00493"&gt;Synthesizing Abstract Transformers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:proof_bitwidths"&gt;
&lt;p&gt;There's a subtletly about the Z3 proofs that I'm sort of
glossing over here. Python integers are of arbitrary width, and the
&lt;code&gt;KnownBits&lt;/code&gt; code is actually carefully written to work for integers of any
size. This property is tested by the Hypothesis tests, which don't limit
the sizes of the generated random integers. However, the Z3 proofs only
check bitvectors of a fixed bitwidth of 64. There are various ways to deal
with this situation. For most "real" compilers, the bitwidth of integers
would be fixed anyway. Then the components &lt;code&gt;ones&lt;/code&gt; and &lt;code&gt;unknowns&lt;/code&gt; of the
&lt;code&gt;KnownBits&lt;/code&gt; class would use the number of bits the corresponding integer
variable has, and the Z3 proofs would use the same width. This is what we
do in the PyPy JIT. &lt;a class="footnote-backref" href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#fnref:proof_bitwidths" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:tests_vs_proofs"&gt;
&lt;p&gt;The less close connection between implementation and proof
for &lt;code&gt;abstract_eq&lt;/code&gt; is one of the reasons why it makes sense to do
unit-testing &lt;em&gt;in addition&lt;/em&gt; to proofs. For a more detailed explanation of
why both tests and proofs are good to
have, see &lt;a href="https://siek.blogspot.com/2024/06/data-structures-and-algorithms-correctly.html#correct-software-via-write-test-and-prove:~:text=We%20recognize%20that%20once%20step,detect%20most%20of%20the%20bugs"&gt;Jeremy Siek's blog
post&lt;/a&gt;,
as well as the &lt;a href="https://www-cs-faculty.stanford.edu/~knuth/faq.html#:~:text=What's%20the%20exact%20citation%20of%20your%20oft%2Dcited%20comment%20about%20bugs?"&gt;Knuth
quote&lt;/a&gt;. &lt;a class="footnote-backref" href="https://www.pypy.org/posts/2024/08/toy-knownbits.html#fnref:tests_vs_proofs" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>toy-optimizer</category><category>z3</category><guid>https://www.pypy.org/posts/2024/08/toy-knownbits.html</guid><pubDate>Sat, 03 Aug 2024 14:00:00 GMT</pubDate></item><item><title>Abstract interpretation in the Toy Optimizer</title><link>https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html</link><dc:creator>Max Bernstein</dc:creator><description>&lt;p&gt;This is a &lt;a href="https://bernsteinbear.com/blog/toy-abstract-interpretation/" rel="canonical"&gt;cross-post&lt;/a&gt;
from Max Bernstein from his excellent blog where he writes about programming
languages, compilers, optimizations, virtual machines. He's looking for a
(dynamic language runtime or compiler related) job too.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;CF Bolz-Tereick wrote some excellent posts in which they &lt;a href="https://pypy.org/posts/2022/07/toy-optimizer.html"&gt;introduce a small IR
and optimizer&lt;/a&gt; and &lt;a href="https://pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html"&gt;extend it with allocation
removal&lt;/a&gt;. We also did a live stream together in which
we did &lt;a href="https://www.youtube.com/watch?v=w-UHg0yOPSE"&gt;some more heap optimizations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this blog post, I'm going to write a small abstract interpreter for the Toy
IR and then show how we can use it to do some simple optimizations. It assumes
that you are familiar with the little IR, which I have reproduced unchanged in
&lt;a href="https://gist.github.com/tekknolagi/4425b28d5267e7bae8b0d7ef8fb4a671"&gt;a GitHub Gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Abstract interpretation is a general framework for efficiently computing
properties that must be true for all possible executions of a program. It's a
widely used approach both in compiler optimizations as well as offline static
analysis for finding bugs. I'm writing this post to pave the way for CF's next
post on proving abstract interpreters correct for range analysis and known bits
analysis inside PyPy.&lt;/p&gt;
&lt;p&gt;Before we begin, I want to note a couple of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Toy IR is in SSA form, which means that every variable is defined exactly
  once. This means that abstract properties of each variable are easy to track.&lt;/li&gt;
&lt;li&gt;The Toy IR represents a linear trace without control flow, meaning we won't
  talk about meet/join or fixpoints. They only make sense if the IR has a
  notion of conditional branches or back edges (loops).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alright, let's get started.&lt;/p&gt;
&lt;h3 id="welcome-to-abstract-interpretation"&gt;Welcome to abstract interpretation&lt;/h3&gt;
&lt;p&gt;Abstract interpretation means a couple different things to different people.
There's rigorous mathematical formalism thanks to Patrick and Radhia Cousot,
our favorite power couple, and there's also sketchy hand-wavy stuff like what
will follow in this post. In the end, all people are trying to do is reason
about program behavior without running it.&lt;/p&gt;
&lt;p&gt;In particular, abstract interpretation is an &lt;em&gt;over-approximation&lt;/em&gt; of the
behavior of a program. Correctly implemented abstract interpreters never lie,
but they might be a little bit pessimistic. This is because instead of using
real values and running the program---which would produce a concrete result and
some real-world behavior---we "run" the program with a parallel universe of
&lt;em&gt;abstract&lt;/em&gt; values. This abstract run gives us information about all possible
runs of the program.&lt;sup id="fnref:logozzo"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html#fn:logozzo"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Abstract values always represent sets of concrete values. Instead of literally
storing a set (in the world of integers, for example, it could get pretty
big...there are a lot of integers), we group them into a finite number of named
subsets.&lt;sup id="fnref:lattices"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html#fn:lattices"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Let's learn a little about abstract interpretation with an example program and
example abstract domain. Here's the example program:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And our abstract domain is "is the number positive" (where "positive" means
nonnegative, but I wanted to keep the words distinct):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;       top
    /       \
positive    negative
    \       /
      bottom
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The special &lt;em&gt;top&lt;/em&gt; value means "I don't know" and the special &lt;em&gt;bottom&lt;/em&gt; value
means "empty set" or "unreachable". The &lt;em&gt;positive&lt;/em&gt; and &lt;em&gt;negative&lt;/em&gt; values
represent the sets of all positive and negative numbers, respectively.&lt;/p&gt;
&lt;p&gt;We initialize all the variables &lt;code&gt;v0&lt;/code&gt;, &lt;code&gt;v1&lt;/code&gt;, and &lt;code&gt;v2&lt;/code&gt; to &lt;em&gt;bottom&lt;/em&gt; and then walk
our IR, updating our knowledge as we go.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# here&lt;/span&gt;
&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order to do that, we have to have &lt;em&gt;transfer functions&lt;/em&gt; for each operation.
For constants, the transfer function is easy: determine if the constant is
positive or negative. For other operations, we have to define a function that
takes the abstract values of the operands and returns the abstract value of the
result.&lt;/p&gt;
&lt;p&gt;In order to be correct, transfer functions for operations have to be compatible
with the behavior of their corresponding concrete implementations. You can
think of them having an implicit universal quantifier &lt;em&gt;forall&lt;/em&gt; in front of
them.&lt;/p&gt;
&lt;p&gt;Let's step through the constants at least:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="c1"&gt;# here&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to figure out the transfer function for &lt;code&gt;add&lt;/code&gt;. It's kind of tricky
right now because we haven't specified our abstract domain very well. I keep
saying "numbers", but what kinds of numbers? Integers? Real numbers? Floating
point? Some kind of fixed-width bit vector (&lt;code&gt;int8&lt;/code&gt;, &lt;code&gt;uint32&lt;/code&gt;, ...) like an
actual machine "integer"?&lt;/p&gt;
&lt;p&gt;For this post, I am going to use the mathematical definition of integer, which
means that the values are not bounded in size and therefore do not overflow.
Actual hardware memory constraints aside, this is kind of like a Python &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So let's look at what happens when we add two abstract numbers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;top&lt;/th&gt;
&lt;th&gt;positive&lt;/th&gt;
&lt;th&gt;negative&lt;/th&gt;
&lt;th&gt;bottom&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;top&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;positive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;positive&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;negative&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;negative&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;bottom&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;td&gt;bottom&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As an example, let's try to add two numbers &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, where &lt;code&gt;a&lt;/code&gt; is positive
and &lt;code&gt;b&lt;/code&gt; is negative. We don't know anything about their values other than their
signs. They could be &lt;code&gt;5&lt;/code&gt; and &lt;code&gt;-3&lt;/code&gt;, where the result is &lt;code&gt;2&lt;/code&gt;, or they could be
&lt;code&gt;1&lt;/code&gt; and &lt;code&gt;-100&lt;/code&gt;, where the result is &lt;code&gt;-99&lt;/code&gt;. This is why we can't say anything
about the result of this operation and have to return &lt;em&gt;top&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The short of this table is that we only really know the result of an addition
if both operands are positive or both operands are negative. Thankfully, in
this example, both operands are known positive. So we can learn something about
&lt;code&gt;v2&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# here&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This may not seem useful in isolation, but analyzing more complex programs even
with this simple domain may be able to remove checks such as &lt;code&gt;if (v2 &amp;lt; 0) { ... }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let's take a look at another example using an sample &lt;code&gt;absval&lt;/code&gt; (absolute value)
IR operation:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;absval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;absval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;absval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Even though we have no constant/concrete values, we can still learn something
about the states of values throughout the program. Since we know that &lt;code&gt;absval&lt;/code&gt;
always returns a positive number, we learn that &lt;code&gt;v2&lt;/code&gt;, &lt;code&gt;v3&lt;/code&gt;, and &lt;code&gt;v4&lt;/code&gt; are all
positive. This means that we can optimize out the &lt;code&gt;absval&lt;/code&gt; operation on &lt;code&gt;v5&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;absval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;absval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other interesting lattices include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Constants (where the middle row is pretty wide)&lt;/li&gt;
&lt;li&gt;Range analysis (bounds on min and max of a number)&lt;/li&gt;
&lt;li&gt;Known bits (using a bitvector representation of a number, which bits are
  always 0 or 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the rest of this blog post, we are going to do a very limited version of
"known bits", called &lt;em&gt;parity&lt;/em&gt;. This analysis only tracks the least significant
bit of a number, which indicates if it is even or odd.&lt;/p&gt;
&lt;h3 id="parity"&gt;Parity&lt;/h3&gt;
&lt;p&gt;The lattice is pretty similar to the positive/negative lattice:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    top
  /     \
even    odd
  \     /
   bottom
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's define a data structure to represent this in Python code:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And instantiate the members of the lattice:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"top"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;EVEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"even"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ODD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"odd"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;BOTTOM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"bottom"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let's write a forward flow analysis of a basic block using this lattice.
We'll do that by assuming that a method on &lt;code&gt;Parity&lt;/code&gt; is defined for each IR
operation. For example, &lt;code&gt;Parity.add&lt;/code&gt;, &lt;code&gt;Parity.lshift&lt;/code&gt;, etc.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BOTTOM&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;transfer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;parity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For every operation, we compute the abstract value---the parity---of the
arguments and then call the corresponding method on &lt;code&gt;Parity&lt;/code&gt; to get the
abstract result.&lt;/p&gt;
&lt;!-- TODO maybe learn more about different IRs and how they do constants.
apparently pypy/llvm are free-floating; cinder is not --&gt;
&lt;p&gt;We need to special case &lt;code&gt;Constant&lt;/code&gt;s due to a quirk of how the Toy IR is
constructed: the constants don't appear in the instruction stream and instead
are free-floating.&lt;/p&gt;
&lt;p&gt;Let's start by looking at the abstraction function for concrete
values---constants:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ODD&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Seems reasonable enough. Let's pause on operations for a moment and consider an
example program:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function (which is admittedly a little contrived) takes two inputs, shifts
them left by one bit, adds the result, and then checks the least significant
bit of the addition result. It then passes that result into a &lt;code&gt;dummy&lt;/code&gt; function,
which you can think of as "return" or "escape".&lt;/p&gt;
&lt;p&gt;To do some abstract interpretation on this program, we'll need to implement the
transfer functions for &lt;code&gt;lshift&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; (&lt;code&gt;dummy&lt;/code&gt; will just always return
&lt;code&gt;TOP&lt;/code&gt;). We'll start with &lt;code&gt;add&lt;/code&gt;. Remember that adding two even numbers returns
an even number, adding two odd numbers returns an even number, and mixing even
and odd returns an odd number.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;BOTTOM&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;BOTTOM&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ODD&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ODD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ODD&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We also need to fill in the other cases where the operands are &lt;em&gt;top&lt;/em&gt; or
&lt;em&gt;bottom&lt;/em&gt;. In this case, they are both "contagious"; if either operand is
bottom, the result is as well. If neither is bottom but either operand is top,
the result is as well.&lt;/p&gt;
&lt;p&gt;Now let's look at &lt;code&gt;lshift&lt;/code&gt;. Shifting any number left by a non-zero number of
bits will always result in an even number, but we need to be careful about the
zero case! Shifting by zero doesn't change the number at all. Unfortunately,
since our lattice has no notion of zero, we have to over-approximate here:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# self &amp;lt;&amp;lt; other&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ODD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means that we will miss some opportunities to optimize, but it's a
tradeoff that's just part of the game. (We could also add more elements to our
lattice, but that's a topic for another day.)&lt;/p&gt;
&lt;p&gt;Now, if we run our abstract interpretation, we'll collect some interesting
properties about the program. If we temporarily hack on the internals of
&lt;code&gt;bb_to_str&lt;/code&gt;, we can print out parity information alongside the IR operations:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is pretty awesome, because we can see that &lt;code&gt;v4&lt;/code&gt;, the result of the
addition, is &lt;em&gt;always&lt;/em&gt; even. Maybe we can do something with that information.&lt;/p&gt;
&lt;h3 id="optimization"&gt;Optimization&lt;/h3&gt;
&lt;p&gt;One way that a program might check if a number is odd is by checking the least
significant bit. This is a common pattern in C code, where you might see code
like &lt;code&gt;y = x &amp;amp; 1&lt;/code&gt;. Let's introduce a &lt;code&gt;bitand&lt;/code&gt; IR operation that acts like the
&lt;code&gt;&amp;amp;&lt;/code&gt; operator in C/Python. Here is an example of use of it in our program:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# new!&lt;/span&gt;
&lt;span class="n"&gt;v6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We'll hold off on implementing the transfer function for it---that's left as an
exercise for the reader---and instead do something different.&lt;/p&gt;
&lt;p&gt;Instead, we'll see if we can optimize operations of the form &lt;code&gt;bitand(X, 1)&lt;/code&gt;. If
we statically know the parity as a result of abstract interpretation, we can
replace the &lt;code&gt;bitand&lt;/code&gt; with a constant &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We'll first modify the &lt;code&gt;analyze&lt;/code&gt; function (and rename it) to return a new
&lt;code&gt;Block&lt;/code&gt; containing optimized instructions:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BOTTOM&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# TODO: Optimize op&lt;/span&gt;
        &lt;span class="c1"&gt;# Emit&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Analyze&lt;/span&gt;
        &lt;span class="n"&gt;transfer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;parity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We're approaching this the way that PyPy does things under the hood, which is
all in roughly a single pass. It tries to optimize an instruction away, and if
it can't, it copies it into the new block.&lt;/p&gt;
&lt;p&gt;Now let's add in the &lt;code&gt;bitand&lt;/code&gt; optimization. It's mostly some gross-looking
pattern matching that checks if the right hand side of a bitwise &lt;code&gt;and&lt;/code&gt;
operation is &lt;code&gt;1&lt;/code&gt; (TODO: the left hand side, too). CF had some neat ideas on how
to make this more ergonomic, which I might save for later.&lt;sup id="fnref:match-args"&gt;&lt;a class="footnote-ref" href="https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html#fn:match-args"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Then, if we know the parity, optimize the &lt;code&gt;bitand&lt;/code&gt; into a constant.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;simplify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BOTTOM&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Try to simplify&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"bitand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;EVEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ODD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="c1"&gt;# Emit&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Analyze&lt;/span&gt;
        &lt;span class="n"&gt;transfer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Parity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parity_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;parity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remember: because we use union-find to rewrite instructions in the optimizer
(&lt;code&gt;make_equal_to&lt;/code&gt;), later uses of the same instruction get the new
optimized version "for free" (&lt;code&gt;find&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Let's see how it works on our IR:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;v0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;v6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hey, neat! &lt;code&gt;bitand&lt;/code&gt; disappeared and the argument to &lt;code&gt;dummy&lt;/code&gt; is now the constant
&lt;code&gt;0&lt;/code&gt; because we know the lowest bit.&lt;/p&gt;
&lt;h3 id="wrapping-up"&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;Hopefully you have gained a little bit of an intuitive understanding of
abstract interpretation. Last year, being able to write some code made me more
comfortable with the math. Now being more comfortable with the math is helping
me write the code. It's nice upward spiral.&lt;/p&gt;
&lt;p&gt;The two abstract domains we used in this post are simple and not very useful in
practice but it's possible to get very far using slightly more complicated
abstract domains. Common domains include: constant propagation, type inference,
range analysis, effect inference, liveness, etc. For example, here is a a
sample lattice for constant propagation:&lt;/p&gt;
&lt;figure style="display: block; margin: 0 auto;"&gt;
&lt;!--
digraph G {
    rankdir="BT";
    top [shape=Msquare];
    bottom [shape=Msquare];

    bottom -&gt; "-inf";
    bottom -&gt; "-2";
    bottom -&gt; "-1";
    bottom -&gt; 0;
    bottom -&gt; 1;
    bottom -&gt; 2;
    bottom -&gt; "+inf";

    "-inf" -&gt; negative;
    "-2" -&gt; negative;
    "-1" -&gt; negative;
    0 -&gt; top;
    1 -&gt; nonnegative;
    2 -&gt; nonnegative;
    "+inf" -&gt; nonnegative;

    negative -&gt; nonzero;
    nonnegative -&gt; nonzero;
    nonzero-&gt;top;

    {rank=same; "-inf"; "-2"; "-1"; 0; 1; 2; "+inf"}
    {rank=same; nonnegative; negative;}
}
--&gt;
    &lt;object class="svg" type="image/svg+xml" data="https://www.pypy.org/images/2024-complex-lattice.svg"&gt;
    &lt;/object&gt;
&lt;/figure&gt;

&lt;p&gt;It has multiple levels to indicate more and less precision. For example, you
might learn that a variable is either &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; and be able to encode that as
&lt;code&gt;nonnegative&lt;/code&gt; instead of just going straight to &lt;code&gt;top&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check out some real-world abstract interpretation in open source projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/KnownBits.cpp"&gt;Known bits in LLVM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/llvm/llvm-project/blob/main/llvm/lib/IR/ConstantRange.cpp"&gt;Constant range in LLVM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;But I am told that the ranges don't form a lattice (see &lt;a href="https://dl.acm.org/doi/10.1145/2651360"&gt;Interval Analysis and Machine Arithmetic: Why Signedness Ignorance Is Bliss&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/kernel/bpf/tnum.c"&gt;Tristate numbers for known bits in Linux eBPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/torvalds/linux/blob/28bbe4ea686a023929d907cc168430b61094811c/kernel/bpf/verifier.c#L13335"&gt;Range analysis in Linux eBPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bminor/binutils-gdb/blob/master/gdb/prologue-value.c"&gt;GDB prologue analysis&lt;/a&gt;
  of assembly to understand the stack and find frame pointers without using
  DWARF (&lt;a href="https://sourceware.org/gdb/wiki/Internals/Prologue%20Analysis"&gt;some
  docs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have some readable examples, please share them so I can add.&lt;/p&gt;
&lt;h3 id="acknowledgements"&gt;Acknowledgements&lt;/h3&gt;
&lt;p&gt;Thank you to &lt;a href="https://cfbolz.de/"&gt;CF Bolz-Tereick&lt;/a&gt; for the toy optimizer and
helping edit this post!&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:logozzo"&gt;
&lt;p&gt;In the words of abstract interpretation researchers Vincent Laviron
and Francesco Logozzo in their paper &lt;em&gt;Refining Abstract
Interpretation-based Static Analyses with Hints&lt;/em&gt; (APLAS 2009):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The three main elements of an abstract interpretation are: (i) the
abstract elements ("which properties am I interested in?"); (ii) the
abstract transfer functions ("which is the abstract semantics of basic
statements?"); and (iii) the abstract operations ("how do I combine the
abstract elements?").&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We don't have any of these "abstract operations" in this post because
there's no control flow but you can read about them elsewhere! &lt;a class="footnote-backref" href="https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html#fnref:logozzo" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:lattices"&gt;
&lt;p&gt;These abstract values are arranged in a &lt;em&gt;lattice&lt;/em&gt;, which is a
mathematical structure with some properties but the most important ones are
that it has a top, a bottom, a partial order, a meet operation, and values
can only move in one direction on the lattice.&lt;/p&gt;
&lt;p&gt;Using abstract values from a lattice promises two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The analysis will terminate&lt;/li&gt;
&lt;li&gt;The analysis will be correct for &lt;em&gt;any&lt;/em&gt; run of the program, not just one
  sample run&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="footnote-backref" href="https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html#fnref:lattices" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:match-args"&gt;
&lt;p&gt;Something about &lt;code&gt;__match_args__&lt;/code&gt; and &lt;code&gt;@property&lt;/code&gt;... &lt;a class="footnote-backref" href="https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html#fnref:match-args" title="Jump back to footnote 3 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>toy-optimizer</category><guid>https://www.pypy.org/posts/2024/07/toy-abstract-interpretation.html</guid><pubDate>Wed, 24 Jul 2024 14:48:00 GMT</pubDate></item><item><title>Allocation Removal in the Toy Optimizer</title><link>https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;p&gt;One of the workhorse optimization of RPython's tracing JIT is &lt;a class="reference external" href="https://dl.acm.org/doi/10.1145/1929501.1929508"&gt;allocation
removal&lt;/a&gt;, which removes short-lived object allocation from traces. Many Python
programs create a lot of objects that only live for a short time, and whose
lifespan is fully predictable (common examples are integer and float boxes, but
also tuples, frames, intermediate string results, etc). Allocation removal will
try (and very often succeed) to remove these allocations from traces. In
this blog post I want to show a toy version of how allocation removal is
implemented.&lt;/p&gt;
&lt;p&gt;In the &lt;a class="reference external" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html"&gt;previous&lt;/a&gt; blog post of this series I showed the complete code for
writing a toy one-pass optimizer that does constant folding, common
subexpression elimination and strength reduction. In this
second post, I want to use allocation removal as a more advanced optimization
pass. The basic optimization framework is the same, we will use the same
datastructures for intermediate representation and also keep using the same
union find data structure to store equivalences between IR operations. Here's
the infrastructure code from the last post:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-1" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-1"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pytest&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-2" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-2"&gt;&lt;/a&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;typing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-3" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-4" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-4"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-5" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-5"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-6" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-7" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abstract"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-8" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-8"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-9" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-9"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-10" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-10"&gt;&lt;/a&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abstract"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-11" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-11"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-12" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-12"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-13" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-13"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-14" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-14"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-15" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-15"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-16" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-16"&gt;&lt;/a&gt;    &lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-17" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-17"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-18" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-18"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-19" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-19"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-20" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-20"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-21" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-21"&gt;&lt;/a&gt;&lt;span class="hll"&gt;
&lt;/span&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-22" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-22"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-23" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-23"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-24" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-24"&gt;&lt;/a&gt;            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Operation(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, "&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-25" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-25"&gt;&lt;/a&gt;            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, "&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-26" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-26"&gt;&lt;/a&gt;            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-27" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-27"&gt;&lt;/a&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-28" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-28"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-29" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-29" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-29"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-30" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-30" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-30"&gt;&lt;/a&gt;        &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-31" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-31" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-31"&gt;&lt;/a&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-32" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-32" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-32"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-33" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-33" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-33"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-34" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-34" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-34"&gt;&lt;/a&gt;                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-35" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-35" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-35"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-36" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-36" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-36"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-37" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-37" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-37"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-38" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-38" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-38"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-39" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-39" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-39"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-40" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-40" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-40"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-41" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-41" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-41"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-42" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-42" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-42"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-43" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-43" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-43"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-44" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-44" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-44"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-45" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-45" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-45"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-46" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-46" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-46"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-47" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-47" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-47"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-48" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-48" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-48"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-49" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-49" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-49"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-50" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-50" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-50"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-51" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-51" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-51"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-52" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-52" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-52"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-53" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-53" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-53"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Constant(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-54" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-54" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-54"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-55" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-55" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-55"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-56" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-56" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-56"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-57" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-57" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-57"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-58" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-58" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-58"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-59" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-59" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-59"&gt;&lt;/a&gt;        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-60" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-60" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-60"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-61" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-61" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-61"&gt;&lt;/a&gt;            &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-62" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-62" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-62"&gt;&lt;/a&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-63" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-63" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-63"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-64" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-64" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-64"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-65" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-65" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-65"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-66" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-66" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-66"&gt;&lt;/a&gt;        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wraparg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-67" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-67" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-67"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-68" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-68" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-68"&gt;&lt;/a&gt;                &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-69" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-69" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-69"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-70" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-70" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-70"&gt;&lt;/a&gt;        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-71" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-71" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-71"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# construct an Operation, wrap the&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-72" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-72" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-72"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# arguments in Constants if necessary&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-73" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-73" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-73"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-74" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-74" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-74"&gt;&lt;/a&gt;                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wraparg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-75" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-75" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-75"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# add it to self, the basic block&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-76" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-76" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-76"&gt;&lt;/a&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-77" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-77" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-77"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-78" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-78" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-78"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-79" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-79" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-79"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-80" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-80" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-80"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# a bunch of operations we support&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-81" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-81" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-81"&gt;&lt;/a&gt;    &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-82" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-82" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-82"&gt;&lt;/a&gt;    &lt;span class="n"&gt;mul&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mul"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-83" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-83" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-83"&gt;&lt;/a&gt;    &lt;span class="n"&gt;getarg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"getarg"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-84" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-84" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-84"&gt;&lt;/a&gt;    &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dummy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-85" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-85" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-85"&gt;&lt;/a&gt;    &lt;span class="n"&gt;lshift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lshift"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-86" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-86" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-86"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# some new one for this post&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-87" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-87" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-87"&gt;&lt;/a&gt;    &lt;span class="n"&gt;alloc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"alloc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-88" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-88" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-88"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-89" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-89" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-89"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-90" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-90" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-90"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"print"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-91" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-91" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-91"&gt;&lt;/a&gt;&lt;span class="hll"&gt;
&lt;/span&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-92" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-92" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-92"&gt;&lt;/a&gt;&lt;span class="hll"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;varprefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"var"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-93" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-93" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-93"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-94" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-94" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-94"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-95" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-95" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-95"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-96" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-96" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-96"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-97" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-97" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-97"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;varnames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-98" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-98" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-98"&gt;&lt;/a&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-99" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-99" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-99"&gt;&lt;/a&gt;    &lt;span class="n"&gt;varnames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-100" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-100" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-100"&gt;&lt;/a&gt;    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-101" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-101" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-101"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-102" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-102" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-102"&gt;&lt;/a&gt;        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;varprefix&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-103" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-103" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-103"&gt;&lt;/a&gt;        &lt;span class="n"&gt;varnames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-104" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-104" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-104"&gt;&lt;/a&gt;        &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-105" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-105" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-105"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-106" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-106" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-106"&gt;&lt;/a&gt;                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-107" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-107" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-107"&gt;&lt;/a&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-108" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-108" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-108"&gt;&lt;/a&gt;        &lt;span class="n"&gt;strop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-109" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-109" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-109"&gt;&lt;/a&gt;        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_14f1512018fc4a52ad9a06b277b752f6-110" name="rest_code_14f1512018fc4a52ad9a06b277b752f6-110" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_14f1512018fc4a52ad9a06b277b752f6-110"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are two changes to the code from the last post: &lt;code class="docutils literal"&gt;Operation&lt;/code&gt; instances
have a new &lt;code class="docutils literal"&gt;.info&lt;/code&gt; field, which is set to &lt;code class="docutils literal"&gt;None&lt;/code&gt; by default. We will learn
how the info field is used a bit further down. Also, we define some new
operations.&lt;/p&gt;
&lt;section id="interpreter"&gt;
&lt;h2&gt;Interpreter&lt;/h2&gt;
&lt;p&gt;In this post we will mainly concern ourselves with optimizing
programs that allocate memory. We assume that our language is garbage collected
and memory safe. The new operations that we will optimize are &lt;code class="docutils literal"&gt;alloc&lt;/code&gt;
(allocates some new object), &lt;code class="docutils literal"&gt;store&lt;/code&gt; (stores a value into a fixed field of an
object), &lt;code class="docutils literal"&gt;load&lt;/code&gt; (loads the value from a field in the object).&lt;/p&gt;
&lt;p&gt;We are leaving out a lot of details of a "real" system here, usually an
&lt;code class="docutils literal"&gt;alloc&lt;/code&gt; operation would get some extra information, for example the type of
the freshly allocated object or at least its size. &lt;code class="docutils literal"&gt;load&lt;/code&gt; and &lt;code class="docutils literal"&gt;store&lt;/code&gt; would
typically have some kind of field offset and maybe some information about the
field's type&lt;/p&gt;
&lt;p&gt;Here's a simple program that uses these operations:&lt;/p&gt;
&lt;pre class="literal-block"&gt;var0 = getarg(0)
obj0 = alloc()
store(obj0, 0, var0)
var1 = load(obj0, 0)
print(var1)&lt;/pre&gt;
&lt;p&gt;The code allocates a new object &lt;code class="docutils literal"&gt;obj0&lt;/code&gt;, stores &lt;code class="docutils literal"&gt;var0&lt;/code&gt; into field &lt;code class="docutils literal"&gt;0&lt;/code&gt; of
the object, the loads the same field and prints the result of the load.&lt;/p&gt;
&lt;p&gt;Before we get started in writing the optimizer for these operations, let's try
to understand the semantics of the new operations a bit better. To do this, we
can sketch a small interpreter for basic blocks, supporting only &lt;code class="docutils literal"&gt;getarg&lt;/code&gt;,
&lt;code class="docutils literal"&gt;alloc&lt;/code&gt;, &lt;code class="docutils literal"&gt;store&lt;/code&gt;, &lt;code class="docutils literal"&gt;load&lt;/code&gt;, &lt;code class="docutils literal"&gt;print&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-1" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_interpret&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-2" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-3" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-4" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-5" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-6" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-7" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-8" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;interpret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-9" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-9"&gt;&lt;/a&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-10" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-10"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-11" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-11"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-12" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-12"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-13" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-13"&gt;&lt;/a&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-14" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-14"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-15" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-15"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-16" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-16"&gt;&lt;/a&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-17" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-17"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-18" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-18"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-19" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-19"&gt;&lt;/a&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-20" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-20"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-21" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-21"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-22" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-22"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-23" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-23"&gt;&lt;/a&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-24" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-24"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;interpret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-25" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-25"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;argval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-26" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-26"&gt;&lt;/a&gt;        &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-27" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-27"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-28" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-28"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-29" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-29" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-29"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-30" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-30" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-30"&gt;&lt;/a&gt;            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-31" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-31" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-31"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-32" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-32" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-32"&gt;&lt;/a&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-33" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-33" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-33"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-34" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-34" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-34"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"getarg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-35" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-35" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-35"&gt;&lt;/a&gt;            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-36" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-36" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-36"&gt;&lt;/a&gt;        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-37" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-37" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-37"&gt;&lt;/a&gt;            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-38" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-38" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-38"&gt;&lt;/a&gt;        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-39" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-39" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-39"&gt;&lt;/a&gt;            &lt;span class="n"&gt;fieldnum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-40" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-40" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-40"&gt;&lt;/a&gt;            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldnum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-41" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-41" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-41"&gt;&lt;/a&gt;        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-42" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-42" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-42"&gt;&lt;/a&gt;            &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-43" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-43" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-43"&gt;&lt;/a&gt;            &lt;span class="n"&gt;fieldnum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-44" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-44" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-44"&gt;&lt;/a&gt;            &lt;span class="n"&gt;fieldvalue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-45" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-45" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-45"&gt;&lt;/a&gt;            &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldvalue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-46" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-46" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-46"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# no result, only side effect&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-47" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-47" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-47"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-48" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-48" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-48"&gt;&lt;/a&gt;        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"print"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-49" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-49" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-49"&gt;&lt;/a&gt;            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-50" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-50" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-50"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-51" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-51" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-51"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-52" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-52" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-52"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-53" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-53" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-53"&gt;&lt;/a&gt;            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-54" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-54" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-54"&gt;&lt;/a&gt;                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not supported"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b6f0a5351b5941e5934b90dccf12feb3-55" name="rest_code_b6f0a5351b5941e5934b90dccf12feb3-55" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b6f0a5351b5941e5934b90dccf12feb3-55"&gt;&lt;/a&gt;        &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The interpreter  walks the operations of a block, executing each one in turn. It
uses the &lt;code class="docutils literal"&gt;info&lt;/code&gt; field to store the result of each already executed
&lt;code class="docutils literal"&gt;Operation&lt;/code&gt;. In this interpreter sketch we stop at the first &lt;code class="docutils literal"&gt;print&lt;/code&gt; that
we execute and return its argument for the simple but bad reason that it makes
&lt;code class="docutils literal"&gt;test_interpret&lt;/code&gt; easier to write.&lt;/p&gt;
&lt;p&gt;Objects in the interpreter are represented using a class &lt;code class="docutils literal"&gt;Object&lt;/code&gt;, which
stores the object's field into a Python dictionary. As written above, this is a
simplification, in a real system the &lt;cite&gt;alloc&lt;/cite&gt; operation might for example take
some kind of type as an argument, that describes which kinds of fields an
object has and how they are laid out in memory, which would allow more
efficient storage of the content. But we don't want to care about this level of
detail in the post, so using a dict in the interpreter is good enough.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="version-1-naive-attempt"&gt;
&lt;h2&gt;Version 1: Naive Attempt&lt;/h2&gt;
&lt;p&gt;In many programs, some allocated objects don't live for very long and have a
completely predictable lifetime. They get allocated, used for a while, and then
there is no way to reference them any more, so the garbage collector will
reclaim them. The very first example block had such an allocation:&lt;/p&gt;
&lt;pre class="literal-block"&gt;var0 = getarg(0)
obj0 = alloc()
store(obj0, 0, var0)
var1 = load(obj0, 0)
print(var1)&lt;/pre&gt;
&lt;p&gt;Here &lt;code class="docutils literal"&gt;obj0&lt;/code&gt; is written to, then read from, and then it's no longer used. We
want to optimize such programs to remove this &lt;code class="docutils literal"&gt;alloc&lt;/code&gt; operation. The optimized
version of this program would look like this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;var0 = getarg(0)
print(var0)&lt;/pre&gt;
&lt;p&gt;The &lt;code class="docutils literal"&gt;alloc&lt;/code&gt;, &lt;code class="docutils literal"&gt;store&lt;/code&gt; and &lt;code class="docutils literal"&gt;load&lt;/code&gt; operations have been completely removed.
This is a pretty important optimizations for PyPy's JIT: Allocations, memory
reads and writes are quite costly and occur &lt;em&gt;a lot&lt;/em&gt; in Python, so getting rid
of as many of them as possible is instrumental for performance.&lt;/p&gt;
&lt;p&gt;Implementing the optimization is not a lot of code! However, understanding all
the corner cases of the
optimization and making sure that the resulting program behave correctly is not
completely trivial. Therefore we will develop the optimization step by step, in
a test driven fashion: I will start each section with a new test that shows a
bug in the version of the optimization that we have so far.&lt;/p&gt;
&lt;p&gt;Let's start in a really naive way. Here's the first test we would like to
pass, using the example program above:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-1" name="rest_code_b42040adb59f474ba8a72e07453694a7-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_remove_unused_allocation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-2" name="rest_code_b42040adb59f474ba8a72e07453694a7-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-3" name="rest_code_b42040adb59f474ba8a72e07453694a7-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-4" name="rest_code_b42040adb59f474ba8a72e07453694a7-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-5" name="rest_code_b42040adb59f474ba8a72e07453694a7-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-6" name="rest_code_b42040adb59f474ba8a72e07453694a7-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-7" name="rest_code_b42040adb59f474ba8a72e07453694a7-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-8" name="rest_code_b42040adb59f474ba8a72e07453694a7-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-9" name="rest_code_b42040adb59f474ba8a72e07453694a7-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the virtual object looks like this:&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-10" name="rest_code_b42040adb59f474ba8a72e07453694a7-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-10"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  obj&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-11" name="rest_code_b42040adb59f474ba8a72e07453694a7-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ┌──────────┐&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-12" name="rest_code_b42040adb59f474ba8a72e07453694a7-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# │ 0: var0  │&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-13" name="rest_code_b42040adb59f474ba8a72e07453694a7-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# └──────────┘&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-14" name="rest_code_b42040adb59f474ba8a72e07453694a7-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-14"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-15" name="rest_code_b42040adb59f474ba8a72e07453694a7-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-15"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_b42040adb59f474ba8a72e07453694a7-16" name="rest_code_b42040adb59f474ba8a72e07453694a7-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_b42040adb59f474ba8a72e07453694a7-16"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = print(optvar0)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We will define a class &lt;code class="docutils literal"&gt;VirtualObject&lt;/code&gt; that is basically identical to
&lt;code class="docutils literal"&gt;Object&lt;/code&gt; above. But it will not be used by the interpreter, instead we will
use it during optimization.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-1" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VirtualObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-2" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-3" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-3"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-4" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-4"&gt;&lt;/a&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-5" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-6" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-6"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-7" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-7"&gt;&lt;/a&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-8" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_85dd782c01dd4c6a90ae22e49c56a539-9" name="rest_code_85dd782c01dd4c6a90ae22e49c56a539-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_85dd782c01dd4c6a90ae22e49c56a539-9"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The structure of the optimizer is going to be like those in the first blog post.
The optimizer makes a single pass over all operations. It removes some and
emits others.&lt;/p&gt;
&lt;p&gt;This first version of the allocation removal optimizer is going to be extremely
optimistic. It simply assumes that &lt;em&gt;all&lt;/em&gt; the allocations in the program can be
optimized away. That is not realistic in practice. We will have to
refine this approach later, but it's a good way to start. That means whenever
the optimizer sees an &lt;code class="docutils literal"&gt;alloc&lt;/code&gt; operation, it removes it and creates a
&lt;code class="docutils literal"&gt;VirtualObject&lt;/code&gt; object which stores the information that is known during
optimization about the result of the &lt;code class="docutils literal"&gt;alloc&lt;/code&gt;. Like in the interpreter, the
&lt;code class="docutils literal"&gt;VirtualObject&lt;/code&gt; is stored in the &lt;code class="docutils literal"&gt;.info&lt;/code&gt; field of the &lt;code class="docutils literal"&gt;Operation&lt;/code&gt; instance
that represents the &lt;code class="docutils literal"&gt;alloc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When the optimizer sees a &lt;code class="docutils literal"&gt;store&lt;/code&gt; operation, it will also remove it and
instead execute the store by calling the &lt;code class="docutils literal"&gt;VirtualObject.store&lt;/code&gt; method.
Here is one important difference between the interpreter and the optimizer: In
the interpreter, the values that were stored into an &lt;code class="docutils literal"&gt;Object&lt;/code&gt; (and thus
put into the object's &lt;code class="docutils literal"&gt;.contents&lt;/code&gt; dictionary) were runtime values, for
example integers or other objects. In the optimizer however, the
fields of the &lt;code class="docutils literal"&gt;VirtualObject&lt;/code&gt; store &lt;code class="docutils literal"&gt;Value&lt;/code&gt; instances, either &lt;code class="docutils literal"&gt;Constant&lt;/code&gt;
instances or &lt;code class="docutils literal"&gt;Operation&lt;/code&gt; instances.&lt;/p&gt;
&lt;p&gt;When the optimizer sees a &lt;code class="docutils literal"&gt;load&lt;/code&gt; operation, it &lt;em&gt;also&lt;/em&gt; removes it, and replaces
the &lt;code class="docutils literal"&gt;load&lt;/code&gt; with the &lt;code class="docutils literal"&gt;Operation&lt;/code&gt; (or &lt;code class="docutils literal"&gt;Constant&lt;/code&gt;) that is stored in the
&lt;code class="docutils literal"&gt;VirtualObject&lt;/code&gt; at that point:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-1" name="rest_code_e82ff091dd424204a92929eb24403b2b-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-2" name="rest_code_e82ff091dd424204a92929eb24403b2b-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-3" name="rest_code_e82ff091dd424204a92929eb24403b2b-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-4" name="rest_code_e82ff091dd424204a92929eb24403b2b-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-5" name="rest_code_e82ff091dd424204a92929eb24403b2b-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-5"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VirtualObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-6" name="rest_code_e82ff091dd424204a92929eb24403b2b-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-6"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-7" name="rest_code_e82ff091dd424204a92929eb24403b2b-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-8" name="rest_code_e82ff091dd424204a92929eb24403b2b-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-8"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-9" name="rest_code_e82ff091dd424204a92929eb24403b2b-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-9"&gt;&lt;/a&gt;            &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-10" name="rest_code_e82ff091dd424204a92929eb24403b2b-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-10"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-11" name="rest_code_e82ff091dd424204a92929eb24403b2b-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-11"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-12" name="rest_code_e82ff091dd424204a92929eb24403b2b-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-12"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-13" name="rest_code_e82ff091dd424204a92929eb24403b2b-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-13"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-14" name="rest_code_e82ff091dd424204a92929eb24403b2b-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-14"&gt;&lt;/a&gt;            &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-15" name="rest_code_e82ff091dd424204a92929eb24403b2b-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-15"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-16" name="rest_code_e82ff091dd424204a92929eb24403b2b-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-16"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-17" name="rest_code_e82ff091dd424204a92929eb24403b2b-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-17"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_e82ff091dd424204a92929eb24403b2b-18" name="rest_code_e82ff091dd424204a92929eb24403b2b-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e82ff091dd424204a92929eb24403b2b-18"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the first version of the optimization. It doesn't handle all kinds of
difficult cases, and we'll have to do something about its optimism.
But, already in this minimalistic form, we can write a slightly more complicated
test with two allocations, one object pointing to the other. It works correctly
too, both allocations are removed:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-1" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_remove_two_allocations&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-2" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-3" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-4" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-5" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-6" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-7" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-8" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-9" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-10" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-11" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the virtual objects look like this:&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-12" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  obj0&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-13" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ┌──────┐&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-14" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-14"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# │ 0: ╷ │&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-15" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-15"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# └────┼─┘&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-16" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#      │&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-17" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-17"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#      ▼&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-18" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-18"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#     obj1&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-19" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-19"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   ┌─────────┐&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-20" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-20"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   │ 0: var0 │&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-21" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-21"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   └─────────┘&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-22" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-22"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# therefore&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-23" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-23"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var1 is the same as obj0&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-24" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-24"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var2 is the same as var0&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-25" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-25"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-26" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-26"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-27" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-27"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-28" name="rest_code_83b582dc6f714a9bb0a8c628c0d9a052-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_83b582dc6f714a9bb0a8c628c0d9a052-28"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = print(optvar0)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="version-2-re-materializing-allocations"&gt;
&lt;h2&gt;Version 2: Re-Materializing Allocations&lt;/h2&gt;
&lt;p&gt;To make it easier to talk about how the optimizer operates, let's introduce
some terminology. As already seen by the choice
of the class name &lt;code class="docutils literal"&gt;VirtualObject&lt;/code&gt;, we will call an object &lt;strong&gt;virtual&lt;/strong&gt; if the
optimizer has optimized away the &lt;code class="docutils literal"&gt;alloc&lt;/code&gt; operation that creates the object.
Other objects are equivalently &lt;strong&gt;not virtual&lt;/strong&gt;, for example those that have
existed before we enter the current code block.&lt;/p&gt;
&lt;p&gt;The first problem that we need to fix is the assumption that every
allocation can be removed. So far we only looked at small programs where every
allocation could be removed, or equivalently, where every object is virtual.
A program that creates virtual objects, stores into and loads from them, and
then forgets the objects. In this simple case removing the allocations is fine.
As we saw in the previous section, it's also fine to have a virtual object
reference another virtual, both allocations can be removed.&lt;/p&gt;
&lt;p&gt;What are the cases were we &lt;em&gt;can't&lt;/em&gt; remove an allocation?
The first version of the optimizer simply assumed that every allocation can be
removed. This can't work. We will replace this assumption with the following
simple heuristic:&lt;/p&gt;
&lt;p&gt;If a reference to a virtual object &lt;code class="docutils literal"&gt;a&lt;/code&gt; is stored into an object &lt;code class="docutils literal"&gt;b&lt;/code&gt;
that is not virtual, then &lt;code class="docutils literal"&gt;a&lt;/code&gt; will also stop being virtual. If an object &lt;code class="docutils literal"&gt;a&lt;/code&gt;
that was virtual stops being virtual, we say that it &lt;strong&gt;escapes&lt;/strong&gt;. &lt;a class="reference internal" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#target-4"&gt;¹&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The simplest test case for this happening looks like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-1" name="rest_code_5fa8825383164c2db0c5896ed9b83919-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_materialize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-2" name="rest_code_5fa8825383164c2db0c5896ed9b83919-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-3" name="rest_code_5fa8825383164c2db0c5896ed9b83919-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-4" name="rest_code_5fa8825383164c2db0c5896ed9b83919-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-5" name="rest_code_5fa8825383164c2db0c5896ed9b83919-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-6" name="rest_code_5fa8825383164c2db0c5896ed9b83919-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-7" name="rest_code_5fa8825383164c2db0c5896ed9b83919-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-7"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  obj is virtual, without any fields&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-8" name="rest_code_5fa8825383164c2db0c5896ed9b83919-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-8"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ┌───────┐&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-9" name="rest_code_5fa8825383164c2db0c5896ed9b83919-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# │ empty │&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-10" name="rest_code_5fa8825383164c2db0c5896ed9b83919-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-10"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# └───────┘&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-11" name="rest_code_5fa8825383164c2db0c5896ed9b83919-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# then we store a reference to obj into&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-12" name="rest_code_5fa8825383164c2db0c5896ed9b83919-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# field 0 of var0. Since var0 is not virtual,&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-13" name="rest_code_5fa8825383164c2db0c5896ed9b83919-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# obj escapes, so we have to put it back&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-14" name="rest_code_5fa8825383164c2db0c5896ed9b83919-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-14"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# into the optimized basic block&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-15" name="rest_code_5fa8825383164c2db0c5896ed9b83919-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-15"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-16" name="rest_code_5fa8825383164c2db0c5896ed9b83919-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-16"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-17" name="rest_code_5fa8825383164c2db0c5896ed9b83919-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-17"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-18" name="rest_code_5fa8825383164c2db0c5896ed9b83919-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-18"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = store(optvar0, 0, optvar1)"""&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-19" name="rest_code_5fa8825383164c2db0c5896ed9b83919-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-19"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# so far, fails like this:&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-20" name="rest_code_5fa8825383164c2db0c5896ed9b83919-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-20"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the line:&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-21" name="rest_code_5fa8825383164c2db0c5896ed9b83919-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-21"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# info.store(field, op.arg(2))&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-22" name="rest_code_5fa8825383164c2db0c5896ed9b83919-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-22"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# produces an AttributeError because info&lt;/span&gt;
&lt;a id="rest_code_5fa8825383164c2db0c5896ed9b83919-23" name="rest_code_5fa8825383164c2db0c5896ed9b83919-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_5fa8825383164c2db0c5896ed9b83919-23"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# is None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the optimizer reaches a point where a virtual object escapes (like the
&lt;code class="docutils literal"&gt;store&lt;/code&gt; operation in the test), the optimizer has already removed the &lt;code class="docutils literal"&gt;alloc&lt;/code&gt;
operation that created the virtual object. If the object escapes, we don't want
to go back in the operations list and re-insert the &lt;code class="docutils literal"&gt;alloc&lt;/code&gt; operation, that
sounds potentially very complicated. Instead, we re-insert the &lt;code class="docutils literal"&gt;alloc&lt;/code&gt;
operation that will recreate the virtual object at the point of escape using a
helper function &lt;code class="docutils literal"&gt;materialize&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-1" name="rest_code_e3afb755432e43ab848115f87fec0669-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-1"&gt;&lt;/a&gt;&lt;span class="hll"&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-2" name="rest_code_e3afb755432e43ab848115f87fec0669-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-2"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-3" name="rest_code_e3afb755432e43ab848115f87fec0669-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-3"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-4" name="rest_code_e3afb755432e43ab848115f87fec0669-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-4"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-5" name="rest_code_e3afb755432e43ab848115f87fec0669-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-5"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VirtualObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-6" name="rest_code_e3afb755432e43ab848115f87fec0669-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-6"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-7" name="rest_code_e3afb755432e43ab848115f87fec0669-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-7"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="c1"&gt;# put the alloc operation back into the trace&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_e3afb755432e43ab848115f87fec0669-8" name="rest_code_e3afb755432e43ab848115f87fec0669-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_e3afb755432e43ab848115f87fec0669-8"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I've added a number of fairly strong assertions to &lt;code class="docutils literal"&gt;materialize&lt;/code&gt; to encode our
current assumptions about the situations in which it expects to be called. We
will remove some of them later as we generalize the code.&lt;/p&gt;
&lt;p&gt;Now that we have &lt;code class="docutils literal"&gt;materialize&lt;/code&gt; we need to change &lt;code class="docutils literal"&gt;optimize_alloc_removal&lt;/code&gt; to
recognize the case of storing a virtual object into a non-virtual one. We can
recognize &lt;code class="docutils literal"&gt;Operation&lt;/code&gt; instances that produced a virtual object by looking at
their &lt;code class="docutils literal"&gt;.info&lt;/code&gt; field. If it is &lt;code class="docutils literal"&gt;None&lt;/code&gt;, the object is not virtual, otherwise
it is. If we store something into a virtual object, we leave the code as above.
If we store a virtual object into an object that is not virtual, we will first
materialize the virtual object, and then emit the store.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-1" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-2" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-3" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-4" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-5" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-5"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VirtualObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-6" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-6"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-7" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-8" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-8"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-9" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-9"&gt;&lt;/a&gt;            &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-10" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-10"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-11" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-11"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-12" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-12"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-13" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-13"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-14" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-14"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# virtual&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-15" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-15"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-16" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-16"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-17" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-17"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-18" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-18"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# not virtual&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-19" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-19"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="c1"&gt;# first materialize the&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-20" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-20"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="c1"&gt;# right hand side&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-21" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-21"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="n"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-22" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-22"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="c1"&gt;# then emit the store via&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-23" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-23"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="c1"&gt;# the general path below&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-24" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-24"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ba0da6ce82554eebab71a21e7ba16d76-25" name="rest_code_ba0da6ce82554eebab71a21e7ba16d76-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ba0da6ce82554eebab71a21e7ba16d76-25"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the general idea, and it is enough to pass &lt;code class="docutils literal"&gt;test_materialize&lt;/code&gt;. But of
course there are still a number of further problems that we now need to solve.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="version-3-don-t-materialize-twice"&gt;
&lt;h2&gt;Version 3: Don't Materialize Twice&lt;/h2&gt;
&lt;p&gt;The first problem is the fact that after we materialize a virtual object, it is
no longer virtual. So if it escapes a second time, it should &lt;em&gt;not&lt;/em&gt; be
materialized a second time. A test for that case could simply repeat the
&lt;code class="docutils literal"&gt;store&lt;/code&gt; operation:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-1" name="rest_code_bc03fea5b9f144809a39084621800bf2-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_dont_materialize_twice&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-2" name="rest_code_bc03fea5b9f144809a39084621800bf2-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# obj is again an empty virtual object,&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-3" name="rest_code_bc03fea5b9f144809a39084621800bf2-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# and we store it into var0 *twice*.&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-4" name="rest_code_bc03fea5b9f144809a39084621800bf2-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-4"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# this should only materialize it once&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-5" name="rest_code_bc03fea5b9f144809a39084621800bf2-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-6" name="rest_code_bc03fea5b9f144809a39084621800bf2-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-7" name="rest_code_bc03fea5b9f144809a39084621800bf2-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-8" name="rest_code_bc03fea5b9f144809a39084621800bf2-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-9" name="rest_code_bc03fea5b9f144809a39084621800bf2-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-10" name="rest_code_bc03fea5b9f144809a39084621800bf2-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-11" name="rest_code_bc03fea5b9f144809a39084621800bf2-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-11"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-12" name="rest_code_bc03fea5b9f144809a39084621800bf2-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-12"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-13" name="rest_code_bc03fea5b9f144809a39084621800bf2-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-13"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-14" name="rest_code_bc03fea5b9f144809a39084621800bf2-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-14"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = store(optvar0, 0, optvar1)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-15" name="rest_code_bc03fea5b9f144809a39084621800bf2-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-15"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = store(optvar0, 0, optvar1)"""&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-16" name="rest_code_bc03fea5b9f144809a39084621800bf2-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# fails so far: the operations that we get&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-17" name="rest_code_bc03fea5b9f144809a39084621800bf2-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-17"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# at the moment are:&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-18" name="rest_code_bc03fea5b9f144809a39084621800bf2-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-18"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-19" name="rest_code_bc03fea5b9f144809a39084621800bf2-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-19"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-20" name="rest_code_bc03fea5b9f144809a39084621800bf2-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-20"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar2 = store(optvar0, 0, optvar1)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-21" name="rest_code_bc03fea5b9f144809a39084621800bf2-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-21"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar3 = alloc()&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-22" name="rest_code_bc03fea5b9f144809a39084621800bf2-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-22"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar4 = store(optvar0, 0, optvar3)&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-23" name="rest_code_bc03fea5b9f144809a39084621800bf2-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-23"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ie the object is materialized twice,&lt;/span&gt;
&lt;a id="rest_code_bc03fea5b9f144809a39084621800bf2-24" name="rest_code_bc03fea5b9f144809a39084621800bf2-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bc03fea5b9f144809a39084621800bf2-24"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# which is incorrect&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We solve the problem by setting the &lt;code class="docutils literal"&gt;.info&lt;/code&gt; field of an object that we
materialize to &lt;code class="docutils literal"&gt;None&lt;/code&gt; to mark it as no longer being virtual.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-1" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-2" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-3" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-4" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-5" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-5"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-6" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-6"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;# already materialized&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-7" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-7"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-8" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-8"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="c1"&gt;# put the alloc operation back into the trace&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-9" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-10" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-10"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="c1"&gt;# but only once&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-11" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-11"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-12" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-12"&gt;&lt;/a&gt;
&lt;a id="rest_code_7489affea0d942cb8af9d92b58dc37b9-13" name="rest_code_7489affea0d942cb8af9d92b58dc37b9-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_7489affea0d942cb8af9d92b58dc37b9-13"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# optimize_alloc_removal unchanged&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This fixes the problem, only one &lt;code class="docutils literal"&gt;alloc&lt;/code&gt; is created. This fix also allows
another test case to pass, one where we store a non-virtual into another
non-virtual, code which we cannot optimize at all:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-1" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_materialize_non_virtuals&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-2" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# in this example we store a non-virtual var1&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-3" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# into another non-virtual var0&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-4" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-4"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# this should just lead to no optimization at&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-5" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-5"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# all&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-6" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-7" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-8" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-9" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-10" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-11" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-11"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-12" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-12"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-13" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-13"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = getarg(1)&lt;/span&gt;
&lt;a id="rest_code_bf768ffbb40b498e8e203ac48644a41e-14" name="rest_code_bf768ffbb40b498e8e203ac48644a41e-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bf768ffbb40b498e8e203ac48644a41e-14"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = store(optvar0, 0, optvar1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="version-4-materialization-of-constants"&gt;
&lt;h2&gt;Version 4: Materialization of Constants&lt;/h2&gt;
&lt;p&gt;Another straightforward extension is to support materializing constants. A
constant is never virtual, so materializing it should do nothing.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-1" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_materialization_constants&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-2" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# in this example we store the constant 17&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-3" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# into the non-virtual var0&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-4" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-4"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# again, this will not be optimized&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-5" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-6" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-7" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-8" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-9" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the previous line fails so far, triggering&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-10" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-10"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the assert:&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-11" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# assert not isinstance(value, Constant)&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-12" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# in materialize&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-13" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-13"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-14" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-14"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_ab3a99656ea644758d30155a9d9e5e2f-15" name="rest_code_ab3a99656ea644758d30155a9d9e5e2f-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_ab3a99656ea644758d30155a9d9e5e2f-15"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = store(optvar0, 0, 17)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To implement that case, we check for &lt;code class="docutils literal"&gt;value&lt;/code&gt; being a constant and return
early:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-1" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-2" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-2"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-3" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-3"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-4" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-5" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-6" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-7" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;# already materialized&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-8" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-9" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# put the alloc operation back into the trace&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-10" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-11" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# but only once&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-12" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-12"&gt;&lt;/a&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-13" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-13"&gt;&lt;/a&gt;
&lt;a id="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-14" name="rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_cbe4902fda1f4fb4a382fad3dbf4ad3d-14"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# optimize_alloc_removal unchanged&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="version-5-materializing-fields"&gt;
&lt;h2&gt;Version 5: Materializing Fields&lt;/h2&gt;
&lt;p&gt;Now we need to solve a more difficult problem. So far, the virtual objects that
we have materialized have all been empty, meaning they didn't have any fields
written to at the point of materialization. Let's write a test for this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-1" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_materialize_fields&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-2" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-3" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-4" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-5" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-6" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;contents0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-7" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;contents1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-8" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-9" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-9"&gt;&lt;/a&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-10" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-10"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the virtual obj looks like this&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-11" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  obj&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-12" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ┌──────┬──────────┐&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-13" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# │ 0: 8 │ 1: var1  │&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-14" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-14"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# └──────┴──────────┘&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-15" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-15"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# then it needs to be materialized&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-16" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# this is the first example where a virtual&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-17" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-17"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# object that we want to materialize has any&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-18" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-18"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# content and is not just an empty object&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-19" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-19"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-20" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-20"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-21" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-21"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-22" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-22"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = getarg(1)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-23" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-23"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = alloc()&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-24" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-24"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = store(optvar2, 0, 8)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-25" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-25"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar4 = store(optvar2, 1, optvar1)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-26" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-26"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar5 = store(optvar0, 0, optvar2)"""&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-27" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-27"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# fails so far! the operations we get&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-28" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-28"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# at the moment are:&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-29" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-29" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-29"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-30" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-30" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-30"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar1 = getarg(1)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-31" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-31" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-31"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar2 = alloc()&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-32" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-32" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-32"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar3 = store(optvar0, 0, optvar2)&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-33" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-33" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-33"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# which is wrong, because the store operations&lt;/span&gt;
&lt;a id="rest_code_96d0c1fec49f4efd96b485c4ca64a403-34" name="rest_code_96d0c1fec49f4efd96b485c4ca64a403-34" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_96d0c1fec49f4efd96b485c4ca64a403-34"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# into optvar1 got lost&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To fix this problem, we need to re-create a &lt;code class="docutils literal"&gt;store&lt;/code&gt; operation for every
element of the &lt;code class="docutils literal"&gt;.contents&lt;/code&gt; dictionary of the virtual object we are
materializing. &lt;a class="reference internal" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#target-5"&gt;²&lt;/a&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-1" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-2" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-3" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-3"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-4" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-5" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-6" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-7" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;# already materialized&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-8" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-9" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# put the alloc operation back into the trace&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-10" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-11" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-11"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="c1"&gt;# put the content back&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-12" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-12"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-13" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-13"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="c1"&gt;# re-create store operation&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-14" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-14"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-15" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-15"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# only materialize once&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-16" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-16"&gt;&lt;/a&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-17" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-17"&gt;&lt;/a&gt;
&lt;a id="rest_code_8da0667ca52d48c5ab3370537ad51a6d-18" name="rest_code_8da0667ca52d48c5ab3370537ad51a6d-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_8da0667ca52d48c5ab3370537ad51a6d-18"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# optimize_alloc_removal unchanged&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is enough to pass the test.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="version-6-recursive-materialization"&gt;
&lt;h2&gt;Version 6: Recursive Materialization&lt;/h2&gt;
&lt;p&gt;In the above example, the fields of the virtual objects contained
only constants or non-virtual objects. However, we could have a situation where
a whole tree of virtual objects is built, and then the root of the tree escapes.
This makes it necessary to escape the whole tree. Let's write a test for a small
tree of two virtual objects:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-1" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_materialize_chained_objects&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-2" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-3" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-4" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-5" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-6" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-7" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-8" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-9" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  obj0&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-10" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-10"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ┌──────┐&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-11" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# │ 0: ╷ │&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-12" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# └────┼─┘&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-13" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#      │&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-14" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-14"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#      ▼&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-15" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-15"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#     obj1&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-16" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   ┌─────────┐&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-17" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-17"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   │ 0: 1337 │&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-18" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-18"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   └─────────┘&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-19" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-19"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# now obj0 escapes&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-20" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-20"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-21" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-21"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-22" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-22"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-23" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-23"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-24" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-24"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = alloc()&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-25" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-25"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = store(optvar2, 0, 1337)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-26" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-26"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar4 = store(optvar1, 0, optvar2)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-27" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-27"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar5 = store(optvar0, 0, optvar1)"""&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-28" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-28"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# fails in an annoying way! the resulting&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-29" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-29" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-29"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# basic block is not in proper SSA form&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-30" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-30" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-30"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# so printing it fails. The optimized&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-31" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-31" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-31"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# block would look like this:&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-32" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-32" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-32"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-33" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-33" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-33"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-34" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-34" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-34"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar3 = store(optvar1, 0, optvar2)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-35" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-35" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-35"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# optvar4 = store(optvar0, 0, optvar1)&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-36" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-36" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-36"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# where optvar2 is an ``alloc`` Operation&lt;/span&gt;
&lt;a id="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-37" name="rest_code_57e5b671a34a47eb9d2c34e37954d0e9-37" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_57e5b671a34a47eb9d2c34e37954d0e9-37"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# that is not itself in the output block&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To fix it, &lt;code class="docutils literal"&gt;materialize&lt;/code&gt; needs to call itself recursively for all the field
values of the virtual object:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-1" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-2" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-3" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-3"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-4" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-5" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-6" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-7" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;# already materialized&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-8" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-9" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# put the alloc operation back into the trace&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-10" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-11" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# put the content back&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-12" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-12"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-13" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-13"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="c1"&gt;# materialize recursively&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-14" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-14"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="n"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-15" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-15"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-16" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# only materialize once&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-17" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-17"&gt;&lt;/a&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-18" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-18"&gt;&lt;/a&gt;
&lt;a id="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-19" name="rest_code_68a6194ba0f24cab897ac6cd829cd8ba-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_68a6194ba0f24cab897ac6cd829cd8ba-19"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# optimize_alloc_removal unchanged&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Getting there, the materialization logic is almost done. We need to fix a
subtle remaining problem though.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="version-7-dealing-with-object-cycles"&gt;
&lt;h2&gt;Version 7: Dealing with Object Cycles&lt;/h2&gt;
&lt;p&gt;The bug we need to fix in this section is a bit tricky, and does not immediately
occur in a lot of programs. In
fact, in PyPy a variant of it was hiding out in our optimizer
until we found it much later (despite us being aware of the general problem and
correctly dealing with it in other cases).&lt;/p&gt;
&lt;p&gt;The problem is this: a virtual object can (directly or indirectly) point to
itself, and we must carefully deal with that case to avoid infinite recursion in
&lt;code class="docutils literal"&gt;materialize&lt;/code&gt;. Here's the simplest test:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-1" name="rest_code_11247ed9d2164581a997065ddbca365f-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_object_graph_cycles&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-2" name="rest_code_11247ed9d2164581a997065ddbca365f-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-3" name="rest_code_11247ed9d2164581a997065ddbca365f-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-4" name="rest_code_11247ed9d2164581a997065ddbca365f-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-5" name="rest_code_11247ed9d2164581a997065ddbca365f-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-6" name="rest_code_11247ed9d2164581a997065ddbca365f-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-7" name="rest_code_11247ed9d2164581a997065ddbca365f-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-7"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   ┌────────┐&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-8" name="rest_code_11247ed9d2164581a997065ddbca365f-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-8"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#   ▼        │&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-9" name="rest_code_11247ed9d2164581a997065ddbca365f-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  obj0      │&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-10" name="rest_code_11247ed9d2164581a997065ddbca365f-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-10"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# ┌──────┐   │&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-11" name="rest_code_11247ed9d2164581a997065ddbca365f-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-11"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# │ 0: ╷ │   │&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-12" name="rest_code_11247ed9d2164581a997065ddbca365f-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# └────┼─┘   │&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-13" name="rest_code_11247ed9d2164581a997065ddbca365f-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#      │     │&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-14" name="rest_code_11247ed9d2164581a997065ddbca365f-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-14"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#      └─────┘&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-15" name="rest_code_11247ed9d2164581a997065ddbca365f-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-15"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# obj0 points to itself, and then it is&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-16" name="rest_code_11247ed9d2164581a997065ddbca365f-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# escaped&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-17" name="rest_code_11247ed9d2164581a997065ddbca365f-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-17"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-18" name="rest_code_11247ed9d2164581a997065ddbca365f-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-18"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the previous line fails with an&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-19" name="rest_code_11247ed9d2164581a997065ddbca365f-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-19"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# InfiniteRecursionError&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-20" name="rest_code_11247ed9d2164581a997065ddbca365f-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-20"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# materialize calls itself, infinitely&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-21" name="rest_code_11247ed9d2164581a997065ddbca365f-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-21"&gt;&lt;/a&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-22" name="rest_code_11247ed9d2164581a997065ddbca365f-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-22"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# what we want is instead this output:&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-23" name="rest_code_11247ed9d2164581a997065ddbca365f-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-23"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-24" name="rest_code_11247ed9d2164581a997065ddbca365f-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-24"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-25" name="rest_code_11247ed9d2164581a997065ddbca365f-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-25"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-26" name="rest_code_11247ed9d2164581a997065ddbca365f-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-26"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = store(optvar1, 0, optvar1)&lt;/span&gt;
&lt;a id="rest_code_11247ed9d2164581a997065ddbca365f-27" name="rest_code_11247ed9d2164581a997065ddbca365f-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_11247ed9d2164581a997065ddbca365f-27"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = store(optvar0, 1, optvar1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The fix is not a big change, but a little bit subtle nevertheless.
We have to change the
order in which things are done in &lt;code class="docutils literal"&gt;materialize&lt;/code&gt;. Right after emitting the
&lt;code class="docutils literal"&gt;alloc&lt;/code&gt;, we set the &lt;code class="docutils literal"&gt;.info&lt;/code&gt; to &lt;code class="docutils literal"&gt;None&lt;/code&gt;, to mark the object as not virtual.
Only &lt;em&gt;afterwards&lt;/em&gt; do we re-create the stores and call &lt;code class="docutils literal"&gt;materialize&lt;/code&gt; recursively.
If a recursive call reaches the same object, it's already marked as non-virtual,
so &lt;code class="docutils literal"&gt;materialize&lt;/code&gt; won't recurse further:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-1" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-2" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-3" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-3"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-4" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-5" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-6" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-7" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;# already materialized&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-8" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-9" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-9"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# put the alloc operation back into the trace&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-10" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-11" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-11"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="c1"&gt;# only materialize once&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-12" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-12"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-13" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-13"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="c1"&gt;# put the content back&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-14" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-14"&gt;&lt;/a&gt;&lt;span class="hll"&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-15" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-15"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="c1"&gt;# materialize recursively&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-16" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-16"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="n"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_566dfe63dbb7414188b1e61a855c6ae7-17" name="rest_code_566dfe63dbb7414188b1e61a855c6ae7-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_566dfe63dbb7414188b1e61a855c6ae7-17"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="version-8-loading-from-non-virtual-objects"&gt;
&lt;h2&gt;Version 8: Loading from non-virtual objects&lt;/h2&gt;
&lt;p&gt;Now materialize is done. We need to go back to &lt;code class="docutils literal"&gt;optimize_alloc_removal&lt;/code&gt; and
improve it further. The last time we changed it, we added a case analysis to the
code dealing with &lt;code class="docutils literal"&gt;store&lt;/code&gt;, distinguishing between storing to a virtual and to
a non-virtual object. We need to add an equivalent distinction to the &lt;code class="docutils literal"&gt;load&lt;/code&gt;
case, because right now loading from a non-virtual crashes.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-1" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_load_non_virtual&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-2" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-3" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-4" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-5" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-6" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-6"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the next line fails in the line&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-7" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-7"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# op.make_equal_to(info.load(field))&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-8" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-8"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# because info is None&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-9" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-10" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-10"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-11" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-11"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-12" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-12"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = load(optvar0, 0)&lt;/span&gt;
&lt;a id="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-13" name="rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_c2ec24c6f56e49eaaca2d75657bc5e12-13"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = print(optvar1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To fix it, we split the &lt;code class="docutils literal"&gt;load&lt;/code&gt; code into two cases, leaving the virtual path
as before, and letting the &lt;code class="docutils literal"&gt;load&lt;/code&gt; from a non-virtual fall through to the
general code at the end of the function.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-1" name="rest_code_72ca4aa04192421c866ef96e0674838a-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-2" name="rest_code_72ca4aa04192421c866ef96e0674838a-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-3" name="rest_code_72ca4aa04192421c866ef96e0674838a-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-4" name="rest_code_72ca4aa04192421c866ef96e0674838a-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-5" name="rest_code_72ca4aa04192421c866ef96e0674838a-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-5"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VirtualObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-6" name="rest_code_72ca4aa04192421c866ef96e0674838a-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-6"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-7" name="rest_code_72ca4aa04192421c866ef96e0674838a-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-8" name="rest_code_72ca4aa04192421c866ef96e0674838a-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-8"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-9" name="rest_code_72ca4aa04192421c866ef96e0674838a-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-9"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# virtual&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-10" name="rest_code_72ca4aa04192421c866ef96e0674838a-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-10"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-11" name="rest_code_72ca4aa04192421c866ef96e0674838a-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-11"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-12" name="rest_code_72ca4aa04192421c866ef96e0674838a-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-12"&gt;&lt;/a&gt;&lt;span class="hll"&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-13" name="rest_code_72ca4aa04192421c866ef96e0674838a-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-13"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="c1"&gt;# otherwise not virtual, use the&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-14" name="rest_code_72ca4aa04192421c866ef96e0674838a-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-14"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="c1"&gt;# general path below&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-15" name="rest_code_72ca4aa04192421c866ef96e0674838a-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-15"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-16" name="rest_code_72ca4aa04192421c866ef96e0674838a-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-16"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-17" name="rest_code_72ca4aa04192421c866ef96e0674838a-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-17"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# virtual&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-18" name="rest_code_72ca4aa04192421c866ef96e0674838a-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-18"&gt;&lt;/a&gt;                &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-19" name="rest_code_72ca4aa04192421c866ef96e0674838a-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-19"&gt;&lt;/a&gt;                &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-20" name="rest_code_72ca4aa04192421c866ef96e0674838a-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-20"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-21" name="rest_code_72ca4aa04192421c866ef96e0674838a-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-21"&gt;&lt;/a&gt;            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# not virtual&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-22" name="rest_code_72ca4aa04192421c866ef96e0674838a-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-22"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# first materialize the&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-23" name="rest_code_72ca4aa04192421c866ef96e0674838a-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-23"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# right hand side&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-24" name="rest_code_72ca4aa04192421c866ef96e0674838a-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-24"&gt;&lt;/a&gt;                &lt;span class="n"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-25" name="rest_code_72ca4aa04192421c866ef96e0674838a-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-25"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# then emit the store via&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-26" name="rest_code_72ca4aa04192421c866ef96e0674838a-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-26"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# the general path below&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-27" name="rest_code_72ca4aa04192421c866ef96e0674838a-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-27"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_72ca4aa04192421c866ef96e0674838a-28" name="rest_code_72ca4aa04192421c866ef96e0674838a-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_72ca4aa04192421c866ef96e0674838a-28"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="version-9-final-materialize-on-other-operations"&gt;
&lt;h2&gt;Version 9 (Final): Materialize on Other Operations&lt;/h2&gt;
&lt;p&gt;We're almost at the end now. There's one final generalization left to do. We
started with the heuristic that storing a virtual into a non-virtual would
escape it. This should be generalized. Every time we pass a virtual into any
operation where it is not the first argument of a &lt;code class="docutils literal"&gt;load&lt;/code&gt; and a &lt;code class="docutils literal"&gt;store&lt;/code&gt;
should also escape it (imagine passing the virtual to some function call).
Let's test this as usual with our &lt;code class="docutils literal"&gt;print&lt;/code&gt; operation:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-1" name="rest_code_29bf55893959444bb286ac72201db69a-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_materialize_on_other_ops&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-2" name="rest_code_29bf55893959444bb286ac72201db69a-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# materialize not just on store&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-3" name="rest_code_29bf55893959444bb286ac72201db69a-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-4" name="rest_code_29bf55893959444bb286ac72201db69a-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-5" name="rest_code_29bf55893959444bb286ac72201db69a-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-6" name="rest_code_29bf55893959444bb286ac72201db69a-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-7" name="rest_code_29bf55893959444bb286ac72201db69a-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-8" name="rest_code_29bf55893959444bb286ac72201db69a-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-9" name="rest_code_29bf55893959444bb286ac72201db69a-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-9"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-10" name="rest_code_29bf55893959444bb286ac72201db69a-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-10"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = alloc()&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-11" name="rest_code_29bf55893959444bb286ac72201db69a-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-11"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = print(optvar1)"""&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-12" name="rest_code_29bf55893959444bb286ac72201db69a-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# again, the resulting basic block is not in&lt;/span&gt;
&lt;a id="rest_code_29bf55893959444bb286ac72201db69a-13" name="rest_code_29bf55893959444bb286ac72201db69a-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_29bf55893959444bb286ac72201db69a-13"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# valid SSA form&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To fix this, we will take the call to &lt;code class="docutils literal"&gt;materialize&lt;/code&gt; out of the &lt;code class="docutils literal"&gt;store&lt;/code&gt; code
path and instead put it into the generic code path the end of the &lt;code class="docutils literal"&gt;while&lt;/code&gt;
loop:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-1" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-1"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# materialize is unchanged&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-2" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-2"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-3" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-4" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-5" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-6" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-7" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-7"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-8" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-8"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# Already materialized&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-9" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-9"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-10" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-10"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-11" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-11"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-12" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-12"&gt;&lt;/a&gt;    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-13" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-13"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-14" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-14"&gt;&lt;/a&gt;        &lt;span class="n"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-15" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-15"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-16" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-16"&gt;&lt;/a&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-17" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-17"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-18" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-18"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-19" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-19"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-20" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-20" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-20"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"alloc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-21" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-21" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-21"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VirtualObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-22" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-22" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-22"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-23" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-23" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-23"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-24" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-24" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-24"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-25" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-25" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-25"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# virtual&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-26" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-26" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-26"&gt;&lt;/a&gt;                &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-27" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-27" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-27"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-28" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-28" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-28"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-29" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-29" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-29"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-30" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-30" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-30"&gt;&lt;/a&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-31" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-31" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-31"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# virtual&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-32" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-32" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-32"&gt;&lt;/a&gt;                &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-33" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-33" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-33"&gt;&lt;/a&gt;                &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-34" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-34" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-34"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-35" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-35" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-35"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="c1"&gt;# materialize all the arguments of&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-36" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-36" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-36"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="c1"&gt;# operations that are put into the&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-37" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-37" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-37"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="c1"&gt;# output basic block&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-38" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-38" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-38"&gt;&lt;/a&gt;&lt;span class="hll"&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-39" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-39" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-39"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="n"&gt;materialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-40" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-40" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-40"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-41" name="rest_code_bfcf3829083b4c13bf8aa86e9604be8c-41" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_bfcf3829083b4c13bf8aa86e9604be8c-41"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it, we're done. It's not a lot of code, but actually quite a powerful
optimization. In addition to removing allocations for objects that are only used
briefly and in predictable ways, it also has another effect. If an object is
allocated, used in a number of operations and then escapes further down in the
block, the operations in between can often be optimized away. This is
demonstrated by the next test (which already passes):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-1" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-1" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_sink_allocations&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-2" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-2" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-3" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-3" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-4" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-4" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-5" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-5" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-5"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-6" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-6" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;456&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-7" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-7" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-8" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-8" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-8"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-9" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-9" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-9"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-10" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-10" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var7&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-11" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-11" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-11"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-12" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-12" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-12"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize_alloc_removal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-13" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-13" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-13"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-14" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-14" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-14"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-15" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-15" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-15"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = add(123, 456)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-16" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-16" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-16"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = alloc()&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-17" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-17" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-17"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = store(optvar2, 0, optvar1)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-18" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-18" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-18"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar4 = store(optvar2, 1, 456)&lt;/span&gt;
&lt;a id="rest_code_51f168bd8829436eb7da03fb0f1bf145-19" name="rest_code_51f168bd8829436eb7da03fb0f1bf145-19" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html#rest_code_51f168bd8829436eb7da03fb0f1bf145-19"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar5 = store(optvar0, 1, optvar2)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the addition is not optimized away, because the code from this blog
post does not contain constant folding and the other optimizations from
the last one. Combining them would not be too hard though.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That's it! The core idea of PyPy's allocation removal optimization in one or
two screens of code. The real implementation has a number of refinements,
but the core ideas are all here.&lt;/p&gt;
&lt;p&gt;I'm not going to show any benchmark numbers or anything like that here, if you
are interested in numbers you could look at the evaluation Section 6.
"Implementation and Evaluation" of the &lt;a class="reference external" href="https://www3.hhu.de/stups/downloads/pdf/BoCuFiLePeRi2011.pdf"&gt;paper&lt;/a&gt; that describes the work.&lt;/p&gt;
&lt;p&gt;There's a complementary optimization that improves &lt;code class="docutils literal"&gt;load&lt;/code&gt; and &lt;code class="docutils literal"&gt;store&lt;/code&gt;
operations for objects that are &lt;em&gt;not&lt;/em&gt; virtual. I'll probably not write that
down as another post, but &lt;a class="reference external" href="https://bernsteinbear.com/"&gt;Max Bernstein&lt;/a&gt; and I developed that together on a
&lt;a class="reference external" href="https://www.pypy.org/posts/2022/10/twitch.tv/pypyproject"&gt;PyPy Twitch channel&lt;/a&gt; channel a few weeks ago, here's the recording:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/w-UHg0yOPSE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;&lt;/section&gt;
&lt;section id="footnotes"&gt;
&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;p id="target-4"&gt;¹ This is how PyPy uses the terminology, not really used consistently by other
projects. The term "escape" is fairly standard throughout the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Escape_analysis"&gt;escape
analysis&lt;/a&gt; literature. The term "virtual" was used originally in &lt;a class="reference external" href="https://dl.acm.org/doi/abs/10.1145/1014007.1014010"&gt;Armin Rigo's
Psyco&lt;/a&gt; but is e.g. also used by the paper &lt;a class="reference external" href="https://www.ssw.uni-linz.ac.at/Research/Papers/Stadler14/Stadler2014-CGO-PEA.pdf"&gt;Partial Escape Analysis and Scalar
Replacement for Java&lt;/a&gt;.&lt;/p&gt;
&lt;p id="target-5"&gt;² The order in which we put the &lt;cite&gt;store&lt;/cite&gt; operations back is relying on
dictionary iteration order, which is insertion order. That's not a bad
ordering, we could also be explicit and sort the fields in some order (ideally
the order in which the object lays them out in memory).&lt;/p&gt;
&lt;/section&gt;</description><category>toy-optimizer</category><guid>https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html</guid><pubDate>Tue, 25 Oct 2022 07:55:00 GMT</pubDate></item><item><title>Implementing a Toy Optimizer</title><link>https://www.pypy.org/posts/2022/07/toy-optimizer.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;p&gt;In this blog post I want to show the complete code (in Python3) of how a very
simple optimizer for sequences of operations can work. These algorithms could
be part of a (really simple) compiler, or a JIT. The architecture of the code in
this blog post is very similar to that of the trace optimizer of the PyPy JIT:
After a trace is produced, is is optimized before being sent to the machine code
backend that produces binary instructions for the CPU architecture that PyPy is
running on.&lt;/p&gt;
&lt;p&gt;To get started, the first thing we need to do is define how our operations are
stored. The
format that a compiler uses to store the program while it is being optimized
is usually called its &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Intermediate_representation"&gt;intermediate representation&lt;/a&gt; (IR). Many production
compilers use IRs that are in the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Static_single-assignment_form"&gt;Static Single-Assignment Form&lt;/a&gt; (SSA), and
we will also use that. SSA form has the property that every variable is
assigned to exactly once, and every variable is defined before it is used. This
simplifies many things.&lt;/p&gt;
&lt;p&gt;Let's make this concrete. If our input program is a complex expressions, such
as &lt;code class="docutils literal"&gt;a * (b + 17) + (b + 17)&lt;/code&gt; the intermediate representation of that (or at
least its text representation) would maybe be something like:&lt;/p&gt;
&lt;pre class="literal-block"&gt;var1 = add(b, 17)
var2 = mul(a, var1)
var3 = add(b, 17)
var4 = add(var2, var3)&lt;/pre&gt;
&lt;p&gt;This sequence of instructions is inefficient. The operation &lt;code class="docutils literal"&gt;add(b, 17)&lt;/code&gt; is
computed twice and we can save time by removing the second one and only
computing it once. In this post I want to show an optimizer that can do this
(and some related) optimizations.&lt;/p&gt;
&lt;p&gt;Looking at the IR we notice that the input expression has been linearized
into a sequence of operations, and all the intermedia results have been given
unique variable names. The value that every variable is assigned is computed
by the right hand side, which is some operation consisting of an operand and an
arbitrary number of arguments. The arguments of an operation are either
themselves variables or constants.&lt;/p&gt;
&lt;p&gt;I will not at all talk about the process of translating the input program
into the IR. Instead, I will assume we have some component that does this
translation already. The tests in this blog post will construct small
snippets of IR by hand. I also won't talk about what happens after the
optimization (usually the optimized IR is translated into machine code).&lt;/p&gt;
&lt;section id="implementing-the-intermediate-representation"&gt;
&lt;h2&gt;Implementing the Intermediate Representation&lt;/h2&gt;
&lt;p&gt;Let's start modelling the intermediate representation with Python classes.
First we define a base class of all values that can be used as arguments in
operations, and let's also add a class that represents constants:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-1" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-1"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pytest&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-2" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-2"&gt;&lt;/a&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;typing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-3" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-4" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-4"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-5" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-6" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-6"&gt;&lt;/a&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-7" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-7"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-8" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-9" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-9"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-10" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-10"&gt;&lt;/a&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-11" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-11"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-12" name="rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5fbe07f3dd0742a9a4351cf85eb1da1d-12"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Constant(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One consequence of the fact that every variable is assigned to only once is
that variables are in a one-to-one correspondence with the right-hand-side of
their unique assignments. That means that we don't need a class that represents
variables at all. Instead, it's sufficient to have a class that represents an
operation (the right-hand side), and that by definition is the same as the variable (left-hand side) that it defines:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-1" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-2" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-3" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-3"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-4" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-4"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-5" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-5"&gt;&lt;/a&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-6" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-7" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Operation(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-8" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-8"&gt;&lt;/a&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-9" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-9"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_5243c15090e546deabe5ea68d4fa38c3-10" name="rest_code_5243c15090e546deabe5ea68d4fa38c3-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_5243c15090e546deabe5ea68d4fa38c3-10"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can instantiate these two classes to represent the example sequence of
operations above:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-1" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_construct_example&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-2" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# first we need something to represent&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-3" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# "a" and "b". In our limited view, we don't&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-4" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-4"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# know where they come from, so we will define&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-5" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-5"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# them with a pseudo-operation called "getarg"&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-6" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-6"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# which takes a number n as an argument and&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-7" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-7"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# returns the n-th input argument. The proper&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-8" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-8"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# SSA way to do this would be phi-nodes.&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-9" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-9"&gt;&lt;/a&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-10" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-10"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"getarg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-11" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-11"&gt;&lt;/a&gt;    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"getarg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-12" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-12"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var1 = add(b, 17)&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-13" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-13"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-14" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-14"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var2 = mul(a, var1)&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-15" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-15"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-16" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var3 = add(b, 17)&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-17" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-17"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-18" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-18"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var4 = add(var2, var3)&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-19" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-19"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-20" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-20"&gt;&lt;/a&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-21" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-21"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-22" name="rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_71854a4b3bfa49ec8cfb5766203cc0cd-22"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# nothing to test really, it shouldn't crash&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Usually, complicated programs are represented as a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Control-flow_graph"&gt;control flow graph&lt;/a&gt; in a
compiler, which represents all the possible paths that control can take while
executing the program. Every node in the control flow graph is a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Basic_block"&gt;basic
block&lt;/a&gt;. A basic block is a linear sequence of operations with no control flow
inside of it.&lt;/p&gt;
&lt;p&gt;When optimizing a program, a compiler usually looks at the whole control flow
graph of a function. However, that is still too complicated! So let's
simplify further and look at only at optimizations we can do when looking at
a single basic block and its sequence of instructions (they are called local
optimizations).&lt;/p&gt;
&lt;p&gt;Let's define a class representing basic blocks and let's also add some
convenience functions for constructing sequences of operations, because the
code in &lt;code class="docutils literal"&gt;test_construct_example&lt;/code&gt; is a bit annoying.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-1" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-2" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-3" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-3"&gt;&lt;/a&gt;        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wraparg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-4" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-4"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-5" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-5"&gt;&lt;/a&gt;                &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-6" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-6"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-7" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-8" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-8"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# construct an Operation, wrap the&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-9" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-9"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# arguments in Constants if necessary&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-10" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-10"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-11" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-11"&gt;&lt;/a&gt;                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wraparg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-12" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-12"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# add it to self, the basic block&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-13" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-13"&gt;&lt;/a&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-14" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-14"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-15" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-15"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-16" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-16"&gt;&lt;/a&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-17" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-17"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# a bunch of operations we support&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-18" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-18"&gt;&lt;/a&gt;    &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-19" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-19"&gt;&lt;/a&gt;    &lt;span class="n"&gt;mul&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mul"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-20" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-20"&gt;&lt;/a&gt;    &lt;span class="n"&gt;getarg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"getarg"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-21" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-21"&gt;&lt;/a&gt;    &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dummy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-22" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-22"&gt;&lt;/a&gt;    &lt;span class="n"&gt;lshift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opbuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lshift"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-23" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-23"&gt;&lt;/a&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-24" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-24"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_convencience_block_construction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-25" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-25"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-26" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-26"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# a again with getarg, the following line&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-27" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-27"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# defines the Operation instance and&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-28" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-28"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# immediately adds it to the basic block bb&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-29" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-29"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-30" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-30"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-31" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-31"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"getarg"&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-32" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-32"&gt;&lt;/a&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-33" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-33"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# it's a Constant&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-34" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-34"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-35" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-35"&gt;&lt;/a&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-36" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-36"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# b with getarg&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-37" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-37"&gt;&lt;/a&gt;    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-38" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-38"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var1 = add(b, 17)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-39" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-39"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-40" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-40"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var2 = mul(a, var1)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-41" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-41"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-42" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-42" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-42"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var3 = add(b, 17)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-43" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-43" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-43"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-44" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-44" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-44"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# var4 = add(var2, var3)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-45" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-45" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-45"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9da0a1bfeb1947749abf7b48b422ea57-46" name="rest_code_9da0a1bfeb1947749abf7b48b422ea57-46" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9da0a1bfeb1947749abf7b48b422ea57-46"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's a good bit of infrastructure to make the tests easy to write. One
thing we are lacking though is a way to print the basic blocks into a nicely
readable textual representation. Because in the current form, the &lt;code class="docutils literal"&gt;repr&lt;/code&gt; of a
Block is very annoying, the output of pretty-printing &lt;code class="docutils literal"&gt;bb&lt;/code&gt; in the test above
looks like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-1" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-1"&gt;&lt;/a&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-2" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-2"&gt;&lt;/a&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-3" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-3"&gt;&lt;/a&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-4" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-4"&gt;&lt;/a&gt;           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-5" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-5"&gt;&lt;/a&gt;                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-6" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-6"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-7" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-7"&gt;&lt;/a&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mul'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-8" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-8"&gt;&lt;/a&gt;           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-9" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-9"&gt;&lt;/a&gt;                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-10" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-10"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-11" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-11"&gt;&lt;/a&gt;                           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-12" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-12"&gt;&lt;/a&gt;                                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-13" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-13"&gt;&lt;/a&gt;                            &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)])]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-14" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-14"&gt;&lt;/a&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-15" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-15"&gt;&lt;/a&gt;           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-16" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-16"&gt;&lt;/a&gt;                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-17" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-17"&gt;&lt;/a&gt;            &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-18" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-18"&gt;&lt;/a&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-19" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-19"&gt;&lt;/a&gt;           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mul'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-20" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-20"&gt;&lt;/a&gt;                       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-21" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-21"&gt;&lt;/a&gt;                                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-22" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-22"&gt;&lt;/a&gt;                             &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-23" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-23"&gt;&lt;/a&gt;                                       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-24" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-24"&gt;&lt;/a&gt;                                                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-25" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-25"&gt;&lt;/a&gt;                                        &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)])]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-26" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-26"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-27" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-27"&gt;&lt;/a&gt;                           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'getarg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-28" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-28"&gt;&lt;/a&gt;                                           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
&lt;a id="rest_code_9acf1d746cd048aea2cf58cf039b1055-29" name="rest_code_9acf1d746cd048aea2cf58cf039b1055-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9acf1d746cd048aea2cf58cf039b1055-29"&gt;&lt;/a&gt;                                 &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)])])]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It's impossible to see what is going on here, because the &lt;code class="docutils literal"&gt;Operations&lt;/code&gt; in the
basic block appear several times, once as elements of the list but then also as
arguments to operations further down in the list. So we need some code that
turns things back into a readable textual representation, so we have a chance
to debug.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-1" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;varprefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"var"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-2" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the implementation is not too important,&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-3" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# look at the test below to see what the&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-4" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-4"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# result looks like&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-5" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-5"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-6" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-6"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-7" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-8" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-8"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-9" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-9"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-10" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-10"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# the key must exist, otherwise it's&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-11" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-11"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# not a valid SSA basic block:&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-12" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-12"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# the variable must be defined before&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-13" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-13"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# its first use&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-14" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-14"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;varnames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-15" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-15"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-16" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-16"&gt;&lt;/a&gt;    &lt;span class="n"&gt;varnames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-17" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-17"&gt;&lt;/a&gt;    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-18" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-18"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-19" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-19"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# give the operation a name used while&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-20" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-20"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# printing:&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-21" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-21"&gt;&lt;/a&gt;        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;varprefix&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-22" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-22"&gt;&lt;/a&gt;        &lt;span class="n"&gt;varnames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-23" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-23"&gt;&lt;/a&gt;        &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-24" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-24"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-25" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-25"&gt;&lt;/a&gt;                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-26" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-26"&gt;&lt;/a&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-27" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-27"&gt;&lt;/a&gt;        &lt;span class="n"&gt;strop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-28" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-28"&gt;&lt;/a&gt;        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-29" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-29"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-30" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-30"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-31" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-31"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_basicblock_to_str&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-32" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-32"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-33" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-33"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-34" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-34"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-35" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-35"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-36" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-36"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-37" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-37"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-38" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-38"&gt;&lt;/a&gt;&lt;span class="s2"&gt;var0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-39" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-39"&gt;&lt;/a&gt;&lt;span class="s2"&gt;var1 = add(5, 4)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-40" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-40"&gt;&lt;/a&gt;&lt;span class="s2"&gt;var2 = add(var1, var0)"""&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-41" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-41"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-42" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-42" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-42"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# with a different prefix for the invented&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-43" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-43" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-43"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# variable names:&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-44" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-44" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-44"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-45" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-45" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-45"&gt;&lt;/a&gt;&lt;span class="s2"&gt;x0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-46" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-46" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-46"&gt;&lt;/a&gt;&lt;span class="s2"&gt;x1 = add(5, 4)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-47" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-47" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-47"&gt;&lt;/a&gt;&lt;span class="s2"&gt;x2 = add(x1, x0)"""&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-48" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-48" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-48"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-49" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-49" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-49"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# and our running example:&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-50" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-50" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-50"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-51" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-51" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-51"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-52" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-52" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-52"&gt;&lt;/a&gt;    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-53" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-53" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-53"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-54" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-54" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-54"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-55" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-55" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-55"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-56" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-56" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-56"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-57" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-57" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-57"&gt;&lt;/a&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-58" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-58" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-58"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"v"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-59" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-59" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-59"&gt;&lt;/a&gt;&lt;span class="s2"&gt;v0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-60" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-60" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-60"&gt;&lt;/a&gt;&lt;span class="s2"&gt;v1 = getarg(1)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-61" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-61" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-61"&gt;&lt;/a&gt;&lt;span class="s2"&gt;v2 = add(v1, 17)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-62" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-62" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-62"&gt;&lt;/a&gt;&lt;span class="s2"&gt;v3 = mul(v0, v2)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-63" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-63" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-63"&gt;&lt;/a&gt;&lt;span class="s2"&gt;v4 = add(v1, 17)&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-64" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-64" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-64"&gt;&lt;/a&gt;&lt;span class="s2"&gt;v5 = add(v3, v4)"""&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-65" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-65" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-65"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Note the re-numbering of the variables! We&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-66" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-66" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-66"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# don't attach names to Operations at all, so&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-67" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-67" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-67"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the printing will just number them in&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-68" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-68" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-68"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# sequence, can sometimes be a source of&lt;/span&gt;
&lt;a id="rest_code_88ee6f99f6bb45caad3f5861ed038447-69" name="rest_code_88ee6f99f6bb45caad3f5861ed038447-69" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_88ee6f99f6bb45caad3f5861ed038447-69"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# confusion.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is much better. Now we're done with the basic infrastructure, we can
define sequences of operations and print them in a readable way. Next we need a
central data structure that is used when actually optimizing basic blocks.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="storing-equivalences-between-operations-using-a-union-find-data-structure"&gt;
&lt;h2&gt;Storing Equivalences between Operations Using a Union-Find Data Structure&lt;/h2&gt;
&lt;p&gt;When optimizing a sequence of operations, we want to make it less costly to
execute. For that we typically want to remove operations (and sometimes
replace operations with less expensive ones). We can remove operations if
they do redundant computation, like case of the duplicate &lt;code class="docutils literal"&gt;add(v1, 17)&lt;/code&gt; in
the example. So what we want to do is to turn the running input sequence:&lt;/p&gt;
&lt;pre class="literal-block"&gt;v0 = getarg(0)
v1 = getarg(1)
v2 = add(v1, 17)
v3 = mul(v0, v2)
v4 = add(v1, 17)
v5 = add(v3, v4)&lt;/pre&gt;
&lt;p&gt;Into the following optimized output sequence:&lt;/p&gt;
&lt;pre class="literal-block"&gt;optvar0 = getarg(0)
optvar1 = getarg(1)
optvar2 = add(optvar1, 17)
optvar3 = mul(optvar0, optvar2)
optvar4 = add(optvar3, optvar2)&lt;/pre&gt;
&lt;p&gt;We left out the second &lt;code class="docutils literal"&gt;add&lt;/code&gt; (which defines &lt;code class="docutils literal"&gt;v4&lt;/code&gt;), and then replaced the
usage of &lt;code class="docutils literal"&gt;v4&lt;/code&gt; with &lt;code class="docutils literal"&gt;v2&lt;/code&gt; in the final operation that defines &lt;code class="docutils literal"&gt;v5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What we effectively did was discover that &lt;code class="docutils literal"&gt;v2&lt;/code&gt; and &lt;code class="docutils literal"&gt;v4&lt;/code&gt; are equivalent and then
replaced &lt;code class="docutils literal"&gt;v4&lt;/code&gt; with &lt;code class="docutils literal"&gt;v2&lt;/code&gt;. In general, we might discover more such equivalences,
and we need a data structure to store them. A good data structure to store
these equivalences is &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure"&gt;Union Find&lt;/a&gt; (also called Disjoint-set data structure),
which stores a collection of disjoint sets. Disjoint means, that no operation
can appear in more than one set. The sets in our concrete case are the sets of
operations that compute the same result.&lt;/p&gt;
&lt;p&gt;When we start out, every operation is in its own singleton set, with no other
member. As we discover more equivalences, we will unify sets into larger sets
of operations that all compute the same result. So one operation the data
structure supports is &lt;code class="docutils literal"&gt;union&lt;/code&gt;, to unify two sets, we'll call that
&lt;code class="docutils literal"&gt;make_equal_to&lt;/code&gt; in the code below.&lt;/p&gt;
&lt;p&gt;The other operation the data structure supports is &lt;code class="docutils literal"&gt;find&lt;/code&gt;, which takes an
operation and returns a "representative" of the set of all equivalent
operations. Two operations are in the same set, if the representative that
find returns for them is the same.&lt;/p&gt;
&lt;p&gt;The exact details of how the data structure works are only sort of important
(even though it's very cool, I promise!). It's OK to skip over the
implementation. We will add the data structure right into our &lt;code class="docutils literal"&gt;Value&lt;/code&gt;,
&lt;code class="docutils literal"&gt;Constant&lt;/code&gt; and &lt;code class="docutils literal"&gt;Operation&lt;/code&gt; classes:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-1" name="rest_code_a137bd2cb0f94b919578d50644b71da6-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-2" name="rest_code_a137bd2cb0f94b919578d50644b71da6-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-3" name="rest_code_a137bd2cb0f94b919578d50644b71da6-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-3"&gt;&lt;/a&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abstract"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-4" name="rest_code_a137bd2cb0f94b919578d50644b71da6-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-5" name="rest_code_a137bd2cb0f94b919578d50644b71da6-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-5"&gt;&lt;/a&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abstract"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-6" name="rest_code_a137bd2cb0f94b919578d50644b71da6-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-6"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-7" name="rest_code_a137bd2cb0f94b919578d50644b71da6-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-7"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-8" name="rest_code_a137bd2cb0f94b919578d50644b71da6-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-8"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-9" name="rest_code_a137bd2cb0f94b919578d50644b71da6-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-9"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-10" name="rest_code_a137bd2cb0f94b919578d50644b71da6-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-10"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-11" name="rest_code_a137bd2cb0f94b919578d50644b71da6-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-11"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-12" name="rest_code_a137bd2cb0f94b919578d50644b71da6-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-12"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-13" name="rest_code_a137bd2cb0f94b919578d50644b71da6-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-13"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-14" name="rest_code_a137bd2cb0f94b919578d50644b71da6-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-14"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-15" name="rest_code_a137bd2cb0f94b919578d50644b71da6-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-15"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-16" name="rest_code_a137bd2cb0f94b919578d50644b71da6-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-16"&gt;&lt;/a&gt;            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Operation(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,"&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-17" name="rest_code_a137bd2cb0f94b919578d50644b71da6-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-17"&gt;&lt;/a&gt;            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-18" name="rest_code_a137bd2cb0f94b919578d50644b71da6-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-18"&gt;&lt;/a&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-19" name="rest_code_a137bd2cb0f94b919578d50644b71da6-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-19"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-20" name="rest_code_a137bd2cb0f94b919578d50644b71da6-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-20"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-21" name="rest_code_a137bd2cb0f94b919578d50644b71da6-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-21"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# returns the "representative" value of&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-22" name="rest_code_a137bd2cb0f94b919578d50644b71da6-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-22"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# self, in the union-find sense&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-23" name="rest_code_a137bd2cb0f94b919578d50644b71da6-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-23"&gt;&lt;/a&gt;        &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-24" name="rest_code_a137bd2cb0f94b919578d50644b71da6-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-24"&gt;&lt;/a&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-25" name="rest_code_a137bd2cb0f94b919578d50644b71da6-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-25"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# could do path compression here too&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-26" name="rest_code_a137bd2cb0f94b919578d50644b71da6-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-26"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# but not essential&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-27" name="rest_code_a137bd2cb0f94b919578d50644b71da6-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-27"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-28" name="rest_code_a137bd2cb0f94b919578d50644b71da6-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-28"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-29" name="rest_code_a137bd2cb0f94b919578d50644b71da6-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-29"&gt;&lt;/a&gt;                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-30" name="rest_code_a137bd2cb0f94b919578d50644b71da6-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-30"&gt;&lt;/a&gt;            &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-31" name="rest_code_a137bd2cb0f94b919578d50644b71da6-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-31"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-32" name="rest_code_a137bd2cb0f94b919578d50644b71da6-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-32"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-33" name="rest_code_a137bd2cb0f94b919578d50644b71da6-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-33"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-34" name="rest_code_a137bd2cb0f94b919578d50644b71da6-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-34"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# change to above: return the&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-35" name="rest_code_a137bd2cb0f94b919578d50644b71da6-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-35"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# representative of argument 'index'&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-36" name="rest_code_a137bd2cb0f94b919578d50644b71da6-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-36"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-37" name="rest_code_a137bd2cb0f94b919578d50644b71da6-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-37"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-38" name="rest_code_a137bd2cb0f94b919578d50644b71da6-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-38"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-39" name="rest_code_a137bd2cb0f94b919578d50644b71da6-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-39"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# this is "union" in the union-find sense,&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-40" name="rest_code_a137bd2cb0f94b919578d50644b71da6-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-40"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# but the direction is important! The&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-41" name="rest_code_a137bd2cb0f94b919578d50644b71da6-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-41"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# representative of the union of Operations&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-42" name="rest_code_a137bd2cb0f94b919578d50644b71da6-42" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-42"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# must be either a Constant or an operation&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-43" name="rest_code_a137bd2cb0f94b919578d50644b71da6-43" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-43"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# that we know for sure is not optimized&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-44" name="rest_code_a137bd2cb0f94b919578d50644b71da6-44" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-44"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# away.&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-45" name="rest_code_a137bd2cb0f94b919578d50644b71da6-45" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-45"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-46" name="rest_code_a137bd2cb0f94b919578d50644b71da6-46" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-46"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-47" name="rest_code_a137bd2cb0f94b919578d50644b71da6-47" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-47"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-48" name="rest_code_a137bd2cb0f94b919578d50644b71da6-48" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-48"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-49" name="rest_code_a137bd2cb0f94b919578d50644b71da6-49" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-49"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forwarded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-50" name="rest_code_a137bd2cb0f94b919578d50644b71da6-50" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-50"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-51" name="rest_code_a137bd2cb0f94b919578d50644b71da6-51" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-51"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-52" name="rest_code_a137bd2cb0f94b919578d50644b71da6-52" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-52"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-53" name="rest_code_a137bd2cb0f94b919578d50644b71da6-53" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-53"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-54" name="rest_code_a137bd2cb0f94b919578d50644b71da6-54" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-54"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-55" name="rest_code_a137bd2cb0f94b919578d50644b71da6-55" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-55"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-56" name="rest_code_a137bd2cb0f94b919578d50644b71da6-56" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-56"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-57" name="rest_code_a137bd2cb0f94b919578d50644b71da6-57" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-57"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Constant(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-58" name="rest_code_a137bd2cb0f94b919578d50644b71da6-58" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-58"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-59" name="rest_code_a137bd2cb0f94b919578d50644b71da6-59" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-59"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-60" name="rest_code_a137bd2cb0f94b919578d50644b71da6-60" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-60"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-61" name="rest_code_a137bd2cb0f94b919578d50644b71da6-61" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-61"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-62" name="rest_code_a137bd2cb0f94b919578d50644b71da6-62" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-62"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_forwarded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-63" name="rest_code_a137bd2cb0f94b919578d50644b71da6-63" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-63"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# if we found out that an Operation is&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-64" name="rest_code_a137bd2cb0f94b919578d50644b71da6-64" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-64"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# equal to a constant, it's a compiler bug&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-65" name="rest_code_a137bd2cb0f94b919578d50644b71da6-65" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-65"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# to find out that it's equal to another&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-66" name="rest_code_a137bd2cb0f94b919578d50644b71da6-66" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-66"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# constant&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-67" name="rest_code_a137bd2cb0f94b919578d50644b71da6-67" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-67"&gt;&lt;/a&gt;        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-68" name="rest_code_a137bd2cb0f94b919578d50644b71da6-68" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-68"&gt;&lt;/a&gt;            &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-69" name="rest_code_a137bd2cb0f94b919578d50644b71da6-69" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-69"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-70" name="rest_code_a137bd2cb0f94b919578d50644b71da6-70" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-70"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_union_find&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-71" name="rest_code_a137bd2cb0f94b919578d50644b71da6-71" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-71"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# construct three operation, and unify them&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-72" name="rest_code_a137bd2cb0f94b919578d50644b71da6-72" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-72"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# step by step&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-73" name="rest_code_a137bd2cb0f94b919578d50644b71da6-73" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-73"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-74" name="rest_code_a137bd2cb0f94b919578d50644b71da6-74" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-74"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-75" name="rest_code_a137bd2cb0f94b919578d50644b71da6-75" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-75"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-76" name="rest_code_a137bd2cb0f94b919578d50644b71da6-76" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-76"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-77" name="rest_code_a137bd2cb0f94b919578d50644b71da6-77" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-77"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-78" name="rest_code_a137bd2cb0f94b919578d50644b71da6-78" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-78"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# at the beginning, every op is its own&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-79" name="rest_code_a137bd2cb0f94b919578d50644b71da6-79" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-79"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# representative, that means every&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-80" name="rest_code_a137bd2cb0f94b919578d50644b71da6-80" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-80"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# operation is in a singleton set&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-81" name="rest_code_a137bd2cb0f94b919578d50644b71da6-81" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-81"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# {a1} {a2} {a3}&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-82" name="rest_code_a137bd2cb0f94b919578d50644b71da6-82" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-82"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-83" name="rest_code_a137bd2cb0f94b919578d50644b71da6-83" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-83"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-84" name="rest_code_a137bd2cb0f94b919578d50644b71da6-84" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-84"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-85" name="rest_code_a137bd2cb0f94b919578d50644b71da6-85" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-85"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-86" name="rest_code_a137bd2cb0f94b919578d50644b71da6-86" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-86"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# now we unify a2 and a1, then the sets are&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-87" name="rest_code_a137bd2cb0f94b919578d50644b71da6-87" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-87"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# {a1, a2} {a3}&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-88" name="rest_code_a137bd2cb0f94b919578d50644b71da6-88" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-88"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-89" name="rest_code_a137bd2cb0f94b919578d50644b71da6-89" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-89"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# they both return a1 as the representative&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-90" name="rest_code_a137bd2cb0f94b919578d50644b71da6-90" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-90"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-91" name="rest_code_a137bd2cb0f94b919578d50644b71da6-91" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-91"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-92" name="rest_code_a137bd2cb0f94b919578d50644b71da6-92" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-92"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# a3 is still different&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-93" name="rest_code_a137bd2cb0f94b919578d50644b71da6-93" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-93"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-94" name="rest_code_a137bd2cb0f94b919578d50644b71da6-94" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-94"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-95" name="rest_code_a137bd2cb0f94b919578d50644b71da6-95" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-95"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# now they are all in the same set {a1, a2, a3}&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-96" name="rest_code_a137bd2cb0f94b919578d50644b71da6-96" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-96"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-97" name="rest_code_a137bd2cb0f94b919578d50644b71da6-97" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-97"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-98" name="rest_code_a137bd2cb0f94b919578d50644b71da6-98" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-98"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-99" name="rest_code_a137bd2cb0f94b919578d50644b71da6-99" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-99"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-100" name="rest_code_a137bd2cb0f94b919578d50644b71da6-100" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-100"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-101" name="rest_code_a137bd2cb0f94b919578d50644b71da6-101" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-101"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# now they are still all the same, and we&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-102" name="rest_code_a137bd2cb0f94b919578d50644b71da6-102" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-102"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# also learned that they are the same as the&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-103" name="rest_code_a137bd2cb0f94b919578d50644b71da6-103" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-103"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# constant 6&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-104" name="rest_code_a137bd2cb0f94b919578d50644b71da6-104" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-104"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the single remaining set then is&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-105" name="rest_code_a137bd2cb0f94b919578d50644b71da6-105" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-105"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# {6, a1, a2, a3}&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-106" name="rest_code_a137bd2cb0f94b919578d50644b71da6-106" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-106"&gt;&lt;/a&gt;    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-107" name="rest_code_a137bd2cb0f94b919578d50644b71da6-107" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-107"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-108" name="rest_code_a137bd2cb0f94b919578d50644b71da6-108" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-108"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-109" name="rest_code_a137bd2cb0f94b919578d50644b71da6-109" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-109"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-110" name="rest_code_a137bd2cb0f94b919578d50644b71da6-110" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-110"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-111" name="rest_code_a137bd2cb0f94b919578d50644b71da6-111" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-111"&gt;&lt;/a&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-112" name="rest_code_a137bd2cb0f94b919578d50644b71da6-112" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-112"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# union with the same constant again is fine&lt;/span&gt;
&lt;a id="rest_code_a137bd2cb0f94b919578d50644b71da6-113" name="rest_code_a137bd2cb0f94b919578d50644b71da6-113" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_a137bd2cb0f94b919578d50644b71da6-113"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="constant-folding"&gt;
&lt;h2&gt;Constant Folding&lt;/h2&gt;
&lt;p&gt;Now comes the first actual optimization, a simple &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Constant_folding"&gt;constant folding&lt;/a&gt; pass. It
will remove operations where all the arguments are constants and replace them
with the constant result.&lt;/p&gt;
&lt;p&gt;Every pass has the same structure: we go over all operations in the basic
block in order and decide for each operation whether it can be removed. For the
constant folding pass, we can remove all the operations with constant
arguments (but we'll implement only the &lt;code class="docutils literal"&gt;add&lt;/code&gt; case here).&lt;/p&gt;
&lt;p&gt;I will show a buggy version of the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Constant_folding"&gt;constant folding&lt;/a&gt; pass first. It has a
problem that is related to why we need the union-find data structure. We will
fix it a bit further down.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-1" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;constfold_buggy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-2" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-3" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-4" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-5" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-5"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# basic idea: go over the list and do&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-6" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-6"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# constant folding of add where possible&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-7" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-8" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-8"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-9" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-9"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-10" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-10"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-11" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-11"&gt;&lt;/a&gt;                    &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-12" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-12"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# can constant-fold! that means we&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-13" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-13"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# learned a new equality, namely&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-14" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-14"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# that op is equal to a specific&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-15" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-15"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# constant&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-16" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-16"&gt;&lt;/a&gt;                &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-17" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-17"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-18" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-18"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# don't need to have the operation&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-19" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-19"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# in the optimized basic block&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-20" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-20"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-21" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-21"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# otherwise the operation is not&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-22" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-22"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# constant-foldable and we put into the&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-23" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-23"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# output list&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-24" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-24"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-25" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-25"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-26" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-26"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-27" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-27"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-28" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-28"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_constfold_simple&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-29" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-29"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-30" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-30"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-31" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-31"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-32" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-32"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-33" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-33"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-34" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-34"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constfold_buggy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-35" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-35"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-36" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-36"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-37" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-37"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = add(9, optvar0)"""&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-38" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-38"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-39" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-39"&gt;&lt;/a&gt;&lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xfail&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-40" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-40"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_constfold_buggy_limitation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-41" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-41"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# this test fails! it shows the problem with&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-42" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-42" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-42"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# the above simple constfold_buggy pass&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-43" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-43" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-43"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-44" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-44" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-44"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-45" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-45" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-45"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-46" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-46" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-46"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# this is folded&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-47" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-47" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-47"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-48" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-48" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-48"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# we want this folded too, but it doesn't work&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-49" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-49" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-49"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-50" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-50" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-50"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-51" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-51" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-51"&gt;&lt;/a&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-52" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-52" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-52"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constfold_buggy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-53" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-53" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-53"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-54" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-54" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-54"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_9c2f4bdec08849aea7aec3316bbfe375-55" name="rest_code_9c2f4bdec08849aea7aec3316bbfe375-55" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_9c2f4bdec08849aea7aec3316bbfe375-55"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = add(19, optvar0)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Why does the test fail? The &lt;code class="docutils literal"&gt;opt_bb&lt;/code&gt; printed output looks like this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;optvar0 = getarg(0)
optvar1 = add(9, 10)
optvar2 = add(optvar1, optvar0)&lt;/pre&gt;
&lt;p&gt;The problem is that when we optimize the second addition in &lt;cite&gt;constfold_buggy&lt;/cite&gt;,
the argument of that operation is an &lt;em&gt;Operation&lt;/em&gt; not a &lt;code class="docutils literal"&gt;Constant&lt;/code&gt;, so
constant-folding is not applied to the second add. However, we have already
learned that the argument &lt;code class="docutils literal"&gt;var1&lt;/code&gt; to the operation &lt;code class="docutils literal"&gt;var2&lt;/code&gt; is equal to
&lt;code class="docutils literal"&gt;Constant(9)&lt;/code&gt;. This information is stored in the union-find data structure.
So what we are missing are suitable find calls in the constant folding pass, to
make use of the previously learned equalities.&lt;/p&gt;
&lt;p&gt;Here's the fixed version:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-1" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;constfold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-2" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-3" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-4" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-5" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-5"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# basic idea: go over the list and do&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-6" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-6"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# constant folding of add where possible&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-7" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-7"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-8" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-8"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# &amp;gt;&amp;gt;&amp;gt; changed&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-9" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-9"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# uses .find()&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-10" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-10"&gt;&lt;/a&gt;&lt;span class="hll"&gt;            &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# uses .find()&lt;/span&gt;
&lt;/span&gt;&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-11" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-11"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt; end changes&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-12" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-12"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-13" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-13"&gt;&lt;/a&gt;                    &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-14" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-14"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# can constant-fold! that means we&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-15" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-15"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# learned a new equality, namely&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-16" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-16"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# that op is equal to a specific&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-17" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-17"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# constant&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-18" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-18"&gt;&lt;/a&gt;                &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-19" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-19"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-20" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-20"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# don't need to have the operation&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-21" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-21"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# in the optimized basic block&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-22" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-22"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-23" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-23"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# otherwise the operation is not&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-24" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-24"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# constant-foldable and we put into the&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-25" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-25"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# output list&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-26" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-26"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-27" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-27"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-28" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-28"&gt;&lt;/a&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-29" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-29"&gt;&lt;/a&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-30" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-30"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_constfold_two_ops&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-31" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-31"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# now it works!&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-32" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-32"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-33" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-33"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-34" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-34"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-35" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-35"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-36" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-36"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-37" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-37"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constfold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-38" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-38"&gt;&lt;/a&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-39" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-39"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-40" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-40"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-41" name="rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_fc2cf22f016847ffa4c1dd6d2d90c54c-41"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = add(19, optvar0)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="common-subexpression-elimination"&gt;
&lt;h2&gt;Common Subexpression Elimination&lt;/h2&gt;
&lt;p&gt;The &lt;code class="docutils literal"&gt;constfold&lt;/code&gt; pass only discovers equalities between &lt;code class="docutils literal"&gt;Operations&lt;/code&gt; and
&lt;code class="docutils literal"&gt;Constants&lt;/code&gt;. Let's do a second pass that also discovers equalities between
&lt;code class="docutils literal"&gt;Operations&lt;/code&gt; and other &lt;code class="docutils literal"&gt;Operations&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A simple optimization that does that has this property &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Common_subexpression_elimination"&gt;common subexpression
elimination&lt;/a&gt; (CSE), which will finally optimize away the problem in the
introductory example code that we had above.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-1" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;cse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-2" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# structure is the same, loop over the input,&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-3" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# add some but not all operations to the&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-4" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-4"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# output&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-5" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-5"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-6" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-6"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-7" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-7"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-8" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-9" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-9"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# only do CSE for add here, but it&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-10" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-10"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# generalizes&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-11" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-11"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-12" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-12"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-13" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-13"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-14" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-14"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# Check whether we have emitted the&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-15" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-15"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# same operation already&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-16" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-16"&gt;&lt;/a&gt;            &lt;span class="n"&gt;prev_op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_prev_add_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-17" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-17"&gt;&lt;/a&gt;                &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-18" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-18"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prev_op&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-19" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-19"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# if yes, we can optimize op away&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-20" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-20"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# and replace it with the earlier&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-21" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-21"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# result, which is an Operation&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-22" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-22"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# that was already emitted to&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-23" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-23"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# opt_bb&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-24" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-24"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-25" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-25"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-26" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-26"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-27" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-27"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-28" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-28"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-29" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-29"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-30" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-30"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-31" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-31"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-32" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-32"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-33" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-33"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# constants compare by their value&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-34" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-34"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-35" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-35"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# everything else by identity&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-36" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-36"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val0&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;val1&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-37" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-37"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-38" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-38"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-39" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-39"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find_prev_add_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-40" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-40"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-41" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-41"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Really naive and quadratic implementation.&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-42" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-42" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-42"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# What we do is walk over the already emitted&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-43" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-43" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-43"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# operations and see whether we emitted an add&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-44" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-44" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-44"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# with the current arguments already. A real&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-45" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-45" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-45"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# implementation might use a hashmap of some&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-46" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-46" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-46"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# kind, or at least only look at a limited&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-47" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-47" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-47"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# window of instructions.&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-48" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-48" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-48"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;opt_op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-49" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-49" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-49"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;opt_op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-50" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-50" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-50"&gt;&lt;/a&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-51" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-51" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-51"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# It's important to call arg here,&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-52" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-52" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-52"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# for the same reason why we&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-53" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-53" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-53"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# needed it in constfold: we need to&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-54" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-54" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-54"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# make sure .find() is called&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-55" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-55" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-55"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt_op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-56" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-56" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-56"&gt;&lt;/a&gt;                &lt;span class="n"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt_op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-57" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-57" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-57"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_op&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-58" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-58" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-58"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-59" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-59" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-59"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-60" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-60" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-60"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-61" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-61" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-61"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_cse&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-62" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-62" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-62"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-63" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-63" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-63"&gt;&lt;/a&gt;    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-64" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-64" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-64"&gt;&lt;/a&gt;    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-65" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-65" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-65"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-66" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-66" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-66"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-67" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-67" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-67"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-68" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-68" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-68"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-69" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-69" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-69"&gt;&lt;/a&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-70" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-70" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-70"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-71" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-71" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-71"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-72" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-72" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-72"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-73" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-73" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-73"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = getarg(1)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-74" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-74" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-74"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = add(optvar1, 17)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-75" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-75" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-75"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = mul(optvar0, optvar2)&lt;/span&gt;
&lt;a id="rest_code_018b30f4add64c36911be6a1ce0f3c5b-76" name="rest_code_018b30f4add64c36911be6a1ce0f3c5b-76" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_018b30f4add64c36911be6a1ce0f3c5b-76"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar4 = add(optvar3, optvar2)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="strength-reduction"&gt;
&lt;h2&gt;Strength Reduction&lt;/h2&gt;
&lt;p&gt;Now we have one pass that replaces &lt;code class="docutils literal"&gt;Operations&lt;/code&gt; with &lt;code class="docutils literal"&gt;Constants&lt;/code&gt; and one that
replaces &lt;code class="docutils literal"&gt;Operations&lt;/code&gt; with previously existing &lt;code class="docutils literal"&gt;Operations&lt;/code&gt;. Let's now do one
final pass that replaces &lt;code class="docutils literal"&gt;Operations&lt;/code&gt; by newly invented &lt;code class="docutils literal"&gt;Operations&lt;/code&gt;, a simple
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Strength_reduction"&gt;strength reduction&lt;/a&gt;. This one will be simple.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-1" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;strength_reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-2" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-3" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-4" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-5" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-5"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-6" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-6"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-7" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-7"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-8" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-8"&gt;&lt;/a&gt;                &lt;span class="c1"&gt;# x + x turns into x &amp;lt;&amp;lt; 1&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-9" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-9"&gt;&lt;/a&gt;                &lt;span class="n"&gt;newop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-10" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-10"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-11" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-11"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-12" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-12"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-13" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-13"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-14" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-14"&gt;&lt;/a&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-15" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-15"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_strength_reduce&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-16" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-16"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-17" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-17"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-18" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-18"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-19" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-19"&gt;&lt;/a&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-20" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-20"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strength_reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-21" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-21"&gt;&lt;/a&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-22" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-22"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-23" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-23"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-24" name="rest_code_40f9cd177acb4c0ebebc94f7950d28ce-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_40f9cd177acb4c0ebebc94f7950d28ce-24"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = lshift(optvar0, 1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="putting-things-together"&gt;
&lt;h2&gt;Putting Things Together&lt;/h2&gt;
&lt;p&gt;Let's combine the passes into one single pass, so that we are going over all
the operations only exactly once, instead of having to look at every operation
once for all the different passes.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-1" name="rest_code_0428db88705248c5bf65bf80bb0bcede-1" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-2" name="rest_code_0428db88705248c5bf65bf80bb0bcede-2" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-3" name="rest_code_0428db88705248c5bf65bf80bb0bcede-3" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-4" name="rest_code_0428db88705248c5bf65bf80bb0bcede-4" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-5" name="rest_code_0428db88705248c5bf65bf80bb0bcede-5" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-5"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-6" name="rest_code_0428db88705248c5bf65bf80bb0bcede-6" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-6"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-7" name="rest_code_0428db88705248c5bf65bf80bb0bcede-7" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-7"&gt;&lt;/a&gt;            &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-8" name="rest_code_0428db88705248c5bf65bf80bb0bcede-8" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-8"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-9" name="rest_code_0428db88705248c5bf65bf80bb0bcede-9" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-9"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# constant folding&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-10" name="rest_code_0428db88705248c5bf65bf80bb0bcede-10" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-10"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-11" name="rest_code_0428db88705248c5bf65bf80bb0bcede-11" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-11"&gt;&lt;/a&gt;                    &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-12" name="rest_code_0428db88705248c5bf65bf80bb0bcede-12" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-12"&gt;&lt;/a&gt;                &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-13" name="rest_code_0428db88705248c5bf65bf80bb0bcede-13" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-13"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-14" name="rest_code_0428db88705248c5bf65bf80bb0bcede-14" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-14"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-15" name="rest_code_0428db88705248c5bf65bf80bb0bcede-15" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-15"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-16" name="rest_code_0428db88705248c5bf65bf80bb0bcede-16" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-16"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# cse&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-17" name="rest_code_0428db88705248c5bf65bf80bb0bcede-17" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-17"&gt;&lt;/a&gt;            &lt;span class="n"&gt;prev_op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_prev_add_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-18" name="rest_code_0428db88705248c5bf65bf80bb0bcede-18" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-18"&gt;&lt;/a&gt;                &lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-19" name="rest_code_0428db88705248c5bf65bf80bb0bcede-19" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-19"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prev_op&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-20" name="rest_code_0428db88705248c5bf65bf80bb0bcede-20" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-20"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-21" name="rest_code_0428db88705248c5bf65bf80bb0bcede-21" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-21"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-22" name="rest_code_0428db88705248c5bf65bf80bb0bcede-22" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-22"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-23" name="rest_code_0428db88705248c5bf65bf80bb0bcede-23" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-23"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# strength reduce:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-24" name="rest_code_0428db88705248c5bf65bf80bb0bcede-24" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-24"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# x + x turns into x &amp;lt;&amp;lt; 1&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-25" name="rest_code_0428db88705248c5bf65bf80bb0bcede-25" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-25"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arg0&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-26" name="rest_code_0428db88705248c5bf65bf80bb0bcede-26" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-26"&gt;&lt;/a&gt;                &lt;span class="n"&gt;newop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-27" name="rest_code_0428db88705248c5bf65bf80bb0bcede-27" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-27"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-28" name="rest_code_0428db88705248c5bf65bf80bb0bcede-28" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-28"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-29" name="rest_code_0428db88705248c5bf65bf80bb0bcede-29" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-29"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-30" name="rest_code_0428db88705248c5bf65bf80bb0bcede-30" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-30"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# and while we are at it, let's do some&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-31" name="rest_code_0428db88705248c5bf65bf80bb0bcede-31" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-31"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# arithmetic simplification:&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-32" name="rest_code_0428db88705248c5bf65bf80bb0bcede-32" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-32"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# a + 0 =&amp;gt; a&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-33" name="rest_code_0428db88705248c5bf65bf80bb0bcede-33" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-33"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-34" name="rest_code_0428db88705248c5bf65bf80bb0bcede-34" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-34"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-35" name="rest_code_0428db88705248c5bf65bf80bb0bcede-35" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-35"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-36" name="rest_code_0428db88705248c5bf65bf80bb0bcede-36" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-36"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-37" name="rest_code_0428db88705248c5bf65bf80bb0bcede-37" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-37"&gt;&lt;/a&gt;                &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-38" name="rest_code_0428db88705248c5bf65bf80bb0bcede-38" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-38"&gt;&lt;/a&gt;                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-39" name="rest_code_0428db88705248c5bf65bf80bb0bcede-39" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-39"&gt;&lt;/a&gt;        &lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-40" name="rest_code_0428db88705248c5bf65bf80bb0bcede-40" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-40"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opt_bb&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-41" name="rest_code_0428db88705248c5bf65bf80bb0bcede-41" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-41"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-42" name="rest_code_0428db88705248c5bf65bf80bb0bcede-42" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-42"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-43" name="rest_code_0428db88705248c5bf65bf80bb0bcede-43" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-43"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_single_pass&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-44" name="rest_code_0428db88705248c5bf65bf80bb0bcede-44" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-44"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-45" name="rest_code_0428db88705248c5bf65bf80bb0bcede-45" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-45"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# constant folding&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-46" name="rest_code_0428db88705248c5bf65bf80bb0bcede-46" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-46"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-47" name="rest_code_0428db88705248c5bf65bf80bb0bcede-47" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-47"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-48" name="rest_code_0428db88705248c5bf65bf80bb0bcede-48" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-48"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-49" name="rest_code_0428db88705248c5bf65bf80bb0bcede-49" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-49"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-50" name="rest_code_0428db88705248c5bf65bf80bb0bcede-50" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-50"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-51" name="rest_code_0428db88705248c5bf65bf80bb0bcede-51" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-51"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-52" name="rest_code_0428db88705248c5bf65bf80bb0bcede-52" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-52"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-53" name="rest_code_0428db88705248c5bf65bf80bb0bcede-53" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-53"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-54" name="rest_code_0428db88705248c5bf65bf80bb0bcede-54" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-54"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = add(19, optvar0)"""&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-55" name="rest_code_0428db88705248c5bf65bf80bb0bcede-55" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-55"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-56" name="rest_code_0428db88705248c5bf65bf80bb0bcede-56" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-56"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# cse + strength reduction&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-57" name="rest_code_0428db88705248c5bf65bf80bb0bcede-57" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-57"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-58" name="rest_code_0428db88705248c5bf65bf80bb0bcede-58" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-58"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-59" name="rest_code_0428db88705248c5bf65bf80bb0bcede-59" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-59"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-60" name="rest_code_0428db88705248c5bf65bf80bb0bcede-60" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-60"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-61" name="rest_code_0428db88705248c5bf65bf80bb0bcede-61" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-61"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# the same as var3&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-62" name="rest_code_0428db88705248c5bf65bf80bb0bcede-62" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-62"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-63" name="rest_code_0428db88705248c5bf65bf80bb0bcede-63" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-63"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# the same as var4&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-64" name="rest_code_0428db88705248c5bf65bf80bb0bcede-64" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-64"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-65" name="rest_code_0428db88705248c5bf65bf80bb0bcede-65" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-65"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-66" name="rest_code_0428db88705248c5bf65bf80bb0bcede-66" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-66"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-67" name="rest_code_0428db88705248c5bf65bf80bb0bcede-67" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-67"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-68" name="rest_code_0428db88705248c5bf65bf80bb0bcede-68" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-68"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-69" name="rest_code_0428db88705248c5bf65bf80bb0bcede-69" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-69"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = getarg(1)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-70" name="rest_code_0428db88705248c5bf65bf80bb0bcede-70" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-70"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar2 = add(optvar0, optvar1)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-71" name="rest_code_0428db88705248c5bf65bf80bb0bcede-71" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-71"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar3 = add(optvar2, 2)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-72" name="rest_code_0428db88705248c5bf65bf80bb0bcede-72" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-72"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar4 = lshift(optvar3, 1)"""&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-73" name="rest_code_0428db88705248c5bf65bf80bb0bcede-73" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-73"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-74" name="rest_code_0428db88705248c5bf65bf80bb0bcede-74" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-74"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# removing + 0&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-75" name="rest_code_0428db88705248c5bf65bf80bb0bcede-75" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-75"&gt;&lt;/a&gt;    &lt;span class="n"&gt;bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-76" name="rest_code_0428db88705248c5bf65bf80bb0bcede-76" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-76"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-77" name="rest_code_0428db88705248c5bf65bf80bb0bcede-77" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-77"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-78" name="rest_code_0428db88705248c5bf65bf80bb0bcede-78" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-78"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-79" name="rest_code_0428db88705248c5bf65bf80bb0bcede-79" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-79"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-80" name="rest_code_0428db88705248c5bf65bf80bb0bcede-80" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-80"&gt;&lt;/a&gt;    &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-81" name="rest_code_0428db88705248c5bf65bf80bb0bcede-81" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-81"&gt;&lt;/a&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-82" name="rest_code_0428db88705248c5bf65bf80bb0bcede-82" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-82"&gt;&lt;/a&gt;    &lt;span class="n"&gt;opt_bb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-83" name="rest_code_0428db88705248c5bf65bf80bb0bcede-83" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-83"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bb_to_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt_bb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"optvar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-84" name="rest_code_0428db88705248c5bf65bf80bb0bcede-84" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-84"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar0 = getarg(0)&lt;/span&gt;
&lt;a id="rest_code_0428db88705248c5bf65bf80bb0bcede-85" name="rest_code_0428db88705248c5bf65bf80bb0bcede-85" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html#rest_code_0428db88705248c5bf65bf80bb0bcede-85"&gt;&lt;/a&gt;&lt;span class="s2"&gt;optvar1 = lshift(optvar0, 1)"""&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That's it for now. Why is this architecture cool? From a software engineering
point of view, sticking everything into a single function like in &lt;code class="docutils literal"&gt;optimize&lt;/code&gt;
above is obviously not great, and if you wanted to do this for real you would
try to split the cases into different functions that are individually
digestible, or even use a DSL that makes the pattern matching much more
readable. But the advantage of the architecture is that it's quite efficient,
it makes it possible to pack a lot of good optimizations into a single pass
over a basic block.&lt;/p&gt;
&lt;p&gt;Of course this works even better if you are in a tracing context, where
everything is put into a trace, which is basically one incredibly long basic
block. In a JIT context it's also quite important that the
optimizer itself runs quickly.&lt;/p&gt;
&lt;p&gt;Various other optimizations are possible in this model. There is a
&lt;a class="reference external" href="https://www.pypy.org/posts/2022/10/toy-optimizer-allocation-removal.html"&gt;follow-up post&lt;/a&gt; that show how to implement what is arguably PyPy's &lt;a class="reference external" href="https://www.pypy.org/posts/2010/09/escape-analysis-in-pypys-jit-1780048403046080197.html"&gt;most
important optimization&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="some-further-pointers"&gt;
&lt;h2&gt;Some Further Pointers&lt;/h2&gt;
&lt;p&gt;This post is only a short introduction and is taking some shortcuts, I wanted to
also give some (non-exhaustive) pointers to more general literature about the
touched topics.&lt;/p&gt;
&lt;p&gt;The approach to CSE described here is usually can be seen as &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Value_numbering"&gt;value
numbering&lt;/a&gt;, it's normally really implemented with a hashmap though. Here's a
&lt;a class="reference external" href="https://www.cs.tufts.edu/~nr/cs257/archive/keith-cooper/value-numbering.pdf"&gt;paper&lt;/a&gt; that describes various styles of implementing that, even beyond a
single basic block. The paper also partly takes the perspective of discovering
equivalence classes of operations that compute the same result.&lt;/p&gt;
&lt;p&gt;A technique that leans even more fully into finding equivalences between
operations is using e-graphs and then applying &lt;a class="reference external" href="https://en.wikipedia.org/wiki/E-graph#Equality_saturation"&gt;equality saturation&lt;/a&gt; (this is
significantly more advanced that what I described here though). A cool modern
project that applies this technique is &lt;a class="reference external" href="https://egraphs-good.github.io/"&gt;egg&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you squint a bit, you can generally view a constant folding pass as a very
simple form of &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Partial_evaluation"&gt;Partial Evaluation&lt;/a&gt;: every operation that has constant
arguments is constant-folded away, and the remaining ones are "residualized",
i.e. put into the output program. This point of view is not super important for
the current post, but will become important in the next one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Acknowledgements:&lt;/strong&gt; Thanks to &lt;a class="reference external" href="https://thorstenball.com/"&gt;Thorsten Ball&lt;/a&gt; for &lt;a class="reference external" href="https://twitter.com/cfbolz/status/1547231548017106944"&gt;getting me&lt;/a&gt; to write
this and for his enthusiastic feedback. I also got great feedback from &lt;a class="reference external" href="https://bernsteinbear.com/"&gt;Max
Bernstein&lt;/a&gt;, Matti Picus and Per Vognsen. A conversation with &lt;a class="reference external" href="https://pengwu.substack.com/"&gt;Peng Wu&lt;/a&gt; that
we had many many years ago and that stuck with me made me keep thinking about
various ways to view compiler optimizations.&lt;/p&gt;
&lt;/section&gt;</description><category>toy-optimizer</category><guid>https://www.pypy.org/posts/2022/07/toy-optimizer.html</guid><pubDate>Tue, 19 Jul 2022 12:00:00 GMT</pubDate></item></channel></rss>