<?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 by Carl Friedrich Bolz-Tereick)</title><link>https://www.pypy.org/</link><description></description><atom:link href="https://www.pypy.org/authors/carl-friedrich-bolz-tereick.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:15 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>The PyPy Blog Turns 15 Years</title><link>https://www.pypy.org/posts/2022/10/blog-15-years.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;p&gt;Exactly 15 years ago today we wrote the &lt;a class="reference external" href="https://www.pypy.org/posts/2007/10/first-post-8150793557471983289.html"&gt;first blog post on the PyPy blog&lt;/a&gt;!
Over the years, we have written 423 posts, from the &lt;a class="reference external" href="https://www.pypy.org/posts/2007/12/faster-than-c-8057790636822502084.html"&gt;shortest&lt;/a&gt; to the
&lt;a class="reference external" href="https://www.pypy.org/posts/2022/07/toy-optimizer.html"&gt;longest&lt;/a&gt;. In 2021 we &lt;a class="reference external" href="https://www.pypy.org/posts/2021/03/pypys-blog-has-moved.html"&gt;moved&lt;/a&gt; from &lt;a class="reference external" href="https://morepypy.blogspot.com"&gt;blogger&lt;/a&gt; to our own domain.&lt;/p&gt;
&lt;p&gt;The topics over the years varied widely, we published &lt;a class="reference external" href="https://www.pypy.org/posts/2013/05/pypy-20-einstein-sandwich-635158782365435530.html"&gt;release&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2017/06/pypy-v58-released-739876359584854017.html"&gt;announcements&lt;/a&gt;;
&lt;a class="reference external" href="https://www.pypy.org/posts/2009/04/roadmap-for-jit-377358891902851723.html"&gt;roadmaps&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2010/06/blackhole-interpreter-2752965445510091289.html"&gt;JIT&lt;/a&gt;, &lt;a class="reference external" href="https://www.pypy.org/posts/2013/10/incremental-garbage-collector-in-pypy-8956893523842234676.html"&gt;GC&lt;/a&gt; and &lt;a class="reference external" href="https://www.pypy.org/posts/2013/10/update-on-stm-7145890443443707910.html"&gt;STM&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2019/07/pypy-jit-for-aarch64-7161523403247118006.html"&gt;updates&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2018/06/repeating-matrix-multiplication-8641748742577945875.html"&gt;benchmarks&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2008/10/dsseldorf-sprint-report-days-1-3-5256639868851086032.html"&gt;sprint&lt;/a&gt;, &lt;a class="reference external" href="https://www.pypy.org/posts/2007/11/pypy-road-show-1-new-york-and-ibm-7837076523877011699.html"&gt;trip&lt;/a&gt; and
&lt;a class="reference external" href="https://www.pypy.org/posts/2009/07/ecoop-2009-8415055006373020774.html"&gt;conference&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2012/04/pycon-2012-wrap-up-559575896040055505.html"&gt;reports&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2016/07/reverse-debugging-for-python-8854823774141612670.html"&gt;technical&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2010/11/efficiently-implementing-python-objects-3838329944323946932.html"&gt;deep&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2015/10/pypy-memory-and-warmup-improvements-2-4598780879518640015.html"&gt;dives&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2022/02/nlp-icelandic-case-study.html"&gt;case studies&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2008/04/trying-to-get-pypy-to-run-on-python-30-5082015544752137606.html"&gt;april&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2008/04/other-aprils-fools-ideas-955926452383759016.html"&gt;fool's
jokes&lt;/a&gt;; &lt;a class="reference external" href="https://www.pypy.org/posts/2015/03/pydgin-using-rpython-to-generate-fast-1514065178985838697.html"&gt;research&lt;/a&gt; projects; &lt;a class="reference external" href="https://www.pypy.org/posts/2013/02/announcing-topaz-rpython-powered-ruby-6662407703061538341.html"&gt;other&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2012/07/hello-everyone-6869934374873967346.html"&gt;languages&lt;/a&gt; &lt;a class="reference external" href="https://www.pypy.org/posts/2014/08/a-field-test-of-software-transactional-5659022209916605798.html"&gt;using&lt;/a&gt; RPython; finished &lt;a class="reference external" href="https://www.pypy.org/posts/2010/10/phd-thesis-about-pypys-cli-jit-backend-969267841095296323.html"&gt;PhD&lt;/a&gt;
&lt;a class="reference external" href="https://www.pypy.org/posts/2019/04/an-rpython-jit-for-lpegs-4779548053359386284.html"&gt;Bachelor&lt;/a&gt; and &lt;a class="reference external" href="https://www.pypy.org/posts/2008/10/prolog-jit-masters-thesis-finished-5462132148241449867.html"&gt;Master&lt;/a&gt;, theses; pictures:&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://www.pypy.org/images/2022-pypy-pictures-collage.jpg"&gt;
&lt;img alt="a collage of photos taken at PyPy sprints" src="https://www.pypy.org/images/2022-pypy-pictures-collage-small.jpg"&gt;
&lt;/a&gt;
&lt;p&gt;and diagrams:&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://www.pypy.org/images/2022-pypy-diagrams-collage.png"&gt;
&lt;img alt="a collage of diagrams from previous blog posts" src="https://www.pypy.org/images/2022-pypy-diagrams-collage-small.png"&gt;
&lt;/a&gt;
&lt;p&gt;Quite a number of blog posts were very early iterations of papers that we
published later, here are a few that I can remember:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2009/03/applying-tracing-jit-to-interpreter-3287844903778799266.html"&gt;Applying a Tracing JIT to an Interpreter&lt;/a&gt; became &lt;a class="reference external" href="https://dl.acm.org/doi/10.1145/1565824.1565827"&gt;Tracing the meta-level:
PyPy's tracing JIT compiler&lt;/a&gt; at ICOOOLPS 2009, by far our most successful
paper.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2010/09/escape-analysis-in-pypys-jit-1780048403046080197.html"&gt;Escape Analysis in PyPy's JIT&lt;/a&gt; became &lt;a class="reference external" href="https://dl.acm.org/doi/10.1145/1929501.1929508"&gt;Allocation removal by partial
evaluation in a tracing JIT&lt;/a&gt; at PEPM 2010.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2011/03/controlling-tracing-of-interpreter-with_21-6524148550848694588.html"&gt;Controlling the Tracing of an Interpreter With Hints&lt;/a&gt; was a draft of the
paper &lt;a class="reference external" href="https://dl.acm.org/doi/10.1145/2069172.2069181"&gt;Runtime feedback in a meta-tracing JIT for efficient dynamic
languages&lt;/a&gt; at ICOOOLPS 2011&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2010/09/using-escape-analysis-across-loop-2887031293132023676.html"&gt;Using Escape Analysis Across Loop Boundaries for Specialization&lt;/a&gt; was the
nucleus of &lt;a class="reference external" href="https://dl.acm.org/doi/10.1145/2384577.2384586"&gt;Loop-aware optimizations in PyPy's tracing JIT&lt;/a&gt; at DLS 2012.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2011/10/more-compact-lists-with-list-strategies-8229304944653956829.html"&gt;List Strategies&lt;/a&gt; was eventually turned into the paper &lt;a class="reference external" href="https://dl.acm.org/doi/10.1145/2509136.2509531"&gt;Storage strategies
for collections in dynamically typed languages&lt;/a&gt; at OOPSLA 2013.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id="greatest-hits"&gt;
&lt;h2&gt;Greatest Hits&lt;/h2&gt;
&lt;p&gt;In terms of visitors, the top five posts on the old blog were – on the new blog
we simply don't have stats (yet?):&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2017/08/lets-remove-global-interpreter-lock-748023554216649595.html"&gt;Let's remove the global interpreter lock&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2011/04/tutorial-writing-interpreter-with-pypy-3785910476193156295.html"&gt;Tutorial: Writing an Interpreter with PyPy, Part 1&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html"&gt;PyPy's new JSON parser&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2016/08/pypy-gets-funding-from-mozilla-for-5569307998787871200.html"&gt;PyPy gets funding from Mozilla for Python 3.5 support&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2017/10/how-to-make-your-code-80-times-faster-1424098117108093942.html"&gt;How to make your code 80 times faster&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The number of posts per year developed like this:&lt;/p&gt;
&lt;img alt="/images/2022-pypy-posts-per-year.svg" src="https://www.pypy.org/images/2022-pypy-posts-per-year.svg"&gt;
&lt;p&gt;The most prolific authors are:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/authors/maciej-fijalkowski.html"&gt;Maciej Fijałkowski&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/authors/carl-friedrich-bolz-tereick.html"&gt;Carl Friedrich Bolz-Tereick&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/authors/armin-rigo.html"&gt;Armin Rigo&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/authors/antonio-cuni.html"&gt;Antonio Cuni&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/authors/mattip.html"&gt;Matti Picus&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Several blog posts have made it to the Hacker News front page, three of them to
number 1:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2014/07/pypy-stm-first-interesting-release-8684276541915333814.html"&gt;PyPy-STM: first “interesting” release&lt;/a&gt; (&lt;a class="reference external" href="https://news.ycombinator.com/item?id=7991404"&gt;discussion&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2017/08/lets-remove-global-interpreter-lock-748023554216649595.html"&gt;Let's Remove the Global Interpreter Lock&lt;/a&gt; (&lt;a class="reference external" href="https://news.ycombinator.com/item?id=15008636"&gt;discussion&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pypy.org/posts/2018/09/inside-cpyext-why-emulating-cpython-c-8083064623681286567.html"&gt;Inside cpyext: Why emulating CPython C API is so Hard&lt;/a&gt; (&lt;a class="reference external" href="https://news.ycombinator.com/item?id=18040664"&gt;discussion&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="personal-favourites"&gt;
&lt;h2&gt;Personal Favourites&lt;/h2&gt;
&lt;p&gt;While looking through the posts, there were a few that stood out to me in some
way, so here's a subjective list of ones that I had fun looking at again:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;2008: &lt;a class="reference external" href="https://www.pypy.org/posts/2008/10/sprint-discussions-jit-generator-3301578822967655604.html"&gt;Sprint Discussions: JIT Generator Planning&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2009: &lt;a class="reference external" href="https://www.pypy.org/posts/2009/08/pypy-gets-new-compiler_25-6401910947439531107.html"&gt;PyPy gets a new compiler&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2010: &lt;a class="reference external" href="https://www.pypy.org/posts/2010/12/oh-and-btw-pypy-gets-funding-through-3568486750776147382.html"&gt;Oh, and btw: PyPy gets funding through "Eurostars"&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2011: &lt;a class="reference external" href="https://www.pypy.org/posts/2011/07/realtime-image-processing-in-python-6985924592886873374.html"&gt;Realtime image processing in Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2012: &lt;a class="reference external" href="https://www.pypy.org/posts/2012/06/architecture-of-cppyy-9077100041707701102.html"&gt;Architecture of Cppyy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2013: &lt;a class="reference external" href="https://www.pypy.org/posts/2013/02/10-years-of-pypy-634401291726575821.html"&gt;10 years of PyPy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2014: &lt;a class="reference external" href="https://www.pypy.org/posts/2014/11/pypy-io-improvements-1042070332447047674.html"&gt;PyPy IO Improvements&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2015: &lt;a class="reference external" href="https://www.pypy.org/posts/2015/10/automatic-simd-vectorization-support-in-639063580401330508.html"&gt;Automatic SIMD vectorization support in PyPy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2016: &lt;a class="reference external" href="https://www.pypy.org/posts/2016/04/pypy-enterprise-edition-3688275697656890948.html"&gt;PyPy Enterprise Edition&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2017: &lt;a class="reference external" href="https://www.pypy.org/posts/2017/03/async-http-benchmarks-on-pypy3-1092124994927894138.html"&gt;Async HTTP benchmarks on PyPy3&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2018: &lt;a class="reference external" href="https://www.pypy.org/posts/2018/04/improving-syntaxerror-in-pypy-5733639208090522433.html"&gt;Improving SyntaxError in PyPy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2018: &lt;a class="reference external" href="https://www.pypy.org/posts/2018/09/the-first-15-years-of-pypy-3412615975376972020.html#incentives-of-oss-compared-to-academia"&gt;The First 15 Years of PyPy — a Personal Retrospective&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2019: &lt;a class="reference external" href="https://www.pypy.org/posts/2019/01/pypy-for-low-latency-systems-613165393301401965.html"&gt;PyPy for low-latency systems&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2020: &lt;a class="reference external" href="https://www.pypy.org/posts/2020/02/pypy-and-cffi-have-moved-to-heptapod-5791595152472747032.html"&gt;PyPy and CFFI have moved to Heptapod&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2021: &lt;a class="reference external" href="https://www.pypy.org/posts/2021/04/ways-pypy-graphviz.html"&gt;Some Ways that PyPy uses Graphviz&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We'd like to thank our authors, guest authors, commenters, users and readers who
have stuck with us through one and a half decades! If there's any particular
topics you would like to read something about, or any guest posts you'd like to
write, let us know!&lt;/p&gt;
&lt;/section&gt;</description><category>meta</category><guid>https://www.pypy.org/posts/2022/10/blog-15-years.html</guid><pubDate>Sun, 30 Oct 2022 12:00: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>Düsseldorf HPy/PyPy/GraalPy sprint September 19-23rd 2022</title><link>https://www.pypy.org/posts/2022/07/ddorf-sprint-sep-2022.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;p&gt;The programming language group of the Computer Science department of
Heinrich-Heine Universität Düsseldorf is happy to invite everybody to another
sprint in Düsseldorf, from the 19th to the 23rd of September 2022. This is a
fully public sprint, everyone and particularly newcomers are welcome to join
us! The goal is to bring together people from the &lt;a class="reference external" href="https://hpyproject.org/"&gt;HPy&lt;/a&gt;, PyPy, &lt;a class="reference external" href="https://www.graalvm.org/python/"&gt;GraalPy&lt;/a&gt; and
CPython communities.&lt;/p&gt;
&lt;section id="topics-and-goals"&gt;
&lt;h2&gt;Topics and goals&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;work on HPy APIs, discussions around next steps for the project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;continuing new and ongoing ports to HPy, including Cython, NumPy, Pillow, Matplotlib&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;3.10 support on PyPy and GraalPy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;preparing the next PyPy release&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;discussions around ways to improve collaboration between the different Python
implementations&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="what-is-a-sprint"&gt;
&lt;h2&gt;What is a sprint?&lt;/h2&gt;
&lt;p&gt;The experience of the PyPy project has shown the benefits of regular
sprints. They are focussed one week physical meetings where people pair-program
on new features and discuss future plans. Coming to one is a great way to get
started with a project!&lt;/p&gt;
&lt;/section&gt;
&lt;section id="location"&gt;
&lt;h2&gt;Location&lt;/h2&gt;
&lt;p&gt;The sprint will take place in a seminar room of the computer science
department.  It is in the building 25.12, room 02.50 (second floor) of the
university campus. For travel instructions see&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.cs.hhu.de/lehrstuehle-und-arbeitsgruppen/softwaretechnik-und-programmiersprachen/kontakt/service/lage-und-anreise"&gt;https://www.cs.hhu.de/lehrstuehle-und-arbeitsgruppen/softwaretechnik-und-programmiersprachen/kontakt/service/lage-und-anreise&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We ask participants to wear masks during the indoor working hours.&lt;/p&gt;
&lt;figure&gt;
&lt;a class="reference external image-reference" href="https://commons.wikimedia.org/wiki/File:Universitaets-_und_Landesbibliothek_Duesseldorf_in_Duesseldorf-Bilk,_von_Nordwesten.jpg"&gt;
&lt;img alt="Photograph of the statue of Heinrich Heine in front of the University library on the campus in Düsseldorf" src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Universitaets-_und_Landesbibliothek_Duesseldorf_in_Duesseldorf-Bilk%2C_von_Nordwesten.jpg/640px-Universitaets-_und_Landesbibliothek_Duesseldorf_in_Duesseldorf-Bilk%2C_von_Nordwesten.jpg"&gt;
&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Wiegels, CC BY 3.0, via Wikimedia Commons&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="exact-times"&gt;
&lt;h2&gt;Exact times&lt;/h2&gt;
&lt;p&gt;Work days: starting September 19th (~morning), ending September 23rd (~afternoon).
We will do a to-be-planned social activity on Wednesday afternoon.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="registration"&gt;
&lt;h2&gt;Registration&lt;/h2&gt;
&lt;p&gt;Please register by editing this file or by opening a &lt;a class="reference external" href="https://doc.pypy.org/coding-guide.html"&gt;pull request&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a class="reference external" href="https://foss.heptapod.net/pypy/extradoc/-/blob/branch/extradoc/sprintinfo/ddorf2022/people.txt"&gt;https://foss.heptapod.net/pypy/extradoc/-/blob/branch/extradoc/sprintinfo/ddorf2022/people.txt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;or by sending a quick mail to the pypy-dev mailing list:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a class="reference external" href="http://mail.python.org/mailman/listinfo/pypy-dev"&gt;http://mail.python.org/mailman/listinfo/pypy-dev&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/section&gt;</description><category>sprints</category><guid>https://www.pypy.org/posts/2022/07/ddorf-sprint-sep-2022.html</guid><pubDate>Fri, 29 Jul 2022 12:00: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><item><title>How is PyPy Tested?</title><link>https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;section id="how-is-pypy-tested"&gt;
&lt;h2&gt;How is PyPy Tested?&lt;/h2&gt;
&lt;p&gt;In this post I want to give an overview of how the PyPy project does and thinks
about testing. PyPy takes testing quite seriously and has done some from the
start of the project. Here I want to present the different styles of
tests that PyPy has, when we use them and how I think about them.&lt;/p&gt;
&lt;section id="background"&gt;
&lt;h3&gt;Background&lt;/h3&gt;
&lt;p&gt;To make the blog post self-contained, I am going to start with a small overview
about PyPy's architecture. If you already know what PyPy is and how it works,
you can skip this section.&lt;/p&gt;
&lt;p&gt;PyPy means "Python in Python". It is an alternative implementation of the Python
language. Usually, when we speak of "Python", we can mean two different things.
On the one hand it means "Python as an abstract programming language". On the
other hand, the main implementation of that language is also often called
"Python". To more clearly distinguish the two, the implementation is often also
called "CPython", because it is an interpreter implemented in C code.&lt;/p&gt;
&lt;p&gt;Now we can make the statement "PyPy is Python in Python" more precise: PyPy is
an interpreter for Python 3.9, implemented in RPython. RPython ("Restricted
Python") is a subset of Python 2, which is statically typed (using type
inference, not type annotations) and can be compiled
to C code. That means we can take our Python 3.9 interpreter, and compile it
into a C binary that can run Python 3.9 code. The final binary behaves pretty
similarly to CPython.&lt;/p&gt;
&lt;p&gt;The main thing that makes PyPy interesting is that during the translation of our
interpreter to C, a number of components are automatically inserted into the
final binary. One component is a reasonably good garbage collector.&lt;/p&gt;
&lt;p&gt;The more exciting component that is inserted into the binary is a just-in-time
compiler. The insertion of this component is not fully automatic, instead it is
guided by a small number of annotations in the source code of the interpreter.
The effect of inserting this JIT compiler into the binary is that the resulting
binary can run Python code significantly faster than CPython, in many cases.
How this works is not important for the rest of the post, if you want to see an
example of concretely doing that to a small interpreter you can look at this
&lt;a class="reference external" href="https://www.youtube.com/watch?v=fZj3uljJl_k"&gt;video&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="pypy-testing-history"&gt;
&lt;h3&gt;PyPy Testing History&lt;/h3&gt;
&lt;p&gt;A few historical notes on the PyPy project and its relationship to testing: The
PyPy project &lt;a class="reference external" href="https://www.pypy.org/posts/2018/09/the-first-15-years-of-pypy-3412615975376972020.html"&gt;was started in 2004&lt;/a&gt;. At the time when the project was started,
Extreme Programming and Agile Software Development were up and coming. On the
methodology side, PyPy was heavily influenced by these, and started using
Test-Driven Development and pair programming right from the start.&lt;/p&gt;
&lt;p&gt;Also technologically, PyPy has been influential on testing in the Python world.
Originally, PyPy had used the &lt;code class="docutils literal"&gt;unittest&lt;/code&gt; testing framework, but pretty soon
the developers got frustrated with it. &lt;a class="reference external" href="https://holgerkrekel.net/"&gt;Holger Krekel&lt;/a&gt;, one of the original
developers who started PyPy, started the &lt;a class="reference external" href="https://pytest.org/"&gt;pytest&lt;/a&gt; testing framework soon
afterwards.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="interpreter-level-tests"&gt;
&lt;h3&gt;Interpreter-Level Tests&lt;/h3&gt;
&lt;p&gt;So, how are tests for PyPy written, concretely? The tests for the interpreter
are split into two different kinds, which we call "interpreter level tests" and
"application level tests". The former are tests that can be used to test the
objects and functions that are used in the implementation of the Python
interpreter. Since the interpreter is written in Python 2, those tests are also
written in Python 2, using pytest. They tend to be more on the unit test side of
things. They are in files with the pattern &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;test_*.py&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example that tests the implementation of integers (very slightly
simplified):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-1" name="rest_code_383a09e745ab4a959d467b907abc1452-1" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-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;TestW_IntObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-2" name="rest_code_383a09e745ab4a959d467b907abc1452-2" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-2"&gt;&lt;/a&gt;    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-3" name="rest_code_383a09e745ab4a959d467b907abc1452-3" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-3"&gt;&lt;/a&gt;
&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-4" name="rest_code_383a09e745ab4a959d467b907abc1452-4" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-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;test_hash&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_383a09e745ab4a959d467b907abc1452-5" name="rest_code_383a09e745ab4a959d467b907abc1452-5" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-5"&gt;&lt;/a&gt;        &lt;span class="n"&gt;w_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;W_IntObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-6" name="rest_code_383a09e745ab4a959d467b907abc1452-6" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-6"&gt;&lt;/a&gt;        &lt;span class="n"&gt;w_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w_x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descr_hash&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;space&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-7" name="rest_code_383a09e745ab4a959d467b907abc1452-7" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-7"&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;w_result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;W_IntObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_383a09e745ab4a959d467b907abc1452-8" name="rest_code_383a09e745ab4a959d467b907abc1452-8" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_383a09e745ab4a959d467b907abc1452-8"&gt;&lt;/a&gt;        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;w_result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intval&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This test checks that if you take an object that represents integers in the
Python language (using the class &lt;code class="docutils literal"&gt;W_IntObject&lt;/code&gt;, a "wrapped integer object")
with the value 42, computing the hash of that object returns another instance of
the same class, also with the value 42.&lt;/p&gt;
&lt;p&gt;These tests can be run on top of any Python 2 implementation, either CPython or
PyPy. We can then test and debug the internals of the PyPy interpreter using
familiar tools like indeed pytest and the Python debuggers. They can be run,
because all the involved code like the tests and the class &lt;code class="docutils literal"&gt;W_IntObject&lt;/code&gt; are
just completely regular Python 2 classes that behave in the regular way when
run on top of a Python interpreter.&lt;/p&gt;
&lt;p&gt;In CPython, these tests don't really have an equivalent. They would correspond
to tests that are written in C and that can test the logic of all the C
functions of CPython that execute certain functionality, accessing the internals
of C structs in the process. &lt;a class="reference internal" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#target-1"&gt;¹&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id="application-level-tests"&gt;
&lt;h3&gt;Application-Level Tests&lt;/h3&gt;
&lt;p&gt;There is also a second class of tests for the interpreter. Those are tests that
don't run on the level of the implementation. Instead, they are executed &lt;em&gt;by&lt;/em&gt;
the PyPy Python interpreter, thus running on the level of the applications run
by PyPy. Since the interpreter is running Python 3, the tests are also written
in Python 3. They are stored in files with the pattern &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;apptest_*.py&lt;/span&gt;&lt;/code&gt; and
look like "regular" Python 3 tests. &lt;a class="reference internal" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#target-2"&gt;²&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's an example of how you could write a test equivalent to the one above:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_85f73a1aaebd40e6a6e0e79aab5f0776-1" name="rest_code_85f73a1aaebd40e6a6e0e79aab5f0776-1" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_85f73a1aaebd40e6a6e0e79aab5f0776-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_hash&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_85f73a1aaebd40e6a6e0e79aab5f0776-2" name="rest_code_85f73a1aaebd40e6a6e0e79aab5f0776-2" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_85f73a1aaebd40e6a6e0e79aab5f0776-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This style of test looks more "natural" and is the preferred one in cases where
the test does not need to access the internals of the logic or the objects of
the interpreter.&lt;/p&gt;
&lt;p&gt;Application level tests can be run in two different ways. On the one hand, we
can simply run them on CPython 3. This is very useful! Since we want PyPy to
behave like CPython, running the tests that we write on CPython is useful to
make sure that the tests themselves aren't wrong.&lt;/p&gt;
&lt;p&gt;On the other hand, the main way to run these tests is on top of PyPy, itself
running on top of a Python 2 implementation. This makes it possible to run the
test without first bootstrapping PyPy to C. Since bootstrapping to C is a
relatively slow operation (can take up to an hour) it is crucially important to
be able to run tests without bootstrapping first. It also again makes it
possible to debug crashes in the interpreter using the regular Python 2
debugger. Of course running tests in this way is unfortunately itself not super
fast, given that they run on a stack of two different interpreters.&lt;/p&gt;
&lt;p&gt;Application-level tests correspond quite closely to CPython's tests suite (which
is using the unittest framework). Of course in CPython it is not possible to run
the test suite without building the CPython binary using a C compiler. &lt;a class="reference internal" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#target-3"&gt;³&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So when do we write application-level tests, and when interpreter-level tests?
Interpreter-level tests are necessary to test internal data structures that
touch data and logic that is not directly exposed to the Python language. If
that is not necessary, we try to write application-level tests. App-level tests
are however by their nature always more on the integration test side of things.
To be able to run the &lt;code class="docutils literal"&gt;test_hash&lt;/code&gt; function above, many parts of PyPy need to
work correctly, the parser, the bytecode compiler, the bytecode interpreter, the
&lt;code class="docutils literal"&gt;hash&lt;/code&gt; builtin, calling the &lt;code class="docutils literal"&gt;__hash__&lt;/code&gt; special method, etc, etc.&lt;/p&gt;
&lt;p&gt;This observation is also true for CPython! One could argue that CPython has no
unit tests at all, because in order to be able to even run the tests, most of
Python needs to be in working order already, so all the tests are really
implicitly integration tests.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-cpython-test-suite"&gt;
&lt;h3&gt;The CPython Test Suite&lt;/h3&gt;
&lt;p&gt;We also use the CPython Test suite as a final check to see whether our
interpreter correctly implements all the features of the Python language. In
that sense it acts as some kind of compliance test suite that checks whether we
implement the language correctly. The test suite is not perfect for this.
Since it is written for CPython's purposes during its development, a
lot of the tests check really specific CPython implementation details. Examples
for these are tests that check that &lt;code class="docutils literal"&gt;__del__&lt;/code&gt; is called immediately after
objects go out of scope (which only happens if you use reference counting as a
garbage collection strategy, PyPy uses a &lt;a class="reference external" href="https://www.pypy.org/posts/2013/10/incremental-garbage-collector-in-pypy-8956893523842234676.html"&gt;different approach to garbage
collection&lt;/a&gt;). Other examples are checking
for exception error messages very explicitly. However, the CPython test suite
has gotten a lot better in these regards over time, by adding
&lt;code class="docutils literal"&gt;support.gc_collect()&lt;/code&gt; calls to fix the former problem, and by marking some
very specific tests with the &lt;code class="docutils literal"&gt;@impl_detail&lt;/code&gt; decorator. Thanks to all the
CPython developers who have worked on this!&lt;/p&gt;
&lt;p&gt;In the process of re-implementing CPython's functionality and running CPython's
tests suite, PyPy can often also be a good way to find bugs in CPython. While we
think about the corner cases of some Python feature we occasionally find
situations where CPython didn't get everything completely correct either, which
we then report back.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="testing-for-performance-regressions"&gt;
&lt;h3&gt;Testing for Performance Regressions&lt;/h3&gt;
&lt;p&gt;All the tests we described so far are checking &lt;em&gt;behaviour&lt;/em&gt;. But one of PyPy's
important goals is to be a &lt;em&gt;fast&lt;/em&gt; implementation not "just" a correct one. Some
aspects of performance can be tested by regular unit tests, either application-
or interpreter-level. In order to check whether some performance shortcut is
taken in the interpreter, we sometimes can write tests that monkeypatch the slow
default implementation to always error. Then, if the fast path is taken
properly, that slow default implementation is never reached.&lt;/p&gt;
&lt;p&gt;But we also have additional tests that test the correct interaction with the JIT
explicitly. For that, we have a special style of test that checks that the JIT
will produce the correct machine code for a small snippet of Python code. To
make this kind of test somewhat more robust, we don't check the machine code
directly, but instead the architecture independent &lt;a class="reference external" href="https://www.pypy.org/posts/2018/09/the-first-15-years-of-pypy-3412615975376972020.html"&gt;intermediate
representation&lt;/a&gt; that the JIT uses to produce machine code from.&lt;/p&gt;
&lt;p&gt;As an example, here is a small test that loading the attribute of a constant
global instance can be completely constant folded away:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-1" name="rest_code_42db78a249444fb5be75e39f63c3c734-1" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-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_attr&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_42db78a249444fb5be75e39f63c3c734-2" name="rest_code_42db78a249444fb5be75e39f63c3c734-2" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'''&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-3" name="rest_code_42db78a249444fb5be75e39f63c3c734-3" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-3"&gt;&lt;/a&gt;&lt;span class="s1"&gt;        class A(object):&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-4" name="rest_code_42db78a249444fb5be75e39f63c3c734-4" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-4"&gt;&lt;/a&gt;&lt;span class="s1"&gt;            pass&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-5" name="rest_code_42db78a249444fb5be75e39f63c3c734-5" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-5"&gt;&lt;/a&gt;&lt;span class="s1"&gt;        a = A()&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-6" name="rest_code_42db78a249444fb5be75e39f63c3c734-6" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-6"&gt;&lt;/a&gt;&lt;span class="s1"&gt;        a.x = 1&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-7" name="rest_code_42db78a249444fb5be75e39f63c3c734-7" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-7"&gt;&lt;/a&gt;&lt;span class="s1"&gt;        def main(n):&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-8" name="rest_code_42db78a249444fb5be75e39f63c3c734-8" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-8"&gt;&lt;/a&gt;&lt;span class="s1"&gt;            i = 0&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-9" name="rest_code_42db78a249444fb5be75e39f63c3c734-9" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-9"&gt;&lt;/a&gt;&lt;span class="s1"&gt;            while i &amp;lt; n:&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-10" name="rest_code_42db78a249444fb5be75e39f63c3c734-10" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-10"&gt;&lt;/a&gt;&lt;span class="s1"&gt;                i = i + a.x&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-11" name="rest_code_42db78a249444fb5be75e39f63c3c734-11" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-11"&gt;&lt;/a&gt;&lt;span class="s1"&gt;            return i&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-12" name="rest_code_42db78a249444fb5be75e39f63c3c734-12" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-12"&gt;&lt;/a&gt;&lt;span class="s1"&gt;    '''&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-13" name="rest_code_42db78a249444fb5be75e39f63c3c734-13" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-13"&gt;&lt;/a&gt;    &lt;span class="n"&gt;log&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-14" name="rest_code_42db78a249444fb5be75e39f63c3c734-14" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-14"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-15" name="rest_code_42db78a249444fb5be75e39f63c3c734-15" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-15"&gt;&lt;/a&gt;    &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loops_by_filename&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;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-16" name="rest_code_42db78a249444fb5be75e39f63c3c734-16" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-16"&gt;&lt;/a&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"""&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-17" name="rest_code_42db78a249444fb5be75e39f63c3c734-17" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-17"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        i9 = int_lt(i5, i6)&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-18" name="rest_code_42db78a249444fb5be75e39f63c3c734-18" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-18"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        guard_true(i9, descr=...)&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-19" name="rest_code_42db78a249444fb5be75e39f63c3c734-19" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-19"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        guard_not_invalidated(descr=...)&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-20" name="rest_code_42db78a249444fb5be75e39f63c3c734-20" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-20"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        i10 = int_add(i5, 1)&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-21" name="rest_code_42db78a249444fb5be75e39f63c3c734-21" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-21"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        --TICK--&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-22" name="rest_code_42db78a249444fb5be75e39f63c3c734-22" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-22"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        jump(..., descr=...)&lt;/span&gt;
&lt;a id="rest_code_42db78a249444fb5be75e39f63c3c734-23" name="rest_code_42db78a249444fb5be75e39f63c3c734-23" href="https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html#rest_code_42db78a249444fb5be75e39f63c3c734-23"&gt;&lt;/a&gt;&lt;span class="s2"&gt;    """&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The string passed to the &lt;code class="docutils literal"&gt;loop.match&lt;/code&gt; function is a string representation of
the intermediate representation code that is generated for the &lt;code class="docutils literal"&gt;while&lt;/code&gt; loop in
the &lt;code class="docutils literal"&gt;main&lt;/code&gt; function given in the source. The important part of that
intermediate representation is that the &lt;code class="docutils literal"&gt;i = i + a.x&lt;/code&gt; addition is optimized
into an &lt;code class="docutils literal"&gt;int_add(x, 1)&lt;/code&gt; operation. The second argument for the addition is the
constant &lt;code class="docutils literal"&gt;1&lt;/code&gt;, because the JIT noted that the global &lt;code class="docutils literal"&gt;a&lt;/code&gt; is a constant, and
the attribute &lt;code class="docutils literal"&gt;x&lt;/code&gt; of that instance is always &lt;code class="docutils literal"&gt;1&lt;/code&gt;. The test thus checks that
this optimization still works.&lt;/p&gt;
&lt;p&gt;Those tests are again more on the unit test side of things (and can thus
unfortunately be a bit brittle sometimes and break). The integration test
equivalent for performance is the &lt;a class="reference external" href="https://speed.pypy.org/"&gt;PyPy Speed Center&lt;/a&gt; which tracks the
performance of micro- and macro-benchmarks over time and lets us see when big
performance regressions are happening. The speed center is not really an
automatic test and does not produce pass/fail outcomes. Instead, it requires
human judgement and intervention in order to interpret the performance changes.
Having a real pass/fail mechanism is something that would be &lt;a class="reference external" href="https://twitter.com/glyph/status/1495122754286198790"&gt;great to have&lt;/a&gt;
but is probably &lt;a class="reference external" href="https://arxiv.org/abs/1602.00602"&gt;quite tricky in practice&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="conclusion"&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This concludes my overview of some of the different styles of tests that we use
to develop the PyPy Python interpreter.&lt;/p&gt;
&lt;p&gt;There is a whole other set of tests for the development of the RPython language,
the garbage collectors it provides as well as the code that does the automatic
JIT insertion, maybe I'll cover these in a future post.&lt;/p&gt;
&lt;section id="footnotes"&gt;
&lt;h4&gt;Footnotes&lt;/h4&gt;
&lt;p id="target-1"&gt;¹ CPython has the &lt;cite&gt;_testcapimodule.c&lt;/cite&gt; and related modules, that are used to
unit-test the C-API. However, these are still driven from Python tests using
the &lt;code class="docutils literal"&gt;unittest&lt;/code&gt; framework and wouldn't run without the Python interpreter
already working.&lt;/p&gt;
&lt;p id="target-2"&gt;² There is also a deprecated different way to write these tests, by putting
them in the &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;test_*.py&lt;/span&gt;&lt;/code&gt; files that interpreter level tests are using and
then having a test class with the pattern &lt;code class="docutils literal"&gt;class AppTest*&lt;/code&gt;. We haven't
converted all of them to the new style yet, even though the old style is
quite weird: since the &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;test_*.py&lt;/span&gt;&lt;/code&gt; files are themselves parsed by
Python 2, the tests methods in &lt;code class="docutils literal"&gt;AppTest*&lt;/code&gt; classes need to be written in the
subset of Python 3 syntax that is also valid Python 2 syntax, leading to a lot
of confusion.&lt;/p&gt;
&lt;p id="target-3"&gt;³ Nit-picky side-note: &lt;a class="reference external" href="https://root.cern.ch/root/html534/guides/users-guide/CINT.html"&gt;C interpreters&lt;/a&gt; &lt;a class="reference external" href="https://www.youtube.com/watch?v=yyDD_KRdQQU"&gt;are a thing&lt;/a&gt;! But not that
widely used in practice, or only in very specific situations.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;</description><guid>https://www.pypy.org/posts/2022/04/how-is-pypy-tested.html</guid><pubDate>Sat, 02 Apr 2022 15:00:00 GMT</pubDate></item><item><title>Error Message Style Guides of Various Languages</title><link>https://www.pypy.org/posts/2021/12/error-message-style-guides.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;section id="error-message-style-guides-of-various-languages"&gt;
&lt;h2&gt;Error Message Style Guides of Various Languages&lt;/h2&gt;
&lt;p&gt;PyPy has been trying to produce good &lt;a class="reference external" href="https://www.pypy.org/posts/2018/04/improving-syntaxerror-in-pypy-5733639208090522433.html"&gt;SyntaxErrors&lt;/a&gt; and &lt;a class="reference external" href="https://twitter.com/cfbolz/status/783313503230844929/photo/1"&gt;other&lt;/a&gt; &lt;a class="reference external" href="https://twitter.com/pypyproject/status/999930324481081344"&gt;errors&lt;/a&gt; for
a long time. CPython has also made an enormous push to &lt;a class="reference external" href="https://docs.python.org/3/whatsnew/3.10.html#better-error-messages"&gt;improve its
SyntaxErrors in the last few releases&lt;/a&gt;. These improvements are great, but the process
feels somewhat arbitrary sometimes. To see what other languages are doing, I
&lt;a class="reference external" href="https://twitter.com/cfbolz/status/1466033151315173384"&gt;asked people on Twitter&lt;/a&gt; whether they know of error message style guides for
other programming languages.&lt;/p&gt;
&lt;p&gt;Wonderfully, people answered me with lots of helpful links (&lt;a class="reference internal" href="https://www.pypy.org/posts/2021/12/error-message-style-guides.html#full-list"&gt;full list&lt;/a&gt; at the
end of the post), thank you everybody! All those sources are very interesting
and contain many great points, I recommend reading them directly! In this
post, I'll try to summarize some common themes or topics that I thought were
particularly interesting.&lt;/p&gt;
&lt;section id="language-use"&gt;
&lt;h3&gt;Language Use&lt;/h3&gt;
&lt;p&gt;Almost all guides stress the need for plain and simple English, as well as
conciseness and clarity [Flix, Racket, Rust, Flow]. Flow suggests to put coding
effort into making the grammar correct, for example in the case of plurals or
to distinguish between "a" and "an".&lt;/p&gt;
&lt;p&gt;The suggested tone should be friendly and neutral, the messages should not
blame the Programmer [Flow]. Rust and Flix suggest to not use the term
'illegal' and use something like 'invalid' instead.&lt;/p&gt;
&lt;p&gt;Flow suggests to avoid "compiler speak". For example terms like 'token' and
'identifier' should be avoided and terms that are more familiar to programmers
be used (eg "name" is better). The Racket guide goes further and has a list of
allowed technical terms and some prohibited terms.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="structure"&gt;
&lt;h3&gt;Structure&lt;/h3&gt;
&lt;p&gt;Several guides (such as Flix and Flow) point out a 80/20 rule: 80% of the times an error message is
read, the developer knows that message well and knows exactly what to do. For
this use case it's important that the message is short. On the other hand, 20%
of the times this same message will have to be understood by a developer who
has never seen it before and is confused, and so the message needs to contain
enough information
to allow them to find out what is going on. So the error message needs to strike
a balance between brevity and clarity.&lt;/p&gt;
&lt;p&gt;The Racket guide proposes to use the following general structure for errors:
'State the constraint that was violated ("expected a"), followed by what was
found instead.'&lt;/p&gt;
&lt;p&gt;The Rust guides says to avoid "Did you mean?" and questions in general, and
wants the compiler to instead be explicit about why something was suggested. The
example the Rust guide gives is: 'Compare "did you mean: Foo" vs. "there is a
struct with a similar name: Foo".' Racket goes further and forbids
suggestions altogether because "Students will follow well‐meaning‐but‐wrong
advice uncritically, if only because they have no reason to doubt the
authoritative voice of the tool."&lt;/p&gt;
&lt;/section&gt;
&lt;section id="formatting-and-source-positions"&gt;
&lt;h3&gt;Formatting and Source Positions&lt;/h3&gt;
&lt;p&gt;The Rust guide suggests to put all identifiers into backticks (like in
Markdown), Flow formats the error messages using full Markdown.&lt;/p&gt;
&lt;p&gt;The Clang, Flow and Rust guides point out the importance of using precise
source code spans to point to errors, which is especially important if the
compiler information is used in the context of an IDE to show a red squiggly
underline or some other highlighting. The spans should be as small as possible to point out the source of
the error [Flow].&lt;/p&gt;
&lt;/section&gt;
&lt;section id="conclusion"&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I am quite impressed how advanced and well-thought out the approaches are. I wonder whether it would makes sense for
Python to adopt a (probably minimal, to get started) subset of these ideas as guidelines for its own errors.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="sources"&gt;
&lt;span id="full-list"&gt;&lt;/span&gt;&lt;h3&gt;Sources&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Rust: &lt;a class="reference external" href="https://rustc-dev-guide.rust-lang.org/diagnostics.html"&gt;https://rustc-dev-guide.rust-lang.org/diagnostics.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clang: &lt;a class="reference external" href="https://clang.llvm.org/diagnostics.html"&gt;https://clang.llvm.org/diagnostics.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flix: &lt;a class="reference external" href="https://flix.dev/principles/"&gt;https://flix.dev/principles/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Racket: &lt;a class="reference external" href="https://cs.brown.edu/~kfisler/Misc/error-msg-guidelines-racket-studlangs.pdf"&gt;https://cs.brown.edu/~kfisler/Misc/error-msg-guidelines-racket-studlangs.pdf&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More about the research that lead to the Racket guidelines (including the referenced papers): &lt;a class="reference external" href="https://twitter.com/ShriramKMurthi/status/1451688982761381892"&gt;https://twitter.com/ShriramKMurthi/status/1451688982761381892&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flow: &lt;a class="reference external" href="https://calebmer.com/2019/07/01/writing-good-compiler-error-messages.html"&gt;https://calebmer.com/2019/07/01/writing-good-compiler-error-messages.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Elm: &lt;a class="reference external" href="https://elm-lang.org/news/compiler-errors-for-humans"&gt;https://elm-lang.org/news/compiler-errors-for-humans&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Elm's error message catalog: &lt;a class="reference external" href="https://github.com/elm/error-message-catalog"&gt;https://github.com/elm/error-message-catalog&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reason: &lt;a class="reference external" href="https://reasonml.github.io/blog/2017/08/25/way-nicer-error-messages.html"&gt;https://reasonml.github.io/blog/2017/08/25/way-nicer-error-messages.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;</description><guid>https://www.pypy.org/posts/2021/12/error-message-style-guides.html</guid><pubDate>Sun, 05 Dec 2021 14:00:00 GMT</pubDate></item><item><title>Better JIT Support for Auto-Generated Python Code</title><link>https://www.pypy.org/posts/2021/09/jit-auto-generated-code.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;h2 id="performance-cliffs"&gt;Performance Cliffs&lt;/h2&gt;
&lt;p&gt;A common bad property of many different JIT compilers is that of a "performance
cliff": A seemingly reasonable code change, leading to massively reduced
performance due to hitting some weird property of the JIT compiler that's not
easy to understand for the programmer (e.g. here's a blog post about the fix of
a performance cliff when running &lt;a href="https://v8.dev/blog/react-cliff"&gt;React on
V8&lt;/a&gt;). Hitting a performance cliff as a
programmer can be intensely frustrating and turn people off from using PyPy
altogether. Recently we've been working on trying to remove some of PyPy's
performance cliffs, and this post describes one such effort.&lt;/p&gt;
&lt;p&gt;The problem showed up in an &lt;a href="https://foss.heptapod.net/pypy/pypy/-/issues/3402"&gt;issue&lt;/a&gt;
where somebody found the performance
of their website using &lt;a href="https://www.tornadoweb.org/en/stable/"&gt;Tornado&lt;/a&gt; a lot
worse than what various benchmarks suggested. It took some careful digging to
figure out what caused the problem: The slow performance was caused by the huge
functions that the Tornado templating engine creates. These functions lead the
JIT to behave in unproductive ways. In this blog post I'll describe why the
problem occurs and how we fixed it.&lt;/p&gt;
&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;p&gt;After quite a bit of debugging we narrowed down the problem to the following
reproducer: If you render a big HTML template
(&lt;a href="https://gist.github.com/cfbolz/4a346d104fee41affc860a7b928b7291#file-index-html"&gt;example&lt;/a&gt;)
using the Tornado templating engine, the template rendering is really not any
faster than CPython. A small template doesn't show this behavior, and other
parts of Tornado seem to perform well. So we looked into how the templating
engine works, and it turns out that the templates are compiled into Python
functions. This means that a big template can turn into a really enormous Python
function (&lt;a href="https://gist.github.com/cfbolz/4a346d104fee41affc860a7b928b7291#file-zz_autogenerated-py"&gt;Python version of the
example&lt;/a&gt;).
For some reason really enormous Python functions aren't handled particularly
well by the JIT, and in the next section I'll explain some the background that's
necessary to understand why this happens.&lt;/p&gt;
&lt;h2 id="trace-limits-and-inlining"&gt;Trace Limits and Inlining&lt;/h2&gt;
&lt;p&gt;To understand why the problem occurs, it's necessary to understand how PyPy's
trace limit and inlining works. The tracing JIT has a maximum trace length built
in, the reason for that is some limitation in the compact encoding of traces in
the JIT. Another reason is that we don't want to generate arbitrary large chunks
of machine code. Usually, when we hit the trace limit, it is due to &lt;em&gt;inlining&lt;/em&gt;.
While tracing, the JIT will inline many of the functions called from the
outermost one. This is usually good and improves performance greatly, however,
inlining can also lead to the trace being too long. If that happens, we
will mark a called function as uninlinable. The next time we trace the outer
function we won't inline it, leading to a shorter trace, which hopefully fits
the trace limit.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagram illustrating the interaction of the trace limit and inlining" src="https://www.pypy.org/images/2021-open-ended-traces-01-inlining.svg"&gt;&lt;/p&gt;
&lt;p&gt;In the diagram above we trace a function &lt;code&gt;f&lt;/code&gt;, which calls a function &lt;code&gt;g&lt;/code&gt;, which
is inlined into the trace. The trace ends up being too long, so the JIT
disables inlining of &lt;code&gt;g&lt;/code&gt;. The next time we try to trace &lt;code&gt;f&lt;/code&gt; the trace will
contain a &lt;em&gt;call&lt;/em&gt; to &lt;code&gt;g&lt;/code&gt; instead of inlining it. The trace ends up being not too
long, so we can turn it into machine code when tracing finishes.&lt;/p&gt;
&lt;p&gt;Now we know enough to understand what the problem with automatically generated
code is: sometimes, the outermost function itself
doesn't fit the trace limit, without any inlining going on at all. This is
usually not the case for normal, hand-written Python functions. However, it can
happen for automatically generated Python code, such as the code that the
Tornado templating engine produces.&lt;/p&gt;
&lt;p&gt;So, what happens when the JIT hits such a huge function? The function is traced
until the trace is too long. Then the trace limits stops further tracing. Since
nothing was inlined, we cannot make the trace shorter the next time by disabling
inlining. Therefore, this happens again and again, the next time we trace the
function we run into exactly the same problem. The net effect is that the
function is even slowed down: we spend time tracing it, then stop tracing and
throw the trace away. Therefore, that effort is never useful, so the resulting
execution can be slower than not using the JIT at all!&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;p&gt;To get out of the endless cycle of useless retracing we first had the idea of
simply disabling all code generation for such huge functions, that produce too long
traces even if there is no inlining at all. However, that lead to disappointing
performance in the example Tornado program, because important parts of the code
remain always interpreted.&lt;/p&gt;
&lt;p&gt;Instead, our solution is now as follows: After we have hit the trace limit and
no inlining has happened so far, we mark the outermost function as a source of huge
traces. The next time we trace such a function, we do so in a special mode. In
that mode, hitting the trace limit behaves differently: Instead of stopping the
tracer and throwing away the trace produced so far, we will use the unfinished
trace to produce machine code. This trace corresponds to the first part of the
function, but stops at a basically arbitrary point in the middle of the
function.&lt;/p&gt;
&lt;p&gt;The question is what should happen when execution
reaches the end of this unfinished trace. We want to be able to cover more of
the function with machine code and therefore need to extend the trace
from that point on. But we don't want to do that too
eagerly to prevent lots and lots of machine code being generated. To achieve
this behaviour we add a guard to the end of the unfinished trace, which will
always fail. This has the right behaviour: a failing guard will transfer control
to the interpreter, but if it fails often enough, we can patch it to jump to
more machine code, that starts from this position. In that way, we can slowly
explore the full gigantic function and add all those parts of the control flow
graph that are actually commonly executed at runtime.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagram showing what happens in the new jit when tracing a huge function" src="https://www.pypy.org/images/2021-open-ended-traces-02-no-inlining.svg"&gt;&lt;/p&gt;
&lt;p&gt;In the diagram we are trying to trace a huge function &lt;code&gt;f&lt;/code&gt;, which leads to
hitting the trace limit. However, nothing was inlined into the trace, so
disabling inlining won't ensure a successful trace attempt the next time.
Instead, we mark &lt;code&gt;f&lt;/code&gt; as "huge". This has the effect that when we trace it again
and are about to hit the trace limit, we end the trace at an arbitrary point by
inserting a guard that always fails.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagram showing what happens in the new jit when tracing a huge function until completion" src="https://www.pypy.org/images/2021-open-ended-traces-03-complete.svg"&gt;&lt;/p&gt;
&lt;p&gt;If this guard failure is executed often enough, we might patch the guard and
add a jump to a further part of the function &lt;code&gt;f&lt;/code&gt;. This can continue potentially
several times, until the trace really hits and end points (for example by
closing the loop and jumping back to trace 1, or by returning from &lt;code&gt;f&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="evaluation"&gt;Evaluation&lt;/h2&gt;
&lt;p&gt;Since this is a performance cliff that we didn't observe in any of our
&lt;a href="http://speed.pypy.org/"&gt;benchmarks&lt;/a&gt; ourselves, it's pointless to look at the
effect that this improvement has on existing benchmarks – there shouldn't and
indeed there isn't any.&lt;/p&gt;
&lt;p&gt;Instead, we are going to look at a micro-benchmark that came out of the
original bug report, one that simply renders a big artificial Tornado template
200 times. The code of the micro-benchmark can be found
&lt;a href="https://gist.github.com/cfbolz/4a346d104fee41affc860a7b928b7291"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All benchmarks were run 10 times in new processes. The means and standard
deviations of the benchmark runs are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Time taken (lower is better)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CPython 3.9.5&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14.19 ± 0.35s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPy3 without JIT&lt;/td&gt;
&lt;td style="text-align: right;"&gt;59.48 ± 5.41s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPy3 JIT old&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14.47 ± 0.35s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPy3 JIT new&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.89 ± 0.10s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;What we can see is that while the old JIT is very helpful for this
micro-benchmark, it only brings the performance up to CPython levels, not
providing any extra benefit. The new JIT gives an almost 3x speedup.&lt;/p&gt;
&lt;p&gt;Another interesting number we can look at is how often the JIT started a trace,
and for how many traces we produced actual machine code:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Traces Started&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Traces sent to backend&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Time spent in JIT&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PyPy3 JIT old&lt;/td&gt;
&lt;td style="text-align: right;"&gt;216&lt;/td&gt;
&lt;td style="text-align: right;"&gt;24&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.65s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPy3 JIT new&lt;/td&gt;
&lt;td style="text-align: right;"&gt;30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;25&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.06s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here we can clearly see the problem: The old JIT would try tracing the
auto-generated templating code again and again, but would never actually produce
any machine code, wasting lots of time in the process. The new JIT still traces a
few times uselessly, but then eventually converges and stops emitting machine
code for all the paths through the auto-generated Python code.&lt;/p&gt;
&lt;!--
1: /home/cfbolz/projects/small-commits-pypy/pypy/goal/pypy-c-38-jit-chunked-traces -jit off render.py
            Mean        Std.Dev.    Min         Median      Max
real        59.479      5.411       51.864      59.966      67.721      
user        59.395      5.383       51.821      59.859      67.585      
sys         0.058       0.034       0.020       0.056       0.108

1: pypy3 render.py
            Mean        Std.Dev.    Min         Median      Max
real        14.469      0.352       13.744      14.472      15.174      
user        14.399      0.359       13.671      14.402      15.126      
sys         0.050       0.034       0.024       0.042       0.148

Tracing:        216 0.653033
Backend:        24  0.003664
TOTAL:              14.854610
ops:                2217432
heapcached ops:     701575
recorded ops:       643513
  calls:            60038
guards:             330245
opt ops:            1876
opt guards:         465
opt guards shared:  237
forcings:           0
abort: trace too long:  191
abort: compiling:   0
abort: vable escape:    0
abort: bad loop:    0
abort: force quasi-immut:   1
nvirtuals:          391
nvholes:            122
nvreused:           141
vecopt tried:       0
vecopt success:     0
Total # of loops:   17
Total # of bridges: 8
Freed # of loops:   5
Freed # of bridges: 5


1: /home/cfbolz/projects/small-commits-pypy/pypy/goal/pypy-c-38-jit-chunked-traces render.py
            Mean        Std.Dev.    Min         Median      Max
real        4.892       0.098       4.718       4.882       5.118       
user        4.807       0.097       4.644       4.797       5.022       
sys         0.067       0.019       0.040       0.070       0.096


Tracing:        30  0.060128
Backend:        25  0.033536
TOTAL:              4.551791
ops:                124584
heapcached ops:     53962
recorded ops:       33486
  calls:            4389
guards:             14061
opt ops:            18922
opt guards:         4281
opt guards shared:  2248
forcings:           0
abort: trace too long:  4
abort: compiling:   0
abort: vable escape:    0
abort: bad loop:    0
abort: force quasi-immut:   1
abort: segmenting trace:    5
nvirtuals:          314
nvholes:            90
nvreused:           114
vecopt tried:       0
vecopt success:     0
Total # of loops:   14
Total # of bridges: 12
Freed # of loops:   0
Freed # of bridges: 0

--&gt;

&lt;h2 id="related-work"&gt;Related Work&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.timfelgentreff.de/"&gt;Tim Felgentreff&lt;/a&gt; pointed me to the fact that
Truffle also has a
&lt;a href="https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/nodes/BlockNode.html"&gt;mechanism&lt;/a&gt;
to slice huge methods into smaller compilation units (and I am sure other JITs
have such mechanisms as well).&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post we've described a performance cliff in PyPy's JIT, that of really
big auto-generated functions which hit the trace limit without inlining, that we
still want to generate machine code for. We achieve this by chunking up the
trace into several smaller traces, which we compile piece by piece. This is not
a super common thing to be happening – otherwise we would have run into and
fixed it earlier – but it's still good to have a fix now.&lt;/p&gt;
&lt;p&gt;The work
described in this post tiny bit experimental still, but we will release it as
part of the upcoming 3.8 beta release, to get some more experience with it.
Please grab a &lt;a href="https://mail.python.org/pipermail/pypy-dev/2021-September/016214.html"&gt;3.8 release
candidate&lt;/a&gt;,
try it out and let us know your observations, good and bad!&lt;/p&gt;</description><guid>https://www.pypy.org/posts/2021/09/jit-auto-generated-code.html</guid><pubDate>Fri, 17 Sep 2021 19:55:09 GMT</pubDate></item><item><title>Some Ways that PyPy uses Graphviz</title><link>https://www.pypy.org/posts/2021/04/ways-pypy-graphviz.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;section id="some-way-that-pypy-uses-graphviz"&gt;
&lt;h2&gt;Some way that PyPy uses Graphviz&lt;/h2&gt;
&lt;p&gt;Somebody wrote this super cool thread on Twitter about using &lt;a class="reference external" href="https://graphviz.org"&gt;Graphviz&lt;/a&gt; to make
software visualize its internal state:&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;🧵 Make yours and everybody else's lives slightly less terrible by having all your programs print out their internal stuff as pictures; ✨ a thread ✨ &lt;a href="https://t.co/NjQ42bXN2E"&gt;pic.twitter.com/NjQ42bXN2E&lt;/a&gt;&lt;/p&gt;— Kate (@thingskatedid) &lt;a href="https://twitter.com/thingskatedid/status/1386077306381242371?ref_src=twsrc%5Etfw"&gt;April 24, 2021&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;&lt;p&gt;PyPy is using this approach a lot too and I collected a few screenshots of that
technique &lt;a class="reference external" href="https://twitter.com/cfbolz/status/1386315196982079491"&gt;on Twitter&lt;/a&gt; and I thought it would make a nice blog post too!&lt;/p&gt;
&lt;p&gt;The most important view early in the project, and the way that our Graphviz
visualizations got started was that we implemented a way to look at the control
flow graphs of our RPython functions after type inference. They are in static
single information form (&lt;a class="reference external" href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.1.9976"&gt;SSI&lt;/a&gt;), a variant of &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Static_single_assignment_form"&gt;SSA&lt;/a&gt; form. Hovering over the
variables shows the inferred types in the footer:&lt;/p&gt;
&lt;img alt="/images/2021-graphviz-02-cfg-types.png" src="https://www.pypy.org/images/2021-graphviz-02-cfg-types.png"&gt;
&lt;p&gt;There's another view that shows the inferred call graph of the program:&lt;/p&gt;
&lt;img alt="/images/2021-graphviz-05-call-graph.png" src="https://www.pypy.org/images/2021-graphviz-05-call-graph.png"&gt;
&lt;p&gt;A related viewer shows the inferred class hierarchy (in this case the exception
hierarchy) and you can focus on a single class, which will show you its base
classes and all the methods and instance attributes that were found:&lt;/p&gt;
&lt;img alt="/images/2021-graphviz-03-classhier.png" src="https://www.pypy.org/images/2021-graphviz-03-classhier.png"&gt;
&lt;img alt="/images/2021-graphviz-04-classhier-detailed.png" src="https://www.pypy.org/images/2021-graphviz-04-classhier-detailed.png"&gt;
&lt;p&gt;We also have a view to show us the traces that are produced by the tracing JIT
tests. this viewer doesn't really scale to the big traces that the full Python
interpreter produces, but it's really useful during testing:&lt;/p&gt;
&lt;img alt="/images/2021-graphviz-06-trace.png" src="https://www.pypy.org/images/2021-graphviz-06-trace.png"&gt;
&lt;p&gt;Then there are more traditional tree views, eg here is a parse tree for a small
piece of Python source code:&lt;/p&gt;
&lt;img alt="/images/2021-graphviz-07-parse-tree.png" src="https://www.pypy.org/images/2021-graphviz-07-parse-tree.png"&gt;
&lt;p&gt;Parsing-related we have visualized the &lt;a class="reference external" href="https://www.pypy.org/posts/2008/01/visualizing-python-tokenizer-5020282079473796926.html"&gt;DFAs of the parser&lt;/a&gt; in the past,
though the code is unfortunately lost.&lt;/p&gt;
&lt;p&gt;All these visualizations are made by walking the relevant data structures and
producing a Graphviz input file using a bit of string manipulation, which is
quite easy to do. Knowing a bit of Graphviz is a really useful skill, it's
super easy to make throwaway visualizations.&lt;/p&gt;
&lt;p&gt;For example here is a one-off thing I did when debugging our &lt;a class="reference external" href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html"&gt;JSON parser&lt;/a&gt; to
show the properties of the objects used in a huge example json file:&lt;/p&gt;
&lt;img alt="/images/2021-graphviz-08-json-parser.png" src="https://www.pypy.org/images/2021-graphviz-08-json-parser.png"&gt;
&lt;p&gt;On top of graphviz, we have a custom tool called the &lt;a class="reference external" href="https://foss.heptapod.net/pypy/pypy/-/tree/branch/default/dotviewer"&gt;dotviewer&lt;/a&gt;, which is
written in Python and uses &lt;a class="reference external" href="https://pygame.org"&gt;Pygame&lt;/a&gt; to give you a zoomable, pannable, searchable
way to look at huge Graphviz graphs. All the images in this post are
screenshots of that tool. In its simplest form it takes any .dot files as
input.&lt;/p&gt;
&lt;p&gt;Here's a small video dotviewer, moving around and searching in the json graph.
By writing a bit of extra Python code the dotviewer can also be extended to add
hyperlinks in the graphs to navigate to different views (for example, we did
that for the callgraphs above).&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/SsTmJ5_Yzh8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;&lt;p&gt;All in all this is a really powerful approach to understand the behaviour of
some of code, or when debugging complicated problems and we have gotten a
huge amount of mileage out of this over the years. It can be seen as an instance
of &lt;a class="reference external" href="https://moldabledevelopment.com/"&gt;moldable development&lt;/a&gt; ("a way of programming through which you construct
custom tools for each problem"). And it's really easy to get into! The Graphviz
language is quite a simple text-based language that can be applied to a huge
amount of different visualization situations.&lt;/p&gt;
&lt;/section&gt;</description><guid>https://www.pypy.org/posts/2021/04/ways-pypy-graphviz.html</guid><pubDate>Mon, 26 Apr 2021 16:00:00 GMT</pubDate></item><item><title>PyPy's new JSON parser</title><link>https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;h2&gt;
Introduction&lt;/h2&gt;
In the last year or two I have worked on and off on making PyPy's
&lt;a class="reference external" href="https://www.json.org/"&gt;JSON&lt;/a&gt; faster, particularly when parsing large
JSON files. In this post I am going to document those techniques and
measure their performance impact. Note that I am quite a lot more
constrained in what optimizations I can apply here, compared to some of
the much more advanced approaches like
&lt;a class="reference external" href="https://www.microsoft.com/en-us/research/publication/mison-fast-json-parser-data-analytics/"&gt;Mison&lt;/a&gt;,
&lt;a class="reference external" href="https://dawn.cs.stanford.edu/2018/08/07/sparser/"&gt;Sparser&lt;/a&gt; or
&lt;a class="reference external" href="https://arxiv.org/abs/1902.08318"&gt;SimdJSON&lt;/a&gt; because I don't want to
change the &lt;tt class="docutils literal"&gt;json.loads&lt;/tt&gt; API that Python programs expect, and because I
don't want to only support CPUs with wide SIMD extensions. With a more
expressive API, more optimizations would be possible.&lt;br&gt;
There are a number of problems of working with huge JSON files:
deserialization takes a long time on the one hand, and the resulting
data structures often take a lot of memory (usually they can be many
times bigger than the size of the file they originated from). Of course
these problems are related, because allocating and initializing a big
data structure takes longer than a smaller data structure. Therefore I
always tried to attack both of these problems at the same time.&lt;br&gt;
One common theme of the techniques I am describing is that of optimizing
the parser for how JSON files are typically used, not how they could
theoretically be used. This is a similar approach to the way dynamic
languages are optimized more generally: most JITs will optimize for
typical patterns of usage, at the cost of less common usage patterns,
which might even become slower as a result of the optimizations.&lt;br&gt;
&lt;h2&gt;
Maps&lt;/h2&gt;
The first technique I investigated is to use maps in the JSON parser.
Maps, also called hidden classes or shapes, are a fairly common way to
(generally, not just in the context of JSON parsing) &lt;a class="reference external" href="https://www.pypy.org/posts/2010/11/efficiently-implementing-python-objects-3838329944323946932.html"&gt;optimize instances
of
classes&lt;/a&gt;
in dynamic language VMs. Maps exploit the fact that while it is in
theory possible to add arbitrary fields to an instance, in practice most
instances of a class are going to have the same set of fields (or one of
a small number of different sets). Since JSON dictionaries or objects
often come from serialized instances of some kind, this property often
holds in JSON files as well: dictionaries often have the same fields in
the same order, within a JSON file.&lt;br&gt;
This property can be exploited in two ways: on the one hand, it can be
used to again store the deserialized dictionaries in a more memory
efficient way by not using a hashmap in most cases, but instead
splitting the dictionary into a shared description of the set of keys
(the map) and an array of storage with the values. This makes the
deserialized dictionaries smaller if the same set of keys is repeated a
lot. This is completely transparent to the Python programmer, the
dictionary will look completely normal to the Python program but its
internal representation is different.&lt;br&gt;
One downside of using maps is that sometimes files will contain many
dictionaries that have unique key sets. Since maps themselves are quite
large data structures and since dictionaries that use maps contain an
extra level of indirection we want to fall back to using normal hashmaps
to represent the dictionaries where that is the case. To prevent this we
perform some statistics at runtime, how often every map (i.e. set of
keys) is used in the file. For uncommonly used maps, the map is
discarded and the dictionaries that used the map converted into using a
regular hashmap.&lt;br&gt;
&lt;h3&gt;
Using Maps to Speed up Parsing&lt;/h3&gt;
Another benefit of using maps to store deserialized dictionaries is that
we can use them to speed up the parsing process itself. To see how this
works, we need to understand maps a bit better. All the maps produced as
a side-effect of parsing JSON form a tree. The tree root is a map that
describes the object without any attributes. From every tree node we
have a number of edges going to other nodes, each edge for a specific
new attribute added:&lt;br&gt;

&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="423pt" height="503pt" viewbox="0 0 623 503" version="1.1"&gt;
&lt;defs&gt;
&lt;g&gt;
&lt;symbol overflow="visible" id="glyph0-0"&gt;
&lt;path style="stroke:none;" d="M 0.640625 2.265625 L 0.640625 -9.015625 L 7.03125 -9.015625 L 7.03125 2.265625 Z M 1.359375 1.546875 L 6.328125 1.546875 L 6.328125 -8.296875 L 1.359375 -8.296875 Z M 1.359375 1.546875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-1"&gt;
&lt;path style="stroke:none;" d="M 7.1875 -3.78125 L 7.1875 -3.21875 L 1.90625 -3.21875 C 1.957031 -2.425781 2.195312 -1.820312 2.625 -1.40625 C 3.050781 -1 3.644531 -0.796875 4.40625 -0.796875 C 4.84375 -0.796875 5.269531 -0.847656 5.6875 -0.953125 C 6.101562 -1.066406 6.515625 -1.226562 6.921875 -1.4375 L 6.921875 -0.359375 C 6.515625 -0.179688 6.09375 -0.046875 5.65625 0.046875 C 5.21875 0.140625 4.78125 0.1875 4.34375 0.1875 C 3.21875 0.1875 2.328125 -0.132812 1.671875 -0.78125 C 1.023438 -1.4375 0.703125 -2.320312 0.703125 -3.4375 C 0.703125 -4.582031 1.007812 -5.488281 1.625 -6.15625 C 2.25 -6.832031 3.085938 -7.171875 4.140625 -7.171875 C 5.078125 -7.171875 5.816406 -6.863281 6.359375 -6.25 C 6.910156 -5.644531 7.1875 -4.820312 7.1875 -3.78125 Z M 6.046875 -4.125 C 6.035156 -4.75 5.859375 -5.25 5.515625 -5.625 C 5.171875 -6 4.71875 -6.1875 4.15625 -6.1875 C 3.507812 -6.1875 2.992188 -6.003906 2.609375 -5.640625 C 2.222656 -5.285156 2 -4.78125 1.9375 -4.125 Z M 6.046875 -4.125 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-2"&gt;
&lt;path style="stroke:none;" d="M 6.65625 -5.65625 C 6.9375 -6.164062 7.273438 -6.546875 7.671875 -6.796875 C 8.078125 -7.046875 8.550781 -7.171875 9.09375 -7.171875 C 9.820312 -7.171875 10.382812 -6.914062 10.78125 -6.40625 C 11.175781 -5.894531 11.375 -5.164062 11.375 -4.21875 L 11.375 0 L 10.21875 0 L 10.21875 -4.1875 C 10.21875 -4.851562 10.097656 -5.347656 9.859375 -5.671875 C 9.628906 -6.003906 9.269531 -6.171875 8.78125 -6.171875 C 8.1875 -6.171875 7.710938 -5.972656 7.359375 -5.578125 C 7.015625 -5.179688 6.84375 -4.640625 6.84375 -3.953125 L 6.84375 0 L 5.6875 0 L 5.6875 -4.1875 C 5.6875 -4.863281 5.566406 -5.363281 5.328125 -5.6875 C 5.097656 -6.007812 4.734375 -6.171875 4.234375 -6.171875 C 3.648438 -6.171875 3.179688 -5.96875 2.828125 -5.5625 C 2.484375 -5.164062 2.3125 -4.628906 2.3125 -3.953125 L 2.3125 0 L 1.15625 0 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.90625 C 2.582031 -6.332031 2.898438 -6.648438 3.265625 -6.859375 C 3.628906 -7.066406 4.0625 -7.171875 4.5625 -7.171875 C 5.070312 -7.171875 5.503906 -7.039062 5.859375 -6.78125 C 6.222656 -6.519531 6.488281 -6.144531 6.65625 -5.65625 Z M 6.65625 -5.65625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-3"&gt;
&lt;path style="stroke:none;" d="M 2.3125 -1.046875 L 2.3125 2.65625 L 1.15625 2.65625 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.9375 C 2.5625 -6.351562 2.867188 -6.660156 3.234375 -6.859375 C 3.597656 -7.066406 4.039062 -7.171875 4.5625 -7.171875 C 5.40625 -7.171875 6.09375 -6.832031 6.625 -6.15625 C 7.15625 -5.476562 7.421875 -4.59375 7.421875 -3.5 C 7.421875 -2.394531 7.15625 -1.503906 6.625 -0.828125 C 6.09375 -0.148438 5.40625 0.1875 4.5625 0.1875 C 4.039062 0.1875 3.597656 0.0859375 3.234375 -0.109375 C 2.867188 -0.316406 2.5625 -0.628906 2.3125 -1.046875 Z M 6.234375 -3.5 C 6.234375 -4.34375 6.054688 -5.003906 5.703125 -5.484375 C 5.359375 -5.960938 4.882812 -6.203125 4.28125 -6.203125 C 3.664062 -6.203125 3.179688 -5.960938 2.828125 -5.484375 C 2.484375 -5.003906 2.3125 -4.34375 2.3125 -3.5 C 2.3125 -2.644531 2.484375 -1.976562 2.828125 -1.5 C 3.179688 -1.019531 3.664062 -0.78125 4.28125 -0.78125 C 4.882812 -0.78125 5.359375 -1.019531 5.703125 -1.5 C 6.054688 -1.976562 6.234375 -2.644531 6.234375 -3.5 Z M 6.234375 -3.5 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-4"&gt;
&lt;path style="stroke:none;" d="M 2.34375 -8.984375 L 2.34375 -7 L 4.71875 -7 L 4.71875 -6.109375 L 2.34375 -6.109375 L 2.34375 -2.3125 C 2.34375 -1.738281 2.421875 -1.367188 2.578125 -1.203125 C 2.734375 -1.046875 3.050781 -0.96875 3.53125 -0.96875 L 4.71875 -0.96875 L 4.71875 0 L 3.53125 0 C 2.644531 0 2.03125 -0.164062 1.6875 -0.5 C 1.351562 -0.832031 1.1875 -1.4375 1.1875 -2.3125 L 1.1875 -6.109375 L 0.34375 -6.109375 L 0.34375 -7 L 1.1875 -7 L 1.1875 -8.984375 Z M 2.34375 -8.984375 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-5"&gt;
&lt;path style="stroke:none;" d="M 4.125 0.65625 C 3.789062 1.488281 3.46875 2.03125 3.15625 2.28125 C 2.851562 2.53125 2.445312 2.65625 1.9375 2.65625 L 1.015625 2.65625 L 1.015625 1.703125 L 1.6875 1.703125 C 2 1.703125 2.242188 1.625 2.421875 1.46875 C 2.597656 1.320312 2.789062 0.96875 3 0.40625 L 3.21875 -0.109375 L 0.375 -7 L 1.59375 -7 L 3.78125 -1.53125 L 5.96875 -7 L 7.1875 -7 Z M 4.125 0.65625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-6"&gt;
&lt;path style="stroke:none;" d="M 4.390625 -3.515625 C 3.460938 -3.515625 2.816406 -3.40625 2.453125 -3.1875 C 2.097656 -2.976562 1.921875 -2.617188 1.921875 -2.109375 C 1.921875 -1.703125 2.050781 -1.378906 2.3125 -1.140625 C 2.582031 -0.898438 2.953125 -0.78125 3.421875 -0.78125 C 4.054688 -0.78125 4.566406 -1.003906 4.953125 -1.453125 C 5.335938 -1.910156 5.53125 -2.515625 5.53125 -3.265625 L 5.53125 -3.515625 Z M 6.671875 -4 L 6.671875 0 L 5.53125 0 L 5.53125 -1.0625 C 5.269531 -0.632812 4.941406 -0.316406 4.546875 -0.109375 C 4.160156 0.0859375 3.679688 0.1875 3.109375 0.1875 C 2.390625 0.1875 1.816406 -0.015625 1.390625 -0.421875 C 0.972656 -0.828125 0.765625 -1.363281 0.765625 -2.03125 C 0.765625 -2.820312 1.023438 -3.414062 1.546875 -3.8125 C 2.078125 -4.21875 2.867188 -4.421875 3.921875 -4.421875 L 5.53125 -4.421875 L 5.53125 -4.53125 C 5.53125 -5.0625 5.351562 -5.46875 5 -5.75 C 4.65625 -6.039062 4.171875 -6.1875 3.546875 -6.1875 C 3.140625 -6.1875 2.75 -6.140625 2.375 -6.046875 C 2 -5.953125 1.632812 -5.8125 1.28125 -5.625 L 1.28125 -6.671875 C 1.695312 -6.835938 2.101562 -6.960938 2.5 -7.046875 C 2.894531 -7.128906 3.28125 -7.171875 3.65625 -7.171875 C 4.675781 -7.171875 5.429688 -6.90625 5.921875 -6.375 C 6.421875 -5.851562 6.671875 -5.0625 6.671875 -4 Z M 6.671875 -4 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-7"&gt;
&lt;path style="stroke:none;" d="M 5.8125 -5.9375 L 5.8125 -9.71875 L 6.953125 -9.71875 L 6.953125 0 L 5.8125 0 L 5.8125 -1.046875 C 5.570312 -0.628906 5.265625 -0.316406 4.890625 -0.109375 C 4.523438 0.0859375 4.082031 0.1875 3.5625 0.1875 C 2.71875 0.1875 2.03125 -0.148438 1.5 -0.828125 C 0.96875 -1.503906 0.703125 -2.394531 0.703125 -3.5 C 0.703125 -4.59375 0.96875 -5.476562 1.5 -6.15625 C 2.03125 -6.832031 2.71875 -7.171875 3.5625 -7.171875 C 4.082031 -7.171875 4.523438 -7.066406 4.890625 -6.859375 C 5.265625 -6.660156 5.570312 -6.351562 5.8125 -5.9375 Z M 1.890625 -3.5 C 1.890625 -2.644531 2.0625 -1.976562 2.40625 -1.5 C 2.757812 -1.019531 3.238281 -0.78125 3.84375 -0.78125 C 4.457031 -0.78125 4.9375 -1.019531 5.28125 -1.5 C 5.632812 -1.976562 5.8125 -2.644531 5.8125 -3.5 C 5.8125 -4.34375 5.632812 -5.003906 5.28125 -5.484375 C 4.9375 -5.960938 4.457031 -6.203125 3.84375 -6.203125 C 3.238281 -6.203125 2.757812 -5.960938 2.40625 -5.484375 C 2.0625 -5.003906 1.890625 -4.34375 1.890625 -3.5 Z M 1.890625 -3.5 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-8"&gt;
&lt;path style="stroke:none;" d=""&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-9"&gt;
&lt;path style="stroke:none;" d="M 1.5 -1.59375 L 2.8125 -1.59375 L 2.8125 -0.515625 L 1.796875 1.484375 L 0.984375 1.484375 L 1.5 -0.515625 Z M 1.5 -1.59375 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-10"&gt;
&lt;path style="stroke:none;" d="M 6.234375 -3.5 C 6.234375 -4.34375 6.054688 -5.003906 5.703125 -5.484375 C 5.359375 -5.960938 4.882812 -6.203125 4.28125 -6.203125 C 3.664062 -6.203125 3.179688 -5.960938 2.828125 -5.484375 C 2.484375 -5.003906 2.3125 -4.34375 2.3125 -3.5 C 2.3125 -2.644531 2.484375 -1.976562 2.828125 -1.5 C 3.179688 -1.019531 3.664062 -0.78125 4.28125 -0.78125 C 4.882812 -0.78125 5.359375 -1.019531 5.703125 -1.5 C 6.054688 -1.976562 6.234375 -2.644531 6.234375 -3.5 Z M 2.3125 -5.9375 C 2.5625 -6.351562 2.867188 -6.660156 3.234375 -6.859375 C 3.597656 -7.066406 4.039062 -7.171875 4.5625 -7.171875 C 5.40625 -7.171875 6.09375 -6.832031 6.625 -6.15625 C 7.15625 -5.476562 7.421875 -4.59375 7.421875 -3.5 C 7.421875 -2.394531 7.15625 -1.503906 6.625 -0.828125 C 6.09375 -0.148438 5.40625 0.1875 4.5625 0.1875 C 4.039062 0.1875 3.597656 0.0859375 3.234375 -0.109375 C 2.867188 -0.316406 2.5625 -0.628906 2.3125 -1.046875 L 2.3125 0 L 1.15625 0 L 1.15625 -9.71875 L 2.3125 -9.71875 Z M 2.3125 -5.9375 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-11"&gt;
&lt;path style="stroke:none;" d="M 6.25 -6.734375 L 6.25 -5.65625 C 5.914062 -5.832031 5.585938 -5.960938 5.265625 -6.046875 C 4.941406 -6.140625 4.613281 -6.1875 4.28125 -6.1875 C 3.53125 -6.1875 2.945312 -5.953125 2.53125 -5.484375 C 2.125 -5.015625 1.921875 -4.351562 1.921875 -3.5 C 1.921875 -2.644531 2.125 -1.976562 2.53125 -1.5 C 2.945312 -1.03125 3.53125 -0.796875 4.28125 -0.796875 C 4.613281 -0.796875 4.941406 -0.835938 5.265625 -0.921875 C 5.585938 -1.015625 5.914062 -1.148438 6.25 -1.328125 L 6.25 -0.265625 C 5.925781 -0.117188 5.59375 -0.0078125 5.25 0.0625 C 4.90625 0.144531 4.539062 0.1875 4.15625 0.1875 C 3.09375 0.1875 2.25 -0.144531 1.625 -0.8125 C 1.007812 -1.476562 0.703125 -2.375 0.703125 -3.5 C 0.703125 -4.632812 1.015625 -5.53125 1.640625 -6.1875 C 2.273438 -6.84375 3.132812 -7.171875 4.21875 -7.171875 C 4.570312 -7.171875 4.914062 -7.132812 5.25 -7.0625 C 5.59375 -6.988281 5.925781 -6.878906 6.25 -6.734375 Z M 6.25 -6.734375 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-12"&gt;
&lt;path style="stroke:none;" d="M 4.75 -9.71875 L 4.75 -8.765625 L 3.65625 -8.765625 C 3.238281 -8.765625 2.945312 -8.679688 2.78125 -8.515625 C 2.625 -8.347656 2.546875 -8.046875 2.546875 -7.609375 L 2.546875 -7 L 4.4375 -7 L 4.4375 -6.109375 L 2.546875 -6.109375 L 2.546875 0 L 1.390625 0 L 1.390625 -6.109375 L 0.296875 -6.109375 L 0.296875 -7 L 1.390625 -7 L 1.390625 -7.484375 C 1.390625 -8.265625 1.570312 -8.832031 1.9375 -9.1875 C 2.300781 -9.539062 2.875 -9.71875 3.65625 -9.71875 Z M 4.75 -9.71875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-13"&gt;
&lt;path style="stroke:none;" d="M 7.015625 -7 L 4.5 -3.59375 L 7.15625 0 L 5.796875 0 L 3.765625 -2.75 L 1.71875 0 L 0.375 0 L 3.09375 -3.65625 L 0.59375 -7 L 1.953125 -7 L 3.8125 -4.5 L 5.671875 -7 Z M 7.015625 -7 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-14"&gt;
&lt;path style="stroke:none;" d="M 3.921875 -6.1875 C 3.304688 -6.1875 2.816406 -5.945312 2.453125 -5.46875 C 2.097656 -4.988281 1.921875 -4.332031 1.921875 -3.5 C 1.921875 -2.65625 2.097656 -1.992188 2.453125 -1.515625 C 2.804688 -1.035156 3.296875 -0.796875 3.921875 -0.796875 C 4.535156 -0.796875 5.019531 -1.035156 5.375 -1.515625 C 5.726562 -2.003906 5.90625 -2.664062 5.90625 -3.5 C 5.90625 -4.320312 5.726562 -4.972656 5.375 -5.453125 C 5.019531 -5.941406 4.535156 -6.1875 3.921875 -6.1875 Z M 3.921875 -7.171875 C 4.921875 -7.171875 5.703125 -6.84375 6.265625 -6.1875 C 6.835938 -5.539062 7.125 -4.644531 7.125 -3.5 C 7.125 -2.351562 6.835938 -1.453125 6.265625 -0.796875 C 5.703125 -0.140625 4.921875 0.1875 3.921875 0.1875 C 2.910156 0.1875 2.117188 -0.140625 1.546875 -0.796875 C 0.984375 -1.453125 0.703125 -2.351562 0.703125 -3.5 C 0.703125 -4.644531 0.984375 -5.539062 1.546875 -6.1875 C 2.117188 -6.84375 2.910156 -7.171875 3.921875 -7.171875 Z M 3.921875 -7.171875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-15"&gt;
&lt;path style="stroke:none;" d="M 7.015625 -4.21875 L 7.015625 0 L 5.875 0 L 5.875 -4.1875 C 5.875 -4.851562 5.742188 -5.347656 5.484375 -5.671875 C 5.222656 -6.003906 4.835938 -6.171875 4.328125 -6.171875 C 3.703125 -6.171875 3.207031 -5.972656 2.84375 -5.578125 C 2.488281 -5.179688 2.3125 -4.640625 2.3125 -3.953125 L 2.3125 0 L 1.15625 0 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.90625 C 2.59375 -6.332031 2.914062 -6.648438 3.28125 -6.859375 C 3.65625 -7.066406 4.085938 -7.171875 4.578125 -7.171875 C 5.378906 -7.171875 5.984375 -6.921875 6.390625 -6.421875 C 6.804688 -5.921875 7.015625 -5.1875 7.015625 -4.21875 Z M 7.015625 -4.21875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-16"&gt;
&lt;path style="stroke:none;" d="M 5.265625 -5.921875 C 5.128906 -5.992188 4.984375 -6.046875 4.828125 -6.078125 C 4.679688 -6.117188 4.519531 -6.140625 4.34375 -6.140625 C 3.6875 -6.140625 3.179688 -5.925781 2.828125 -5.5 C 2.484375 -5.082031 2.3125 -4.476562 2.3125 -3.6875 L 2.3125 0 L 1.15625 0 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.90625 C 2.5625 -6.332031 2.878906 -6.648438 3.265625 -6.859375 C 3.648438 -7.066406 4.117188 -7.171875 4.671875 -7.171875 C 4.753906 -7.171875 4.84375 -7.164062 4.9375 -7.15625 C 5.03125 -7.144531 5.132812 -7.128906 5.25 -7.109375 Z M 5.265625 -5.921875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-17"&gt;
&lt;path style="stroke:none;" d="M 5.671875 -6.796875 L 5.671875 -5.703125 C 5.347656 -5.867188 5.007812 -5.992188 4.65625 -6.078125 C 4.300781 -6.160156 3.9375 -6.203125 3.5625 -6.203125 C 3 -6.203125 2.570312 -6.113281 2.28125 -5.9375 C 2 -5.769531 1.859375 -5.507812 1.859375 -5.15625 C 1.859375 -4.882812 1.957031 -4.671875 2.15625 -4.515625 C 2.363281 -4.367188 2.773438 -4.226562 3.390625 -4.09375 L 3.78125 -4 C 4.601562 -3.832031 5.1875 -3.585938 5.53125 -3.265625 C 5.875 -2.941406 6.046875 -2.5 6.046875 -1.9375 C 6.046875 -1.28125 5.785156 -0.757812 5.265625 -0.375 C 4.753906 0 4.050781 0.1875 3.15625 0.1875 C 2.78125 0.1875 2.390625 0.148438 1.984375 0.078125 C 1.578125 0.00390625 1.144531 -0.101562 0.6875 -0.25 L 0.6875 -1.4375 C 1.113281 -1.21875 1.53125 -1.050781 1.9375 -0.9375 C 2.351562 -0.832031 2.765625 -0.78125 3.171875 -0.78125 C 3.710938 -0.78125 4.128906 -0.875 4.421875 -1.0625 C 4.710938 -1.25 4.859375 -1.507812 4.859375 -1.84375 C 4.859375 -2.15625 4.753906 -2.394531 4.546875 -2.5625 C 4.335938 -2.726562 3.875 -2.890625 3.15625 -3.046875 L 2.765625 -3.140625 C 2.046875 -3.285156 1.53125 -3.515625 1.21875 -3.828125 C 0.90625 -4.140625 0.75 -4.566406 0.75 -5.109375 C 0.75 -5.765625 0.976562 -6.269531 1.4375 -6.625 C 1.90625 -6.988281 2.570312 -7.171875 3.4375 -7.171875 C 3.851562 -7.171875 4.25 -7.140625 4.625 -7.078125 C 5 -7.015625 5.347656 -6.921875 5.671875 -6.796875 Z M 5.671875 -6.796875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-18"&gt;
&lt;path style="stroke:none;" d="M 1.203125 -7 L 2.359375 -7 L 2.359375 0 L 1.203125 0 Z M 1.203125 -9.71875 L 2.359375 -9.71875 L 2.359375 -8.265625 L 1.203125 -8.265625 Z M 1.203125 -9.71875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph0-19"&gt;
&lt;path style="stroke:none;" d="M 1.203125 -9.71875 L 2.359375 -9.71875 L 2.359375 0 L 1.203125 0 Z M 1.203125 -9.71875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-0"&gt;
&lt;path style="stroke:none;" d="M 1.078125 3.84375 L 1.078125 -15.359375 L 11.96875 -15.359375 L 11.96875 3.84375 Z M 2.3125 2.640625 L 10.765625 2.640625 L 10.765625 -14.140625 L 2.3125 -14.140625 Z M 2.3125 2.640625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-1"&gt;
&lt;path style="stroke:none;" d="M 2.140625 -15.875 L 12.171875 -15.875 L 12.171875 -14.078125 L 4.28125 -14.078125 L 4.28125 -9.375 L 11.84375 -9.375 L 11.84375 -7.5625 L 4.28125 -7.5625 L 4.28125 -1.8125 L 12.375 -1.8125 L 12.375 0 L 2.140625 0 Z M 2.140625 -15.875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-2"&gt;
&lt;path style="stroke:none;" d="M 11.953125 -11.90625 L 7.640625 -6.109375 L 12.171875 0 L 9.875 0 L 6.40625 -4.671875 L 2.9375 0 L 0.625 0 L 5.25 -6.234375 L 1.015625 -11.90625 L 3.328125 -11.90625 L 6.484375 -7.671875 L 9.640625 -11.90625 Z M 11.953125 -11.90625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-3"&gt;
&lt;path style="stroke:none;" d="M 7.46875 -5.984375 C 5.882812 -5.984375 4.785156 -5.800781 4.171875 -5.4375 C 3.566406 -5.082031 3.265625 -4.46875 3.265625 -3.59375 C 3.265625 -2.894531 3.492188 -2.34375 3.953125 -1.9375 C 4.410156 -1.53125 5.03125 -1.328125 5.8125 -1.328125 C 6.894531 -1.328125 7.765625 -1.710938 8.421875 -2.484375 C 9.078125 -3.253906 9.40625 -4.273438 9.40625 -5.546875 L 9.40625 -5.984375 Z M 11.375 -6.796875 L 11.375 0 L 9.40625 0 L 9.40625 -1.8125 C 8.96875 -1.082031 8.414062 -0.546875 7.75 -0.203125 C 7.082031 0.140625 6.265625 0.3125 5.296875 0.3125 C 4.078125 0.3125 3.109375 -0.03125 2.390625 -0.71875 C 1.671875 -1.40625 1.3125 -2.320312 1.3125 -3.46875 C 1.3125 -4.8125 1.757812 -5.820312 2.65625 -6.5 C 3.550781 -7.175781 4.890625 -7.515625 6.671875 -7.515625 L 9.40625 -7.515625 L 9.40625 -7.703125 C 9.40625 -8.609375 9.109375 -9.304688 8.515625 -9.796875 C 7.929688 -10.296875 7.101562 -10.546875 6.03125 -10.546875 C 5.351562 -10.546875 4.691406 -10.460938 4.046875 -10.296875 C 3.398438 -10.128906 2.78125 -9.882812 2.1875 -9.5625 L 2.1875 -11.375 C 2.894531 -11.644531 3.585938 -11.847656 4.265625 -11.984375 C 4.941406 -12.128906 5.597656 -12.203125 6.234375 -12.203125 C 7.953125 -12.203125 9.238281 -11.753906 10.09375 -10.859375 C 10.945312 -9.960938 11.375 -8.609375 11.375 -6.796875 Z M 11.375 -6.796875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-4"&gt;
&lt;path style="stroke:none;" d="M 11.328125 -9.625 C 11.816406 -10.5 12.398438 -11.144531 13.078125 -11.5625 C 13.765625 -11.988281 14.566406 -12.203125 15.484375 -12.203125 C 16.722656 -12.203125 17.675781 -11.765625 18.34375 -10.890625 C 19.019531 -10.023438 19.359375 -8.789062 19.359375 -7.1875 L 19.359375 0 L 17.40625 0 L 17.40625 -7.125 C 17.40625 -8.269531 17.203125 -9.117188 16.796875 -9.671875 C 16.390625 -10.222656 15.769531 -10.5 14.9375 -10.5 C 13.925781 -10.5 13.125 -10.160156 12.53125 -9.484375 C 11.945312 -8.804688 11.65625 -7.890625 11.65625 -6.734375 L 11.65625 0 L 9.6875 0 L 9.6875 -7.125 C 9.6875 -8.269531 9.484375 -9.117188 9.078125 -9.671875 C 8.671875 -10.222656 8.046875 -10.5 7.203125 -10.5 C 6.210938 -10.5 5.421875 -10.160156 4.828125 -9.484375 C 4.242188 -8.804688 3.953125 -7.890625 3.953125 -6.734375 L 3.953125 0 L 1.984375 0 L 1.984375 -11.90625 L 3.953125 -11.90625 L 3.953125 -10.0625 C 4.390625 -10.789062 4.921875 -11.328125 5.546875 -11.671875 C 6.171875 -12.023438 6.914062 -12.203125 7.78125 -12.203125 C 8.644531 -12.203125 9.378906 -11.976562 9.984375 -11.53125 C 10.585938 -11.09375 11.035156 -10.457031 11.328125 -9.625 Z M 11.328125 -9.625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-5"&gt;
&lt;path style="stroke:none;" d="M 3.953125 -1.78125 L 3.953125 4.53125 L 1.984375 4.53125 L 1.984375 -11.90625 L 3.953125 -11.90625 L 3.953125 -10.109375 C 4.359375 -10.816406 4.875 -11.34375 5.5 -11.6875 C 6.125 -12.03125 6.875 -12.203125 7.75 -12.203125 C 9.195312 -12.203125 10.375 -11.625 11.28125 -10.46875 C 12.1875 -9.320312 12.640625 -7.8125 12.640625 -5.9375 C 12.640625 -4.070312 12.1875 -2.5625 11.28125 -1.40625 C 10.375 -0.257812 9.195312 0.3125 7.75 0.3125 C 6.875 0.3125 6.125 0.140625 5.5 -0.203125 C 4.875 -0.546875 4.359375 -1.070312 3.953125 -1.78125 Z M 10.609375 -5.9375 C 10.609375 -7.382812 10.3125 -8.515625 9.71875 -9.328125 C 9.125 -10.148438 8.3125 -10.5625 7.28125 -10.5625 C 6.238281 -10.5625 5.421875 -10.148438 4.828125 -9.328125 C 4.242188 -8.515625 3.953125 -7.382812 3.953125 -5.9375 C 3.953125 -4.5 4.242188 -3.367188 4.828125 -2.546875 C 5.421875 -1.734375 6.238281 -1.328125 7.28125 -1.328125 C 8.3125 -1.328125 9.125 -1.734375 9.71875 -2.546875 C 10.3125 -3.367188 10.609375 -4.5 10.609375 -5.9375 Z M 10.609375 -5.9375 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-6"&gt;
&lt;path style="stroke:none;" d="M 2.046875 -16.546875 L 4.015625 -16.546875 L 4.015625 0 L 2.046875 0 Z M 2.046875 -16.546875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-7"&gt;
&lt;path style="stroke:none;" d="M 12.234375 -6.4375 L 12.234375 -5.484375 L 3.25 -5.484375 C 3.332031 -4.140625 3.734375 -3.113281 4.453125 -2.40625 C 5.179688 -1.695312 6.195312 -1.34375 7.5 -1.34375 C 8.25 -1.34375 8.972656 -1.4375 9.671875 -1.625 C 10.378906 -1.8125 11.082031 -2.085938 11.78125 -2.453125 L 11.78125 -0.609375 C 11.082031 -0.304688 10.363281 -0.078125 9.625 0.078125 C 8.882812 0.234375 8.132812 0.3125 7.375 0.3125 C 5.476562 0.3125 3.972656 -0.238281 2.859375 -1.34375 C 1.753906 -2.457031 1.203125 -3.957031 1.203125 -5.84375 C 1.203125 -7.789062 1.726562 -9.335938 2.78125 -10.484375 C 3.832031 -11.628906 5.253906 -12.203125 7.046875 -12.203125 C 8.640625 -12.203125 9.898438 -11.6875 10.828125 -10.65625 C 11.765625 -9.625 12.234375 -8.21875 12.234375 -6.4375 Z M 10.28125 -7.015625 C 10.269531 -8.085938 9.972656 -8.941406 9.390625 -9.578125 C 8.804688 -10.222656 8.03125 -10.546875 7.0625 -10.546875 C 5.96875 -10.546875 5.09375 -10.234375 4.4375 -9.609375 C 3.78125 -8.992188 3.40625 -8.128906 3.3125 -7.015625 Z M 10.28125 -7.015625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-8"&gt;
&lt;path style="stroke:none;" d=""&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-9"&gt;
&lt;path style="stroke:none;" d="M 3.984375 -15.296875 L 3.984375 -11.90625 L 8.015625 -11.90625 L 8.015625 -10.390625 L 3.984375 -10.390625 L 3.984375 -3.921875 C 3.984375 -2.953125 4.113281 -2.328125 4.375 -2.046875 C 4.644531 -1.773438 5.191406 -1.640625 6.015625 -1.640625 L 8.015625 -1.640625 L 8.015625 0 L 6.015625 0 C 4.503906 0 3.457031 -0.28125 2.875 -0.84375 C 2.300781 -1.40625 2.015625 -2.429688 2.015625 -3.921875 L 2.015625 -10.390625 L 0.578125 -10.390625 L 0.578125 -11.90625 L 2.015625 -11.90625 L 2.015625 -15.296875 Z M 3.984375 -15.296875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-10"&gt;
&lt;path style="stroke:none;" d="M 8.953125 -10.078125 C 8.734375 -10.210938 8.492188 -10.304688 8.234375 -10.359375 C 7.972656 -10.421875 7.6875 -10.453125 7.375 -10.453125 C 6.269531 -10.453125 5.421875 -10.09375 4.828125 -9.375 C 4.242188 -8.65625 3.953125 -7.625 3.953125 -6.28125 L 3.953125 0 L 1.984375 0 L 1.984375 -11.90625 L 3.953125 -11.90625 L 3.953125 -10.0625 C 4.359375 -10.78125 4.890625 -11.316406 5.546875 -11.671875 C 6.210938 -12.023438 7.015625 -12.203125 7.953125 -12.203125 C 8.085938 -12.203125 8.234375 -12.191406 8.390625 -12.171875 C 8.554688 -12.148438 8.738281 -12.125 8.9375 -12.09375 Z M 8.953125 -10.078125 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-11"&gt;
&lt;path style="stroke:none;" d="M 11.953125 -7.1875 L 11.953125 0 L 10 0 L 10 -7.125 C 10 -8.25 9.773438 -9.09375 9.328125 -9.65625 C 8.890625 -10.21875 8.234375 -10.5 7.359375 -10.5 C 6.304688 -10.5 5.472656 -10.160156 4.859375 -9.484375 C 4.253906 -8.804688 3.953125 -7.890625 3.953125 -6.734375 L 3.953125 0 L 1.984375 0 L 1.984375 -11.90625 L 3.953125 -11.90625 L 3.953125 -10.0625 C 4.410156 -10.78125 4.957031 -11.316406 5.59375 -11.671875 C 6.226562 -12.023438 6.960938 -12.203125 7.796875 -12.203125 C 9.160156 -12.203125 10.191406 -11.773438 10.890625 -10.921875 C 11.597656 -10.078125 11.953125 -8.832031 11.953125 -7.1875 Z M 11.953125 -7.1875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-12"&gt;
&lt;path style="stroke:none;" d="M 9.640625 -11.5625 L 9.640625 -9.703125 C 9.085938 -9.992188 8.515625 -10.207031 7.921875 -10.34375 C 7.328125 -10.488281 6.710938 -10.5625 6.078125 -10.5625 C 5.097656 -10.5625 4.363281 -10.410156 3.875 -10.109375 C 3.394531 -9.816406 3.15625 -9.375 3.15625 -8.78125 C 3.15625 -8.320312 3.328125 -7.960938 3.671875 -7.703125 C 4.023438 -7.441406 4.726562 -7.195312 5.78125 -6.96875 L 6.4375 -6.8125 C 7.832031 -6.519531 8.820312 -6.101562 9.40625 -5.5625 C 9.988281 -5.019531 10.28125 -4.257812 10.28125 -3.28125 C 10.28125 -2.175781 9.84375 -1.300781 8.96875 -0.65625 C 8.09375 -0.0078125 6.890625 0.3125 5.359375 0.3125 C 4.722656 0.3125 4.054688 0.25 3.359375 0.125 C 2.671875 0 1.945312 -0.1875 1.1875 -0.4375 L 1.1875 -2.453125 C 1.90625 -2.078125 2.613281 -1.796875 3.3125 -1.609375 C 4.019531 -1.421875 4.71875 -1.328125 5.40625 -1.328125 C 6.320312 -1.328125 7.03125 -1.484375 7.53125 -1.796875 C 8.03125 -2.117188 8.28125 -2.566406 8.28125 -3.140625 C 8.28125 -3.671875 8.097656 -4.078125 7.734375 -4.359375 C 7.378906 -4.640625 6.59375 -4.910156 5.375 -5.171875 L 4.703125 -5.34375 C 3.484375 -5.59375 2.601562 -5.984375 2.0625 -6.515625 C 1.53125 -7.046875 1.265625 -7.769531 1.265625 -8.6875 C 1.265625 -9.8125 1.660156 -10.675781 2.453125 -11.28125 C 3.242188 -11.894531 4.375 -12.203125 5.84375 -12.203125 C 6.5625 -12.203125 7.238281 -12.144531 7.875 -12.03125 C 8.519531 -11.925781 9.109375 -11.769531 9.640625 -11.5625 Z M 9.640625 -11.5625 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-13"&gt;
&lt;path style="stroke:none;" d="M 2.046875 -11.90625 L 4.015625 -11.90625 L 4.015625 0 L 2.046875 0 Z M 2.046875 -16.546875 L 4.015625 -16.546875 L 4.015625 -14.078125 L 2.046875 -14.078125 Z M 2.046875 -16.546875 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;symbol overflow="visible" id="glyph1-14"&gt;
&lt;path style="stroke:none;" d="M 6.671875 -10.546875 C 5.617188 -10.546875 4.785156 -10.132812 4.171875 -9.3125 C 3.566406 -8.488281 3.265625 -7.363281 3.265625 -5.9375 C 3.265625 -4.519531 3.566406 -3.398438 4.171875 -2.578125 C 4.773438 -1.753906 5.609375 -1.34375 6.671875 -1.34375 C 7.710938 -1.34375 8.535156 -1.753906 9.140625 -2.578125 C 9.753906 -3.398438 10.0625 -4.519531 10.0625 -5.9375 C 10.0625 -7.351562 9.753906 -8.472656 9.140625 -9.296875 C 8.535156 -10.128906 7.710938 -10.546875 6.671875 -10.546875 Z M 6.671875 -12.203125 C 8.367188 -12.203125 9.703125 -11.644531 10.671875 -10.53125 C 11.648438 -9.425781 12.140625 -7.894531 12.140625 -5.9375 C 12.140625 -3.988281 11.648438 -2.457031 10.671875 -1.34375 C 9.703125 -0.238281 8.367188 0.3125 6.671875 0.3125 C 4.960938 0.3125 3.625 -0.238281 2.65625 -1.34375 C 1.6875 -2.457031 1.203125 -3.988281 1.203125 -5.9375 C 1.203125 -7.894531 1.6875 -9.425781 2.65625 -10.53125 C 3.625 -11.644531 4.960938 -12.203125 6.671875 -12.203125 Z M 6.671875 -12.203125 "&gt;&lt;/path&gt;
&lt;/symbol&gt;
&lt;/g&gt;
&lt;/defs&gt;
&lt;g id="surface53632"&gt;
&lt;rect x="0" y="0" width="623" height="503" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"&gt;&lt;/rect&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 21 3 L 29 3 L 29 5 L 21 5 Z M 21 3 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-1" x="381.472656" y="65.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-2" x="389.347548" y="65.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-3" x="401.816081" y="65.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-4" x="409.941081" y="65.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-5" x="414.959798" y="65.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14 10 L 22 10 L 22 12 L 14 12 Z M 14 10 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="258.09375" y="205.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 25 5 L 18.396094 9.716992 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 18.091016 9.934961 L 18.352539 9.441016 L 18.396094 9.716992 L 18.643164 9.847852 Z M 18.091016 9.934961 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="302" y="121.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="309.843696" y="121.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="317.968696" y="121.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="326.093696" y="121.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="330.162435" y="121.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14 17 L 22 17 L 22 19 L 14 19 Z M 14 17 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="249.949219" y="345.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-9" x="257.792914" y="345.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="261.861654" y="345.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-10" x="265.930393" y="345.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 21 24 L 29 24 L 29 26 L 21 26 Z M 21 24 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="382.371094" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-9" x="390.214789" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="394.283529" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-10" x="398.352268" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-9" x="406.477268" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="410.546007" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-11" x="414.614746" y="485.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 24 L 16 24 L 16 26 L 8 26 Z M 8 24 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="123.640625" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-9" x="131.484321" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="135.55306" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-10" x="139.621799" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-9" x="147.746799" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="151.815538" y="485.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-12" x="155.884277" y="485.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 18 12 L 18 16.513281 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 18 16.888281 L 17.75 16.388281 L 18 16.513281 L 18.25 16.388281 Z M 18 16.888281 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1,0.266667,0.1,0.266667,0.1,0.266667;stroke-miterlimit:10;" d="M 18 19 L 12.374023 23.688281 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 12.085938 23.928516 L 12.309961 23.416211 L 12.374023 23.688281 L 12.630078 23.800391 Z M 12.085938 23.928516 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 18 19 L 24.603906 23.716992 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 24.908984 23.934961 L 24.356836 23.847852 L 24.603906 23.716992 L 24.647461 23.441016 Z M 24.908984 23.934961 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="219" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="226.843696" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="234.968696" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="243.093696" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-10" x="247.162435" y="281.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="161" y="412.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="168.843696" y="412.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="176.968696" y="412.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="185.093696" y="412.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-12" x="189.162435" y="412.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="341" y="410.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="348.843696" y="410.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="356.968696" y="410.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="365.093696" y="410.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-11" x="369.162435" y="410.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 10 L 36 10 L 36 12 L 28 12 Z M 28 10 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-13" x="538.230469" y="205.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 17 L 36 17 L 36 19 L 28 19 Z M 28 17 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-13" x="530.359375" y="345.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-9" x="537.934245" y="345.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="542.002984" y="345.154405"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-5" x="546.071723" y="345.154405"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1,0.266667,0.1,0.266667,0.1,0.266667;stroke-miterlimit:10;" d="M 25 5 L 31.603906 9.716992 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 31.908984 9.934961 L 31.356836 9.847852 L 31.603906 9.716992 L 31.647461 9.441016 Z M 31.908984 9.934961 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 32 12 L 32 16.513281 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 32 16.888281 L 31.75 16.388281 L 32 16.513281 L 32.25 16.388281 Z M 32 16.888281 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="482" y="122.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="489.843696" y="122.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="497.968696" y="122.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="506.093696" y="122.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-13" x="510.162435" y="122.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="551" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="558.843696" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-7" x="566.968696" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="575.093696" y="281.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-5" x="579.162435" y="281.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5 4 L 9.513281 4 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 9.888281 4 L 9.388281 4.25 L 9.513281 4 L 9.388281 3.75 Z M 9.888281 4 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1,0.266667,0.1,0.266667,0.1,0.266667;stroke-miterlimit:10;" d="M 5 7 L 9.513281 7 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 9.888281 7 L 9.388281 7.25 L 9.513281 7 L 9.388281 6.75 Z M 9.888281 7 " transform="matrix(20,0,0,20,-98,-18.75)"&gt;&lt;/path&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-11" x="2" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-14" x="9.037489" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-2" x="16.868707" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-2" x="29.33724" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-14" x="41.805773" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-15" x="49.63699" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="57.74924" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-4" x="61.81798" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-16" x="66.836697" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="72.099013" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-15" x="79.942708" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-17" x="88.054959" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-18" x="94.723524" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-4" x="98.279839" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-18" x="103.298557" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-14" x="106.854872" y="81.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-15" x="114.686089" y="81.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-19" x="2" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-1" x="5.556315" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-17" x="13.431207" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-17" x="20.099772" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="26.768338" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-11" x="30.837077" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-14" x="37.874566" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-2" x="45.705783" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-2" x="58.174316" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-14" x="70.642849" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-15" x="78.474067" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-8" x="86.586317" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-4" x="90.655056" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-16" x="95.673774" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-6" x="100.936089" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-15" x="108.779785" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-17" x="116.892036" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-18" x="123.560601" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-4" x="127.116916" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-18" x="132.135634" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-14" x="135.691949" y="141.255968"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph0-15" x="143.523166" y="141.255968"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;g style="fill:rgb(0%,0%,0%);fill-opacity:1;"&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-1" x="242" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-2" x="255.758409" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-3" x="268.644965" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-4" x="281.988878" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-5" x="303.200629" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-6" x="317.022786" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-7" x="323.072591" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-8" x="336.469672" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-4" x="343.39133" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-3" x="364.603082" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-5" x="377.946994" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-8" x="391.769151" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-9" x="398.690809" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-10" x="407.228678" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-3" x="416.181315" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-11" x="429.525228" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-12" x="443.326226" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-13" x="454.67117" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-9" x="460.720974" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-13" x="469.258843" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-14" x="475.308648" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-11" x="488.631131" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-8" x="502.432129" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-9" x="509.353787" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-10" x="517.891656" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-7" x="526.365777" y="21.26709"&gt;&lt;/use&gt;
  &lt;use xlink:href="https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html#glyph1-7" x="539.762858" y="21.26709"&gt;&lt;/use&gt;
&lt;/g&gt;
&lt;/g&gt;
&lt;/svg&gt;

&lt;br&gt;
This map tree is the result of parsing a file that has dictionaries with
the keys a, b, c many times, the keys a, b, f less often, and also some
objects with the keys x, y.&lt;br&gt;
When parsing a dictionary we traverse this tree from the root, according
to the keys that we see in the input file. While doing this, we
potentially add new nodes, if we get key combinations that we have never
seen before. The set of keys of a dictionary parsed so far are
represented by the current tree node, while we can store the values into
an array. We can use the tree of nodes to speed up parsing. A lot of the
nodes only have one child, because after reading the first few keys of
an object, the remaining ones are often uniquely determined in a given
file. If we have only one child map node, we can speculatively parse the
next key by doing a &lt;tt class="docutils literal"&gt;memcmp&lt;/tt&gt; between the key that the map tree says is
likely to come next and the characters that follow the ',' that started
the next entry in the dictionary. If the &lt;tt class="docutils literal"&gt;memcmp&lt;/tt&gt; returns true this
means that the speculation paid off, and we can transition to the new map
that the edge points to, and parse the corresponding value. If not, we
fall back to general code that parses the string, handles escaping rules
etc. This trick was explained to me by some V8 engineers, the same trick
is supposedly used &lt;a class="reference external" href="https://github.com/v8/v8/blob/master/src/json/json-parser.cc"&gt;as part of the V8 JSON parser&lt;/a&gt;.&lt;br&gt;
This scheme doesn't immediately work for map tree nodes that have more
than one child. However, since we keep statistics anyway about how often
each map is used as the map of a parsed dictionary, we can speculate
that the most common map transition is taken more often than the others
in the future, and use that as the speculated next node.&lt;br&gt;
So for the example transition tree shown in the figure above the key
speculation would succeed for objects with keys &lt;tt class="docutils literal"&gt;a, b, c&lt;/tt&gt;. For objects
with keys &lt;tt class="docutils literal"&gt;a, b, f&lt;/tt&gt; the speculation would succeed for the first two
keys, but not for the third key &lt;tt class="docutils literal"&gt;f&lt;/tt&gt;. For objects with the keys
&lt;tt class="docutils literal"&gt;x, y&lt;/tt&gt; the speculation would fail for the first key &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; but succeed
for the second key &lt;tt class="docutils literal"&gt;y&lt;/tt&gt;.&lt;br&gt;
For real-world datasets these transition trees can become a lot more
complicated, for example here is a visualization of a part of the
transition tree generated for parsing a New York Times dataset:&lt;br&gt;
&lt;a href="https://2.bp.blogspot.com/-Jv_p8rFIq8Y/XZubp3WVptI/AAAAAAAAwuY/rhTCqXJpoMUdtEf22tzqK64dcEJmBE6fwCPcBGAYYCw/s1600/2019_json_nytimes.png"&gt;&lt;img border="0" height="310" src="https://2.bp.blogspot.com/-Jv_p8rFIq8Y/XZubp3WVptI/AAAAAAAAwuY/rhTCqXJpoMUdtEf22tzqK64dcEJmBE6fwCPcBGAYYCw/s400/2019_json_nytimes.png" width="400"&gt;&lt;/a&gt;

&lt;br&gt;
&lt;h2&gt;
Caching Strings&lt;/h2&gt;
A rather obvious observation we can use to improve performance of the
parser is the fact that string values repeat a lot in most JSON files.
For strings that are used as dictionary keys this is pretty obvious.
However it happens also for strings that are used as values in
dictionaries (or are stored in lists). We can use this fact to
intern/memoize strings and save memory. This is an approach that many
JSON parsers use, including
&lt;a class="reference external" href="https://github.com/python/cpython/blob/3.7/Modules/_json.c#L749"&gt;CPython's&lt;/a&gt;.
To do this, I keep a dictionary of strings that we have seen so far
during parsing and look up new strings that are deserialized. If we have
seen the string before, we can re-use the deserialized previous string.
Right now I only consider utf-8 strings for caching that do not contain
any escapes (whether stuff like &lt;tt class="docutils literal"&gt;\", \n&lt;/tt&gt; or escaped unicode chars).&lt;br&gt;
This simple approach works extremely well for dictionary keys, but needs
a number of improvements to be a win in general. The first observation
is that computing the hash to look up the string in the dictionary of
strings we've seen so far is basically free. We can compute the hash
while scanning the input for the end of the string we are currently
deserializing. Computing the hash while scanning doesn't increase the
time spent scanning much. This is not a new idea, I am sure many other
parsers do the same thing (but CPython doesn't seem to).&lt;br&gt;
Another improvement follows from the observation that inserting every
single deserialized non-key string into a hashmap is too expensive.
Instead, we insert strings into the cache more conservatively, by
keeping a small ring buffer of hashes of recently deserialized strings.
The hash is looked for in the ring buffer, and only if the hash is
present we insert the string into the memoization hashmap. This has the
effect of only inserting strings into the memoization hashmap that
re-occur a second time not too far into the file. This seems to give a
good trade-off between still re-using a lot of strings but keeping the
time spent updating and the size of the memoization hashmap low.&lt;br&gt;
Another twist is that in a lot of situations caching strings is not
useful at all, because it will almost never succeed. Examples of this
are UUIDs (which are unique), or the content of a tweet in a JSON file
with many tweets (which is usually unique). However, in the same file it
might be useful to cache e.g. the user name of the Twitter user, because
many tweets from the same person could be in such a file. Therefore the
usefulness of the string cache depends on which fields of objects we are
deserializing the value off. Therefore we keep statistics per map field
and disable string memoization per individual field if the cache hit
rate falls below a certain threshold. This gives the best of both
worlds: in the cases where string values repeat a lot in certain fields
we use the cache to save time and memory. But for those fields that
mostly contain unique strings we don't waste time looking up and adding
strings in the memoization table. Strings outside of dictionaries are
quite rare anyway, so we just always try to use the cache for them.&lt;br&gt;
The following pseudocode sketches the code to deserialize a string in
the input at a given position. The function also takes a map, which is
the point in the map tree that we are currently deserializing a field
off (if we are deserializing a string in another context, some kind of
dummy map can be used there).&lt;br&gt;
&lt;pre&gt;&lt;code class="python"&gt;
def deserialize_string(pos, input, map):
    # input is the input string, pos is the position of the starting " of
    # the string

    # find end of string, check whether it contains escape codes,
    # compute hash, all at the same time
    end, escapes, hash = find_end_of_string(pos + 1, input)
    if end == -1:
        raise ParseError
    if escapes:
        # need to be much more careful with escaping
        return deserialize_string_escapes(pos, input)
    
    # should we cache at all?
    if map.cache_disabled():
        return input[pos + 1:end]

    # if string is in cache, return it
    if hash in cache:
        map.cache_hit += 1
        return cache[hash]

    result = input[pos + 1:end]
    map.cache_miss += 1

    # if hash is in the ring buffer of recently seen hashes,
    # add the string to the cache
    if hash in ring_buffer:
        cache[hash] = result
    else:
        ring_buffer.write(hash)
    return result

&lt;/code&gt;
&lt;/pre&gt;
&lt;h2&gt;
Evaluation&lt;/h2&gt;
To find out how much the various techniques help, I implemented a number
of JSON parsers in PyPy with different combinations of the techniques
enabled. I compared the numbers with the JSON parser of CPython 3.7.3
(simplejson), with ujson, with the JSON parser of Node 12.11.1 (V8) and with
RapidJSON (in DOM mode).&lt;br&gt;
I collected a number of medium-to-large JSON files to try the JSON
parsers on:&lt;br&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://censys.io/data"&gt;Censys&lt;/a&gt;: A subset of the Censys port and
protocol scan data for websites in the Alexa top million domains&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.gharchive.org/"&gt;Gharchive&lt;/a&gt;: Github activity from
January 15-23, 2015 from Github Archive&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://files.pushshift.io/reddit/comments/"&gt;Reddit&lt;/a&gt;: Reddit
comments from May 2009&lt;/li&gt;
&lt;li&gt;Rosie: The nested matches produced using the &lt;a class="reference external" href="https://rosie-lang.org/"&gt;Rosie pattern
language&lt;/a&gt; &lt;tt class="docutils literal"&gt;all.things&lt;/tt&gt; pattern on a log
file&lt;/li&gt;
&lt;li&gt;Nytimes: Metadata of a collection of New York Times articles&lt;/li&gt;
&lt;li&gt;Tpch: The TPC-H database benchmark's deals table as a JSON file&lt;/li&gt;
&lt;li&gt;Twitter: A JSON export of the @pypyproject Twitter account data&lt;/li&gt;
&lt;li&gt;Wikidata: A file storing a subset of the Wikidata fact dump from Nov
11, 2014&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.yelp.com/dataset/download"&gt;Yelp&lt;/a&gt;: A file of yelp
businesses&lt;/li&gt;
&lt;/ul&gt;
Here are the file sizes of the benchmarks:&lt;br&gt;
&lt;table class="dataframe"&gt;
  &lt;thead&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;File Size [MiB]&lt;/th&gt;
    &lt;/tr&gt;
&lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Censys&lt;/td&gt;
      &lt;td&gt;898.45&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Gharchive&lt;/td&gt;
      &lt;td&gt;276.34&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;NYTimes&lt;/td&gt;
      &lt;td&gt;12.98&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Reddit&lt;/td&gt;
      &lt;td&gt;931.65&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Rosie&lt;/td&gt;
      &lt;td&gt;388.88&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;TPCH&lt;/td&gt;
      &lt;td&gt;173.86&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Wikidata&lt;/td&gt;
      &lt;td&gt;119.75&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Yelp&lt;/td&gt;
      &lt;td&gt;167.61&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
I measured the times of each benchmark with a number of variations
of the improved PyPy algorithms:&lt;br&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;PyPyBaseline: The PyPy JSON parser as it was before my work with JSON
parsing started (PyPy version 5.8)&lt;/li&gt;
&lt;li&gt;PyPyKeyStringCaching: Memoizing the key strings of dictionaries, but
not the other strings in a json file, and not using maps to represent
dictionaries (this is the JSON parser that PyPy has been shipping since
version 5.9, in the benchmarks I used 7.1).&lt;/li&gt;
&lt;li&gt;PyPyMapNoCache: Like PyPyKeyStringCaching, but using maps to
represent dictionaries. This includes speculatively parsing the next
key using memcmp, but does not use string caching of non-key strings.&lt;/li&gt;
&lt;li&gt;PyPyFull: Like PyPyMapNoCache but uses a string cache for all
strings, not just keys. This is equivalent to what will be released soon as part of PyPy 7.2&lt;/li&gt;
&lt;/ul&gt;
In addition to wall clock time of parsing, I also measured the increase
in memory use of each implementation after the input string has been
deserialized, i.e. the size of the in-memory representation of every
JSON file.&lt;br&gt;

&lt;h3&gt;
Contributions of Individual Optimizations&lt;/h3&gt;
Let's first look at the contributions of the individual optimizations to the
overall performance and memory usage.&lt;br&gt;
&lt;img src="https://docs.google.com/uc?id=1oqsebLsZH8pj4exAVbDthaRhERXqg8mN" width="800/"&gt;
&lt;img src="https://docs.google.com/uc?id=1_3UuTihT0A6wfM-F3sj8j9M9IoQuvcCt" width="800/"&gt;

&lt;br&gt;
All the benchmarks were run 30 times in new processes, all the numbers are
normalized to PyPyFull.&lt;br&gt;
The biggest individual improvement to both parsing time and memory used comes
from caching just the keys in parsed dictionaries. This is the optimization in
PyPy's JSON parser that has been implemented for a while already. To understand
why this optimization is so useful, let's look at some numbers about each
benchmark, namely the number of total keys across all dictionaries in each
file, as well as the number of unique keys. As we can see, for all benchmarks
the number of unique keys is significantly smaller than the number of keys in
total.&lt;br&gt;
&lt;table class="dataframe"&gt;
  &lt;thead&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Number of keys&lt;/th&gt;
      &lt;th&gt;Number of unique keys&lt;/th&gt;
    &lt;/tr&gt;
&lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Censys&lt;/td&gt;
      &lt;td&gt;14 404 234&lt;/td&gt;
      &lt;td&gt;163&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Gharchive&lt;/td&gt;
      &lt;td&gt;6 637 881&lt;/td&gt;
      &lt;td&gt;169&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;NYTimes&lt;/td&gt;
      &lt;td&gt;417 337&lt;/td&gt;
      &lt;td&gt;60&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Reddit&lt;/td&gt;
      &lt;td&gt;25 226 397&lt;/td&gt;
      &lt;td&gt;21&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Rosie&lt;/td&gt;
      &lt;td&gt;28 500 101&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;TPCH&lt;/td&gt;
      &lt;td&gt;6 700 000&lt;/td&gt;
      &lt;td&gt;45&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Wikidata&lt;/td&gt;
      &lt;td&gt;6 235 088&lt;/td&gt;
      &lt;td&gt;1 602&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Yelp&lt;/td&gt;
      &lt;td&gt;5 133 914&lt;/td&gt;
      &lt;td&gt;61&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
The next big jump in deserialization time and memory comes from introducing
maps to represent deserialized dictionaries. With PyPyMapNoCache
deserialization time goes down because it's much cheaper to walk the tree
of maps and store all deserialized objects into an array of values than to
build hashmaps with the same keys again and again. Memory use goes down
for the same reason: it takes a lot less memory to store the shared
structure of each set of keys in the map, as opposed to repeating it again
and again in every hashmap.&lt;br&gt;
We can look at some numbers about every benchmark again. The table shows how
many map-based dictionaries are deserialized for every benchmark, and how many
hashmap-backed dictionaries. We see that the number of hashmap-backed
dictionaries is often zero, or at most a small percentage of all dictionaries
in each benchmark. Yelp has the biggest number of hashmap-backed dictionaries.
The reason for this is that the input file contains hashmaps that store
combinations of various features of Yelp businesses, and a lot of these
combinations are totally unique to a business. Therefore the heuristics
determine that it's better to store these using hashmaps.&lt;br&gt;
&lt;table class="dataframe"&gt;
  &lt;thead&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Map Dicts&lt;/th&gt;
      &lt;th&gt;Regular Dicts&lt;/th&gt;
      &lt;th&gt;% Regular Dicts&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Censys&lt;/td&gt;
      &lt;td&gt;4 049 235&lt;/td&gt;
      &lt;td&gt;1 042&lt;/td&gt;
      &lt;td&gt;0.03&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Gharchive&lt;/td&gt;
      &lt;td&gt;955 301&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;NYTimes&lt;/td&gt;
      &lt;td&gt;80 393&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Reddit&lt;/td&gt;
      &lt;td&gt;1 201 257&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Rosie&lt;/td&gt;
      &lt;td&gt;6 248 966&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;TPCH&lt;/td&gt;
      &lt;td&gt;1 000 000&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;0.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Wikidata&lt;/td&gt;
      &lt;td&gt;1 923 460&lt;/td&gt;
      &lt;td&gt;46 905&lt;/td&gt;
      &lt;td&gt;2.38&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Yelp&lt;/td&gt;
      &lt;td&gt;443 140&lt;/td&gt;
      &lt;td&gt;52 051&lt;/td&gt;
      &lt;td&gt;10.51&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

We can also look at numbers about how often the memcmp-based speculative
parsing of the next key of a given map succeeds. Looking at statistics
about each benchmark, we can see that the speculation of what key we
expect next pays off in a significant percentage of cases, between 63% for
Wikidata where the dictionary structures are quite irregular, and 99% for
Reddit, where all the dictionaries have the same set of keys.&lt;br&gt;
&lt;table class="dataframe"&gt;
  &lt;thead&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Number of Keys&lt;/th&gt;
      &lt;th&gt;Map Transitions&lt;/th&gt;
      &lt;th&gt;% Successful Speculation&lt;/th&gt;
    &lt;/tr&gt;
&lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Censys&lt;/td&gt;
      &lt;td&gt;14 404 234&lt;/td&gt;
      &lt;td&gt;14 403 243&lt;/td&gt;
      &lt;td&gt;65.79&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Gharchive&lt;/td&gt;
      &lt;td&gt;6 637 881&lt;/td&gt;
      &lt;td&gt;6 637 881&lt;/td&gt;
      &lt;td&gt;86.71&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;NYTimes&lt;/td&gt;
      &lt;td&gt;417 337&lt;/td&gt;
      &lt;td&gt;417 337&lt;/td&gt;
      &lt;td&gt;79.85&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Reddit&lt;/td&gt;
      &lt;td&gt;25 226 397&lt;/td&gt;
      &lt;td&gt;25 226 397&lt;/td&gt;
      &lt;td&gt;100.00&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Rosie&lt;/td&gt;
      &lt;td&gt;28 500 101&lt;/td&gt;
      &lt;td&gt;28 500 101&lt;/td&gt;
      &lt;td&gt;90.37&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;TPCH&lt;/td&gt;
      &lt;td&gt;6 700 000&lt;/td&gt;
      &lt;td&gt;6 700 000&lt;/td&gt;
      &lt;td&gt;86.57&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Wikidata&lt;/td&gt;
      &lt;td&gt;6 235 088&lt;/td&gt;
      &lt;td&gt;5 267 744&lt;/td&gt;
      &lt;td&gt;63.68&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;Yelp&lt;/td&gt;
      &lt;td&gt;5 133 914&lt;/td&gt;
      &lt;td&gt;4 593 980&lt;/td&gt;
      &lt;td&gt;90.43&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr style="text-align: right;"&gt;
      &lt;td&gt;geomean&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
      &lt;td&gt;82.04&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
General string caching is the most unclear optimization. On the one hand its
impact on memory usage is quite substantial, leading to a 20% reduction for
Gharchive and Reddit, up to a 2× improvement for Yelp. On the other hand, the
effect on performance is less clear, since it even leads to a slowdown in
Gharchive and Reddit, and generally only a small improvement. Choosing the
right heuristic for when to disable the cache also has somewhat unclear effects
and is definitely a topic worthy of further investigation.&lt;br&gt;
&lt;h3&gt;
Comparison against other JSON Decoders&lt;/h3&gt;
To get a more general feeling of the performance and memory usage of the
improved PyPy parser, we compare it against CPython's built-in json
parser, ujson for CPython, Node's (V8) JSON parser and RapidJSON. For
better context for the memory usage I also show the file size of the input
files.&lt;br&gt;
These benchmarks are not really an apples-to-apple comparison. All of the
implementations use different in-memory representations of strings in
the deserialized data-structure (Node uses two bytes per character in
a string, &lt;a href="https://www.python.org/dev/peps/pep-0393/"&gt;in CPython it
depends&lt;/a&gt; but 4 bytes on my
machine), PyPyBaseline uses four bytes, PyPy and RapidJSON use utf-8). But
it's still interesting to get some ballpark numbers. The results are as
follows:&lt;br&gt;
&lt;img src="https://docs.google.com/uc?id=1Q-aFNXE-sWJi5kSKTwmQNLz5LI3DDgtm" width="800/"&gt;
&lt;img src="https://docs.google.com/uc?id=1sgGyqp93_czrxN4IYkXeZ-jFWCAs37bu" width="800/"&gt;

&lt;br&gt;
As we can see, PyPyFull handily beats CPython and ujson, with a geometric
mean of the improvement of about 2.5×. The memory improvement can be even
more extreme, with an improvement of over 4× against CPython/ujson in some
cases (CPython gives better memory sizes, because its parser caches the
keys of dictionaries as well). Node is often more than 50% slower, whereas
RapidJSON beats us easily, by a factor of 2× on average.&lt;br&gt;
&lt;h2&gt;
Conclusions&lt;/h2&gt;
While the speedup I managed to achieve over the course of this project is
nice and I am certainly happy to beat both CPython and Node, I am
ultimately still annoyed that RapidJSON manages to maintain such a clear
lead over PyPyFull, and would like to get closer to it. One problem that
PyPy suffers compared to RapidJSON is the overhead of garbage collection.
Deserializing large JSON files is pretty much the worst case for the
generational GC that PyPy uses, since none of the deserialized objects die
young (and the GC expects that most objects do). That means that a lot of
the deserialization time of PyPy is wasted allocating the resulting
objects in the nursery, and then copying them into the old generation.
Somehow, this should be done in better ways, but all my attempts to not
have to do the copy did not seem to help much. So maybe more improvements
are possible, if I can come up with more ideas.&lt;br&gt;
On the memory side of things, Node/V8 is beating PyPy clearly which might
indicate more general problems in how we represent Python objects in
memory. On the other hand, I think it's cool that we are competitive with
RapidJSON in terms of memory and often within 2× of the file size.&lt;br&gt;
An effect that I didn't consider at all in this blog post is the fact that
accessing the deserialized objects with constants strings is &lt;i&gt;also&lt;/i&gt; faster
than with regular dictionaries, due to them being represented with maps.
More benchmarking work to do in the future!&lt;br&gt;
If you have your own programs that run on PyPy and use the json parser
a lot, please measure them on the new code and let me know whether you see
any difference!</description><guid>https://www.pypy.org/posts/2019/10/pypys-new-json-parser-492911724084305501.html</guid><pubDate>Tue, 08 Oct 2019 12:37:00 GMT</pubDate></item><item><title>An RPython JIT for LPegs</title><link>https://www.pypy.org/posts/2019/04/an-rpython-jit-for-lpegs-4779548053359386284.html</link><dc:creator>Carl Friedrich Bolz-Tereick</dc:creator><description>&lt;p&gt;The following is a guest post by Stefan Troost, he describes the work he did in his bachelor thesis:&lt;/p&gt;

&lt;p&gt;In this project we have used the RPython infrastructure to generate an RPython
JIT for a
less-typical use-case: string pattern matching. The work in this project is
based on &lt;a href="https://www.pypy.org/posts/2019/04/bford.info/pub/lang/peg.pdf"&gt;Parsing Expression Grammars&lt;/a&gt; and
&lt;a href="https://www.pypy.org/posts/2019/04/www.inf.puc-rio.br/~roberto/docs/peg.pdf"&gt;LPeg&lt;/a&gt;, an implementation of PEGs
designed to be used in Lua. In this post I will showcase some of the work that
went into this project, explain PEGs in general and LPeg in particular, and
show some benchmarking results.&lt;/p&gt;
&lt;h1&gt;&lt;a id="Parsing_Expression_Grammars_12"&gt;&lt;/a&gt;Parsing Expression Grammars&lt;/h1&gt;
&lt;p&gt;Parsing Expression Grammas (PEGs) are a type of formal grammar similar to
context-free grammars, with the main difference being that they are unambiguous.
This is achieved by redefining the ambiguous choice operator of CFGs (usually
noted as &lt;code&gt;|&lt;/code&gt;) as an &lt;em&gt;ordered&lt;/em&gt; choice operator. In practice this means that if a
rule in a PEG presents a choice, a PEG parser should prioritize the leftmost
choice. Practical uses include parsing and pattern-searching. In comparison to
regular expressions PEGs stand out as being able to be parsed in linear time,
being strictly more powerful than REs, as well as being arguably more readable.&lt;/p&gt;
&lt;h1&gt;&lt;a id="LPeg_24"&gt;&lt;/a&gt;LPeg&lt;/h1&gt;
&lt;p&gt;LPeg is an implementation of PEGs written in C to be used in the Lua
programming language. A crucial detail of this implementation is that it parses
high level function calls, translating them to bytecode, and interpreting that
bytecode. Therefore, we are able to improve that implementation by replacing
LPegs C-interpreter with an RPython JIT. I use a modified version of LPeg to
parse PEGs and pass the generated Intermediate Representation, the LPeg
bytecode, to my VM.&lt;/p&gt;
&lt;h1&gt;&lt;a id="The_LPeg_Library_35"&gt;&lt;/a&gt;The LPeg Library&lt;/h1&gt;
&lt;p&gt;The LPeg Interpreter executes bytecodes created by parsing a string of commands
using the LPeg library. Our JIT supports a subset of the LPeg library, with
some of the more advanced or obscure features being left out. Note that this
subset is still powerful enough to do things like parse JSON.&lt;/p&gt;
&lt;table class="table table-striped table-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operator&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.P(string)&lt;/td&gt;
&lt;td&gt;Matches string literally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.P(n)&lt;/td&gt;
&lt;td&gt;Matches exactly n characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.P(-n)&lt;/td&gt;
&lt;td&gt;Matches at most n characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.S(string)&lt;/td&gt;
&lt;td&gt;Matches any character in string (Set)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.R(“xy”)&lt;/td&gt;
&lt;td&gt;Matches any character between x and y (Range)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pattern^n&lt;/td&gt;
&lt;td&gt;Matches at least n repetitions of pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pattern^-n&lt;/td&gt;
&lt;td&gt;Matches at most n repetitions of pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pattern1 * pattern2&lt;/td&gt;
&lt;td&gt;Matches pattern1 followed by pattern2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pattern1 + pattern2&lt;/td&gt;
&lt;td&gt;Matches pattern1 or pattern2 (ordered choice)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pattern1 - pattern2&lt;/td&gt;
&lt;td&gt;Matches pattern1 if pattern2 does not match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-pattern&lt;/td&gt;
&lt;td&gt;Equivalent to ("" - pattern)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As a simple example, the pattern &lt;code&gt;lpeg.P"ab"+lpeg.P"cd"&lt;/code&gt; would match either the
string &lt;code&gt;ab&lt;/code&gt; or the string &lt;code&gt;cd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To extract semantic information from a pattern, captures are needed. These are
the following operations supported for capture creation.&lt;/p&gt;
&lt;table class="table table-striped table-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;What it produces&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.C(pattern)&lt;/td&gt;
&lt;td&gt;the match for pattern plus all captures made by pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lpeg.Cp()&lt;/td&gt;
&lt;td&gt;the current position (matches the empty string)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;(tables taken from the &lt;a href="https://www.inf.puc-rio.br/~roberto/lpeg/"&gt;LPeg documentation&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;These patterns are translated into bytecode by LPeg, at which point we are able
to pass them into our own VM.&lt;/p&gt;
&lt;h1&gt;&lt;a id="The_VM_73"&gt;&lt;/a&gt;The VM&lt;/h1&gt;
&lt;p&gt;The state of the VM at any point is defined by the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PC&lt;/code&gt;: program counter indicating the current instruction&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fail&lt;/code&gt;: an indicator that some match failed and the VM must backtrack&lt;/li&gt;
&lt;li&gt;&lt;code&gt;index&lt;/code&gt;: counter indicating the current character of the input string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stackentries&lt;/code&gt;: stack of return addresses and choice points&lt;/li&gt;
&lt;li&gt;&lt;code&gt;captures&lt;/code&gt;: stack of capture objects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The execution of bytecode manipulates the values of these variables in order to
produce some output. How that works and what that output looks like will be
explained now.&lt;/p&gt;
&lt;h1&gt;&lt;a id="The_Bytecode_88"&gt;&lt;/a&gt;The Bytecode&lt;/h1&gt;
&lt;p&gt;For simplicity’s sake I will not go over every individual bytecode, but instead
choose some that exemplify the core concepts of the bytecode set.&lt;/p&gt;
&lt;h2&gt;&lt;a id="generic_character_matching_bytecodes_93"&gt;&lt;/a&gt;generic character matching bytecodes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;any&lt;/code&gt;: Checks if there’s any characters left in the inputstring. If it succeeds
it advances the index and PC by 1, if not the bytecode fails.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;char c&lt;/code&gt;: Checks if there is another bytecode in the input and if that
character is equal to &lt;code&gt;c&lt;/code&gt;. Otherwise the bytecode fails.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;set c1-c2&lt;/code&gt;: Checks if there is another bytecode in the input and if that
character is between (including) c1 and c2. Otherwise the bytecode fails.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These bytecodes are the easiest to understand with very little impact on the
VM. What it means for a bytecode to fail will be explained when
we get to control flow bytecodes.&lt;/p&gt;
&lt;p&gt;To get back to the example, the first half of the pattern &lt;code&gt;lpeg.P"ab"&lt;/code&gt; could be
compiled to the following bytecodes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char a
char b
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;a id="control_flow_bytecodes_117"&gt;&lt;/a&gt;control flow bytecodes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;jmp n&lt;/code&gt;: Sets &lt;code&gt;PC&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt;, effectively jumping to the n’th bytecode. Has no defined
failure case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;testchar c n&lt;/code&gt;: This is a lookahead bytecode. If the current character is equal
to &lt;code&gt;c&lt;/code&gt; it advances the &lt;code&gt;PC&lt;/code&gt; but not the index. Otherwise it jumps to &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;call n&lt;/code&gt;: Puts a return address (the current &lt;code&gt;PC + 1&lt;/code&gt;) on the &lt;code&gt;stackentries&lt;/code&gt; stack
and sets the &lt;code&gt;PC&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt;. Has no defined failure case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ret&lt;/code&gt;: Opposite of &lt;code&gt;call&lt;/code&gt;. Removes the top value of the &lt;code&gt;stackentries&lt;/code&gt; stack (if
the string of bytecodes is valid this will always be a return address) and
sets the &lt;code&gt;PC&lt;/code&gt; to the removed value. Has no defined failure case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;choice n&lt;/code&gt;: Puts a choice point on the &lt;code&gt;stackentries&lt;/code&gt; stack. Has no defined
failure case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;commit n&lt;/code&gt;: Removes the top value of the &lt;code&gt;stackentries&lt;/code&gt; stack (if the string of
bytecodes is valid this will always be a choice point) and jumps to &lt;code&gt;n&lt;/code&gt;. Has no
defined failure case.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using &lt;code&gt;testchar&lt;/code&gt; we can implement the full pattern &lt;code&gt;lpeg.P"ab"+lpeg.P"cd"&lt;/code&gt; with
bytecode as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;testchar a -&amp;gt; L1
any
char b
end
any
L1: char c
char d
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;any&lt;/code&gt; bytecode is needed because &lt;code&gt;testchar&lt;/code&gt; does not consume a character
from the input.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Failure_Handling_Backtracking_and_Choice_Points_158"&gt;&lt;/a&gt;Failure Handling, Backtracking and Choice Points&lt;/h2&gt;
&lt;p&gt;A choice point consist of the VM’s current &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;capturestack&lt;/code&gt; as well as a
&lt;code&gt;PC&lt;/code&gt;. This is not the VM’s &lt;code&gt;PC&lt;/code&gt; at the time of creating the
choicepoint, but rather the &lt;code&gt;PC&lt;/code&gt; where we should continue trying to find
matches when a failure occurs later.&lt;/p&gt;
&lt;p&gt;Now that we have talked about choice points, we can talk about how the VM
behaves in the fail state. If the VM is in the fail state, it removed entries
from the stackentries stack until it finds a choice point. Then it backtracks
by restoring the VM to the state defined by the choice point. If no choice
point is found this way, no match was found in the string and the VM halts.&lt;/p&gt;
&lt;p&gt;Using choice points we could implement the example &lt;code&gt;lpeg.P"ab" + lpeg.P"cd"&lt;/code&gt; in
bytecodes in a different way (LPEG uses the simpler way shown above, but for
more complex patterns it can’t use the lookahead solution using &lt;code&gt;testchar&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;choice L1
char a
char b
commit
end
L1: char c
char d
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;a id="Captures_188"&gt;&lt;/a&gt;Captures&lt;/h2&gt;
&lt;p&gt;Some patterns require the VM to produce more output than just “the pattern
matched” or “the pattern did not match”. Imagine searching a document for an
IPv4 address and all your program responded was “I found one”. In order to
recieve additional information about our inputstring, captures are used.&lt;/p&gt;
&lt;h3&gt;&lt;a id="The_capture_object_195"&gt;&lt;/a&gt;The capture object&lt;/h3&gt;
&lt;p&gt;In my VM, two types of capture objects are supported, one of them being the
position capture. It consists of a single index referencing the point in the
inputstring where the object was created.&lt;/p&gt;
&lt;p&gt;The other type of capture object is called simplecapture. It consists of an
index and a size value, which are used to reference a substring of the
inputstring. In addition, simplecaptures have a variable status indicating they
are either open or full. If a simplecapture object is open, that means that its
size is not yet determined, since the pattern we are capturing is of variable
length.&lt;/p&gt;
&lt;p&gt;Capture objects are created using the following bytecodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Fullcapture Position&lt;/code&gt;: Pushes a positioncapture object with the current index
value to the capture stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Fullcapture Simple n&lt;/code&gt;: Pushes a simplecapture object with current index value
and size=n to the capture stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Opencapture Simple&lt;/code&gt;: Pushes an open simplecapture object with current index
value and undetermined size to the capture stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;closecapture&lt;/code&gt;: Sets the top element of the capturestack to full and sets its
size value using the difference between the current index and the index of
the capture object.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&lt;a id="The_RPython_Implementation_224"&gt;&lt;/a&gt;The RPython Implementation&lt;/h1&gt;
&lt;p&gt;These, and many more bytecodes were implemented in an RPython-interpreter.
By adding jit hints, we were able to generate an efficient JIT.
We will now take a closer look at some implementations of bytecodes.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;...
        &lt;span class="hljs-keyword"&gt;elif&lt;/span&gt; instruction.name == &lt;span class="hljs-string"&gt;"any"&lt;/span&gt;:
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; index &amp;gt;= len(inputstring):
                fail = &lt;span class="hljs-keyword"&gt;True&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;else&lt;/span&gt;:
                pc += &lt;span class="hljs-number"&gt;1&lt;/span&gt;
                index += &lt;span class="hljs-number"&gt;1&lt;/span&gt;

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code for the &lt;code&gt;any&lt;/code&gt;-bytecode is relatively straight-forward. It either
advances the &lt;code&gt;pc&lt;/code&gt; and &lt;code&gt;index&lt;/code&gt; or sets the VM into the fail state,
depending on whether the end of the inputstring has been reached or not.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;...
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; instruction.name == &lt;span class="hljs-string"&gt;"char"&lt;/span&gt;:
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; index &amp;gt;= len(inputstring):
                fail = &lt;span class="hljs-keyword"&gt;True&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;elif&lt;/span&gt; instruction.character == inputstring[index]:
                pc += &lt;span class="hljs-number"&gt;1&lt;/span&gt;
                index += &lt;span class="hljs-number"&gt;1&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;else&lt;/span&gt;:
                fail = &lt;span class="hljs-keyword"&gt;True&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;char&lt;/code&gt;-bytecode also looks as one would expect. If the VM’s string index is
out of range or the character comparison fails, the VM is put into the
fail state, otherwise the &lt;code&gt;pc&lt;/code&gt; and &lt;code&gt;index&lt;/code&gt; are advanced by 1. As you can see, the
character we’re comparing the current inputstring to is stored in the
instruction object (note that this code-example has been simplified for
clarity, since the actual implementation includes a jit-optimization that
allows the VM to execute multiple successive char-bytecodes at once).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;...
        &lt;span class="hljs-keyword"&gt;elif&lt;/span&gt; instruction.name == &lt;span class="hljs-string"&gt;"jmp"&lt;/span&gt;:
            pc = instruction.goto
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;jmp&lt;/code&gt;-bytecode comes with a &lt;code&gt;goto&lt;/code&gt; value which is a &lt;code&gt;pc&lt;/code&gt; that we want
execution to continue at.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;...
        &lt;span class="hljs-keyword"&gt;elif&lt;/span&gt; instruction.name == &lt;span class="hljs-string"&gt;"choice"&lt;/span&gt;:
            pc += &lt;span class="hljs-number"&gt;1&lt;/span&gt;
            choice_points = choice_points.push_choice_point(
                instruction.goto, index, captures)
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see here, the &lt;code&gt;choice&lt;/code&gt;-bytecode puts a choice point onto the stack that
may be backtracked to if the VM is in the fail-state. This choice point
consists of a pc to jump to which is determined by the bytecode.
But it also includes the current &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;captures&lt;/code&gt; values at the time the choice
point was created. An ongoing topic of jit optimization is which data structure
is best suited to store choice points and return addresses. Besides naive
implementations of stacks and single-linked lists, more case-specific
structures are also being tested for performance.&lt;/p&gt;
&lt;h1&gt;&lt;a id="Benchmarking_Result_299"&gt;&lt;/a&gt;Benchmarking Result&lt;/h1&gt;
&lt;p&gt;In order to find out how much it helps to JIT LPeg patterns we ran a small
number of benchmarks. We used an otherwise idle Intel Core i5-2430M CPU with
3072 KiB of cache and 8 GiB of RAM, running with 2.40GHz. The machine was
running Ubuntu 14.04 LTS, Lua 5.2.3 and we used GNU grep 2.16 as a point of
comparison for one of the benchmarks. The benchmarks were run 100 times in
a new process each. We measured the full runtime of the called process,
including starting the process.&lt;/p&gt;
&lt;p&gt;Now we will take a look at some plots generated by measuring the runtime of
different iterations of my JIT compared to lua and using bootstrapping to
generate a sampling distribution of mean values. The plots contain a few different
variants of pypeg, only the one called "fullops" is important for this blog post, however.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://1.bp.blogspot.com/-Qv3aZapdMOk/XKXMDhTGujI/AAAAAAAAsNo/b7QShypeeV8mvePwTjPgmDSzUVB6EsiaACLcBGAs/s1600/rawplot_100_kb_urlinput.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="https://1.bp.blogspot.com/-Qv3aZapdMOk/XKXMDhTGujI/AAAAAAAAsNo/b7QShypeeV8mvePwTjPgmDSzUVB6EsiaACLcBGAs/s400/rawplot_100_kb_urlinput.png" width="400"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;This is the plot for a search pattern that searches a text file for valid URLs.
As we can see, if the input file is as small as 100 kb, the benefits of JIT
optimizations do not outweigh the time required to generate the
machine code. As a result, all of our attempts perform significantly slower
than LPeg.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://2.bp.blogspot.com/-mTry3w1vSFA/XKXMNoaeHOI/AAAAAAAAsNs/YhdGWoGmyjU3yxqFgcePBklGv-qw13wXgCLcBGAs/s1600/rawplot_500_kb_urlinput.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="https://2.bp.blogspot.com/-mTry3w1vSFA/XKXMNoaeHOI/AAAAAAAAsNs/YhdGWoGmyjU3yxqFgcePBklGv-qw13wXgCLcBGAs/s400/rawplot_500_kb_urlinput.png" width="400"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;This is the plot for the same search pattern on a larger input file. As we can
see, for input files as small as 500 kb our VM already outperforms LPeg’s. An
ongoing goal of continued development is to get this lower boundary as small as
possible.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://2.bp.blogspot.com/-Cr4BE9Cejg8/XKXMUXamP3I/AAAAAAAAsN0/t5PTo0Q4vPMLwL12bdQ93Q4bAMIjJTEVACLcBGAs/s1600/rawplot_5_mb_urlinput.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="https://2.bp.blogspot.com/-Cr4BE9Cejg8/XKXMUXamP3I/AAAAAAAAsN0/t5PTo0Q4vPMLwL12bdQ93Q4bAMIjJTEVACLcBGAs/s400/rawplot_5_mb_urlinput.png" width="400"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;The benefits of a JIT compared to an Interpreter become more and more relevant
for larger input files. Searching a file as large as 5 MB makes this fairly
obvious and is exactly the behavior we expect.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://2.bp.blogspot.com/-uIoguDb7ApE/XKXMngYEnSI/AAAAAAAAsOA/zdv2WAfdRwwruS1yOdX7jFz0nB_PPQqRACLcBGAs/s1600/rawplot_50_kb_jsoninput.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="https://2.bp.blogspot.com/-uIoguDb7ApE/XKXMngYEnSI/AAAAAAAAsOA/zdv2WAfdRwwruS1yOdX7jFz0nB_PPQqRACLcBGAs/s400/rawplot_50_kb_jsoninput.png" width="400"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;This time we are looking at a different more complicated pattern, one that parses JSON used on a
50 kb input file. As expected, LPeg outperforms us, however, something
unexpected happens as we increase the filesize.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://3.bp.blogspot.com/-r1-Aq39Oe9I/XKXMuQlcB6I/AAAAAAAAsOE/Eqmj7i3JKz0zdTK6Cd1ai11aZCf-EZkVwCLcBGAs/s1600/rawplot_100_kb_jsoninput.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="https://3.bp.blogspot.com/-r1-Aq39Oe9I/XKXMuQlcB6I/AAAAAAAAsOE/Eqmj7i3JKz0zdTK6Cd1ai11aZCf-EZkVwCLcBGAs/s400/rawplot_100_kb_jsoninput.png" width="400"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Since LPeg has a defined maximum depth of 400 for the choicepoints and
returnaddresses Stack, LPeg by default refuses to parse files as small as
100kb. This raises the question if LPeg was intended to be used for parsing.
Until a way to increase LPeg’s maximum stack depth is found, no comparisons to
LPeg can be performed at this scale. This has been a low priority in the past
but may be addressed in the future.&lt;/p&gt;
&lt;p&gt;To conclude, we see that at sufficiently high filesizes, our JIT outperforms
the native LPeg-interpreter. This lower boundary is currently as low as 100kb
in filesize.&lt;/p&gt;
&lt;h1&gt;&lt;a id="Conclusion_353"&gt;&lt;/a&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Writing a JIT for PEG’s has proven itself to be a challenge worth pursuing, as
the expected benefits of a JIT compared to an Interpreter have been achieved.
Future goals include getting LPeg to be able to use parsing patterns on larger
files, further increasing the performance of our JIT and comparing it to other
well-known programs serving a similar purpose, like grep.&lt;/p&gt;
&lt;p&gt;The prototype implementation that I described in this post can be found
&lt;a href="https://github.com/sktroost/PyPeg/tree/master/pypeg"&gt;on Github&lt;/a&gt;
(it's a bit of a hack in some places, though).&lt;/p&gt;</description><guid>https://www.pypy.org/posts/2019/04/an-rpython-jit-for-lpegs-4779548053359386284.html</guid><pubDate>Thu, 04 Apr 2019 21:26:00 GMT</pubDate></item></channel></rss>