<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <author>
    <name>Ramkumar Ramachandra</name>
  </author>
  <id>https://artagnon.com/feed.xml</id>
  <title>artagnon.com</title>
  <updated>2026-02-16T15:13:35+00:00</updated>
  <entry>
    <id>art/2043</id>
    <link href="art/2043"/>
    <summary>&lt;p&gt;&quot;I&#39;m sorry, but we have to let you go&quot;, she says. &quot;Right. What do I need to ink?&quot;, I respond, prepared. I don&#39;t need this job to pay the bills, and I don&#39;t enjoy it. I&#39;d been contemplating resignation for a while now, but a fat severance cheque can&#39;t hurt. The HR woman hands me a crisp document on her tablet. &quot;Do you know what you&#39;ll do next?&quot;, she asks robotically. My mind wanders, and I flippantly say &quot;Maybe I&#39;ll move to Antarctica and take up flame-throwing&quot;. &quot;Oh, good luck with that&quot;, she says, with a meaningless smile. Another robotic response. The lord wonders why she&#39;s still employed.&lt;/p&gt;
&lt;p&gt;I wander around the sterile campus filled with man-child millionaires typing away furiously on their notebooks, one last time. The memory of the insipid lunch I had at the canteen lingers. Looking forward to a good celebratory dinner though. I have a foggy recollection of the templated interviews I had to sit through eight months ago — it&#39;s dizzying to think that I survived here for the better part of a year.&lt;/p&gt;
&lt;p&gt;As I head back home on the loop, I carelessly browse some blog entries by people who quit the company. It&#39;s been done to death. Everyone thinks that their reasons are somehow more unique or insightful than those of the others, but they all boil down to one reason: stagnation. They all had dreams of becoming billionaires, but got stuck in middle-management. Of course, the posts carefully leave this detail out — instead they talk about &quot;growth&quot;. They sound like vegetables in a garden competing for sunlight and soil.&lt;/p&gt;
&lt;p&gt;A little electric transports me from the loop station to my suburban home. These internet companies had their glory days in the early 2000s — today, they&#39;re just addiction algorithms that keep users hooked onto their platforms, and maximize eyeballs on ads. All of them have sizable neuro departments, doing research on addiction patterns in children and young adults. Work is both unethical and mind-numbing, but it pays really well.&lt;/p&gt;
&lt;p&gt;As my mind clears, my link brings up ticket prices to various destinations. Impulsively, I book two one-way tickets to Paris departing the next morning. For the highly educated and cultured, moving countries is never a problem — international travel has really eased up in the last decade. Back in the dark ages, the immigrants would visa-hop until they &quot;settled down&quot;. Today, everyone is an immigrant of some kind — who wants to live in the country they grew up in? It&#39;s half-past four, and I recognize my neighborhood from the mini.&lt;/p&gt;
&lt;p&gt;&quot;We&#39;re moving to Paris tomorrow!&quot;, I announce, as I get in. Madeline makes a weird anime expression as she looks up from her paperback. I try to identify the soft indie music from the LP, but no avail. &quot;It&#39;s about time&quot;, she says, after a pause, with a broad unquestioning smile. I&#39;d never consulted her on the destination, but she&#39;s not one to take issue with such things. We love surprising each other.&lt;/p&gt;
&lt;p&gt;I&#39;m trying to remember how I ever convinced her to move to this suburb in the first place — ah yes, a long vacation in a house facing the sea, with abundant money to buy books, LPs, and scotch didn&#39;t sound like a bad prospect. The last month or so has been a bit hard on us though — the cultural poverty of the surroundings was getting a bit much. There isn&#39;t much to do when friends from other parts of the world visit us. Much of the culture in the nearby city is centered around tech, a topic that we have little interest in. Our friends are initially fascinated by the high-tech convenience systems that come with wealth, but its novelty starts to wear off pretty quickly.&lt;/p&gt;
&lt;p&gt;&quot;Mauzac or Négrette?&quot;, she offers, as she gently gets up from the couch. I pick Mauzac, switch the music to Tame Impala, and turn the volume up a notch. Normal people wouldn&#39;t bother with analog music, and just shuffle about within their recommendation systems. &quot;Ancient music!&quot;, she exclaims, and we kiss tenderly and hug as two young lesbians. She never asks about work, and I have no reason to talk about it either. I pull up some AirBnBs on my link, narrow it down to a few near the center of the city, and let Madeline pick one. I&#39;ve already made the big decision of the evening.&lt;/p&gt;
&lt;p&gt;&quot;You will get that link removed, yes?&quot;, Madeline asks with raised eyebrows. &quot;I don&#39;t know; it&#39;s so convenient&quot;, I respond sheepishly. It won&#39;t be half as useful in Paris, but I hadn&#39;t given the issue much thought. She shakes her head with a grin. &quot;You resisted getting it for the longest time, but this tech job finally broke you&quot;. We were among the minority in London for resisting links. Madeline thinks it&#39;s an outrageous breach of privacy. I agreed with her for the longest time, but fell into the convenience-trap in the end.&lt;/p&gt;
&lt;p&gt;The doorbell chimes, indicating that our bot has arrived with packing boxes. Moving is hardly an ordeal these days — we move every three or four years. Unlike most people, we don&#39;t need a reason to move, but rather a reason not to move. Becoming fluent in the local language usually doesn&#39;t take us more than a couple of months; Mandarin was the exception — took us a little over six. Prior to our move to this suburb, we had four good years in London. She was working at the local museum, and I was doing my PhD in higher categories.&lt;/p&gt;
&lt;p&gt;&quot;Will you miss the high-tech conveniences?&quot;, she asks naughtily, as the sophomore girlfriend. She loves doing this to the rigid old man: poking him about what he&#39;ll miss everytime something changes. When we moved from London, she asked me whether I&#39;d miss the tube. &quot;I certainly won&#39;t miss the 8-hour weekday grind&quot;. I was exaggerating — having expended the minimum work in order to keep my dayjob afloat, and used a lot of my time to read and practice oil-on-canvas. These goliath companies are complacent about keeping tabs on their employees, as most of them are addicted to developing the addiction algorithms. The irony. Nevertheless, that should change the line of conversation.&lt;/p&gt;
&lt;p&gt;We have a few baseline characteristics, and keep transforming ourselves with every move. &quot;In Madrid, we were true Spanish, in London, we were true Londonders, but I don&#39;t know what we became in this suburb&quot;, she continues after my thought. The suburbians are poorly-traveled boring people with straight career-lines whose dominant interest is children. Designing children. Even the most conservative ones genetically engineer atleast the hair color and skin tone. &quot;Culturally poor, incredibly wealthy burbians, but without kids?&quot;, I offer, in summary. &quot;You remember when our lovely neighbors tried to come over during the first week and offer us their wonderful food?&quot;, she asks sarcastically. I raise my eyebrows and shut my eyes in feigned embarrassment. We had to throw away most of the food because it was so insipid.&lt;/p&gt;
&lt;p&gt;&quot;I&#39;ll let you pick dinner&quot;, I state with authority, playing the dominant role. &quot;Bœf bourguignon with cream of artichoke?&quot;, she offers coyly. As we move into the kitchen, the bot skirts past us — it&#39;s finished with the study, and is heading for the bookshelf in the living room now. We&#39;re always a little disappointed when we open the refrigerator. There is literally one weekend market within commuting distance of where we live, where we have to get our ingredients for the week. It&#39;s overpriced, and the stuff isn&#39;t great, and there&#39;s very little diversity. We can&#39;t stand the frozen stuff everyone else gets at these gigamarkets. London had a terrible food culture as well: everyone was getting takeout boxes from the local Indian restaurant. &quot;Don&#39;t fret. We&#39;ll soon be heading to the local butcherie, poissonnerie, and fruit/légume marché every other day, just like in Hong Kong&quot;, I say with a broad smile.&lt;/p&gt;
&lt;p&gt;As I cleave the beef, she expertly chops the carrots and peels the potatoes while sipping her wine. Many of these burbians get their ingredients shipped home, and have bots cook for them, an idea we find repulsive. &quot;Will you have something to read on the flight tomorrow?&quot;, I ask with the concern of a close girlfriend. We both read rapidly, but she&#39;s got to a different level during the course of this vacation; burns through two or three paperbacks a day. &quot;You&#39;re nearly done with Daisy Johnson&#39;s latest, yes?&quot;, I ask referring to the book she was reading when I entered. She nods, and we both rush to the living room, to pick a couple of novels set in Paris from the shelf before the bot gets to them. I love my paper books as well; vastly prefer them to reading off the screen or the link.&lt;/p&gt;
&lt;p&gt;As the prep phase of the cooking draws to an end, the induction top switches on. In Hong Kong, we used to have a traditional gas top, and often cooked in woks. &quot;We don&#39;t have to worry about earning for a while now&quot;, she remarks. It&#39;s true; with our savings and the generous UBI pay in the EU, why would anyone work for a living? &quot;The last time we had that luxury was in Madrid&quot;, I respond, with a tinge of bitterness. &quot;I&#39;ll probably write a novel&quot;, she says. She&#39;s only written short stories so far, and this stint has more than prepared her to write her first novel. &quot;And where is it going to be set?&quot;, I ask flatly, as the professor. &quot;Paris, of course. Modern era&quot;, she says with a beaming smile. &quot;themed in European film history&quot;, she continues. She&#39;d have to learn a few major European languages and cultures. &quot;You&#39;re going to be nosed up studying for quite a while then&quot;, I say, downplaying the excitement. She knows that I know that we&#39;re going to be traveling a lot, with purpose, and merely smiles at the unvoiced thought.&lt;/p&gt;
&lt;p&gt;The soup is ready, and we start sipping it in the dining room, while the beef simmers. &quot;I&#39;ll work on a project to formalize neuroscience&quot;, I say finally. The question has been lingering for some time now. &quot;Quite the challenge&quot;, she remarks, adjusting her glasses, playing the nerd. The bedrock of most software construction starts with an understanding of the brain. Most software construction and most neuroscience is stuck in the dark ages though. For the most part, Madeline only uses software that is correct by construction. She&#39;s disgusted by recommendation systems, and terrified that a software bug will breach her privacy or hurt her. Practically speaking, this restricts her choice to a subset of pre-neuro software. &quot;I should get my link removed&quot;, I say in sudden alarm. &quot;Yes, you should; the Parisians won&#39;t take well to it&quot;, she responds soberly.&lt;/p&gt;
&lt;p&gt;The bourguignon is delicious. Perfect dinner to end this stint. We retire to bed with our books, smoking a couple of cubans.&lt;/p&gt;</summary>
    <title>2043</title>
    <updated>2020-09-01T16:54:09+02:00</updated>
    <dc:date>2020-09-01T16:54:09+02:00</dc:date>
  </entry>
  <entry>
    <id>art/aging</id>
    <link href="art/aging"/>
    <summary>&lt;p&gt;I&#39;m eighty today, but the sequence of events I&#39;m going to narrate took place when I was in my early twenties. It was a pleasant Friday in San Francisco, and as many people will tell you, SanFran has the ideal weather. The mood at my workplace was jubilant. Added to the fact that the weekend was coming up, our CTO had announced that we would be going public the following Monday. Everyone was dressed in colorful tees and shorts, and we were all trying to estimate what our net worth would be after the IPO, based on the amount of vested shares each of us had. Needless to say, we were doing very well, and were expecting the IPO to make a big splash. Many of us were dating each other in the office; even our CTO was under thirty. As the afternoon wound down, all of us left early, and in high spirits.&lt;/p&gt;
&lt;p&gt;I mindlessly took a stroll along the pier with a co-worker, and we got ice-cream to celebrate. She left shortly after, citing that she wanted to spend time with her boyfriend. People had suspected that there was something off with me, but wrote it off as plain weirdness that I&#39;d eventually grow our of. I was careful not to get too close to anyone, for I knew, deep within myself, that I was pretending. I didn&#39;t belong here, among these people. If you ask a lay person what this meant, they&#39;d ask if the problem was racism, sexism, or some such social issue, but the problem with me was much deeper than that; I constantly felt like a 200 year-old person.&lt;/p&gt;
&lt;p&gt;As I continued my stroll back home alone, I entered a deep state of melancholy. Normal people could live their lives in pursuit of wealth, good-looking partners, and social status. I just didn&#39;t get the point. I might be in my early twenties today, but time will fold onto itself until I&#39;m forty, sixty, and eventually eighty. One way to put it, perhaps, would be to say that I couldn&#39;t live in the drama of the searing present. There&#39;d be an IPO, which might bump our net worth and social status. We might be able to afford a 3000 sq-ft home in SanFran as a result. Or our company might sink, and we might have to move to a less fashionable city, in order to buy a house. It was inconsequential to me either way: I just didn&#39;t see the point of thinking about it; what will happen will happen, whether or not we bite our nails over it.&lt;/p&gt;
&lt;p&gt;We&#39;re born one day, and we die approximately eighty years later. Society is not structured to accommodate people well beyond their age. That was the truth of what I was doing at a young startup in SanFran: the first-hand life experience, not because I expected to enjoy it, but because it would be an interesting observation to fill the 23rd year of my life. 23, because it was a socially-acceptable age for this.&lt;/p&gt;
&lt;p&gt;I felt every groove on my key as I inserted it into my door. I&#39;d already planned my departure, in complete secret. I took off my shoes, and started up my surround-sound system to play soft Icelandic music. Having curled up on the couch comfortably with some good whiskey, I lit up a Cuban cigar. All the creature comforts were attended to; we were all well-paid, and nobody had suspected who I really was. My bookshelf was overflowing with Pulitzer/Booker-prize finalists, and many other rare gems. My e-ink tablet had serious works on mathematics, philosophy, neuroscience, and physics. Normal people usually have some self-help books disguised as psychology, and other baloney disguised as non-fiction. Any serious text would only be read in the context of their jobs.&lt;/p&gt;
&lt;p&gt;I started thinking about Reykjavik. My flight was in three hours, and the packing was done; I was departing permanently. I&#39;d spend a good six months relaxing in Iceland, and plan my next steps. I&#39;d sell my stock after the IPO remotely, and give in my resignation (again, via phone) shortly after. The end of my one-year lease on the house was approaching shortly — I&#39;d already asked my landlord to cancel the renewal of my lease, and had arranged for my stuff to be stored in a warehouse via a moving company. I&#39;d packed ten novels to read over the course of six months. I was leaving most unceremoniously.&lt;/p&gt;
&lt;p&gt;Was I feeling happy or relieved? Not really. I&#39;d still have to pack the years of my life with stuff to do, until I felt like I&#39;d found home and wanted to put down roots. I wouldn&#39;t want to be a pretending-nomad forever, and perhaps I&#39;ll always be a misfit, but I was sure there&#39;d be a place I&#39;d be able to call home. Time was abundant.&lt;/p&gt;
&lt;p&gt;The re-telling of something that happened over fifty years ago brings me great joy. I&#39;m near the end of my life today, and I can whole-heartedly say, that I have lived a full life. The deep sense of melancholy that I had at the age of 23 only deepened with age, but I learnt to live with it. I live in a place where people understand and love me, and for that, I feel very fortunate.&lt;/p&gt;</summary>
    <title>Aging</title>
    <updated>2022-04-16T12:43:00+02:00</updated>
    <dc:date>2022-04-16T12:43:00+02:00</dc:date>
  </entry>
  <entry>
    <id>art/ai-war</id>
    <link href="art/ai-war"/>
    <summary>&lt;p&gt;There are innumerable reasons to hate AI, starting with its environmental impact: the AI boom has been estimated to consume as much power as New York City, and as much water as the global consumption of bottled water in 2025. The reasons could also be personal, from leading to a loss of livelihood, to threatening the way we pursue our passions. The distaste is fueled by visible misuse, including the flood of low-quality AI-generated bug reports and PRs on open-source projects, music and books uploaded to Spotify and Amazon, papers at academic venues, and the &lt;a href=&quot;https://youtu.be/E-YwjXEVGo8?si=RcEymmyF_qWB13ks&quot;&gt;recent horrifying McDonalds ad&lt;/a&gt;. To make things worse, there is plenty of &lt;a href=&quot;https://dmitrybrant.com/2025/09/07/using-claude-code-to-modernize-a-25-year-old-kernel-driver&quot;&gt;anecdotal evidence&lt;/a&gt; to suggest that AI makes an individual more productive, while there are plenty of &lt;a href=&quot;https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/&quot;&gt;studies&lt;/a&gt; that suggest the opposite. At the same time, there is no denying that the technology is &lt;em&gt;very&lt;/em&gt; widespread across the industry, well beyond just the software industry. For many of us, personal distaste and ethical issues has lead to a AI-denialism stance, where we &lt;a href=&quot;https://mikelovesrobots.substack.com/p/wheres-the-shovelware-why-ai-coding&quot;&gt;declare that AI doesn&#39;t work for anyone&lt;/a&gt;, and espouse &lt;a href=&quot;https://pluralistic.net/2025/12/05/pop-that-bubble/&quot;&gt;borderline conspiracy theories&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The primary feature of AI to pay attention to is that it&#39;s a fuzzy non-deterministic system, and measuring productivity gains from AI at an individual level is a bit like studying witchcraft. Today, AI adoption across the industry — be it software, finance, digital humanities, law, journalism, or otherwise — is so widespread, that dismissing it as just &quot;hype&quot; or &quot;herd mentality&quot; is not a cogent position any longer. To a first approximation, corporations are rational capitalist actors looking to maximize their profits, and they are paying good money for AI products for a reason. I only see one conclusion by Occam&#39;s razor: that, for many orgs, implementing AI org-wide is a net-positive, although the results vary at an individual-level. Many orgs have run internal productivity metrics and found a 20-30% increase — and the proof is that they continue paying for AI products, even in the light of studies that suggest that AI makes individuals less productive. This would lead us to look for publicly observable metrics to correlate the fact that there&#39;s an increase in productivity across the board: for example, we might expect to see quicker software release cycles, an uptick in feature rollout or bug-fixes in products, or in open-source code. Perhaps not the not the most satisfying answer, but orgs are not increasing their production volume with AI adoption, and are instead raking in profits by lowering their costs — and the publicly observable metrics are the layoffs, hiring slump, unemployment, and under-employment in advanced economies. The other problem is that the technology is a poor fit for open-source projects, and I will expand on this next. As an economist put quite poignantly, the current situation is akin to a &lt;em&gt;war-time economy&lt;/em&gt;, where the defense companies are raking in profits with huge environmental costs (or the AI adopters today), while everyone else is left to survive on rations.&lt;/p&gt;
&lt;p&gt;Open source communities work because the community members are deeply passionate about the project, and treat their work like a hobby — they take pride in their work, and there is nothing to sell. All open source projects must attract and retain new contributors every year to survive. Maintainers often do a lot of work helping new contributors, and the payoff is only seen when a new contributor continues gaining experience, and eventually grows into a maintainer themselves. This key social aspect of an open source project is the reason why AI adoption will be minimal at best: the cost of maintaining LLM-generated code outweighs the marginal benefit of adding a new feature — and since it was low-effort for the new contributor, they are less likely to stay on and learn. The cost-benefit computation is different for a corporation selling a product — revenue is directly correlated to feature rollout. The idea of corporations profiting off open source is nothing new — and in this age, all they have to do is train their LLM on our hand-crafted &quot;artisanal&quot; code.&lt;/p&gt;
&lt;p&gt;The economics of AI &lt;a href=&quot;https://www.wheresyoured.at/the-case-against-generative-ai/&quot;&gt;doesn&#39;t add up at all&lt;/a&gt;, and the technology cannot even be sold at cost — there is no denying that we live in a bubble similar to the sub-prime mortgage bubble. After the crash, a lot of everyday people will lose a significant portion of their savings for no fault of theirs, and what will probably be left are cheap compressed versions of what we have today, running on commodity hardware.&lt;/p&gt;
&lt;p&gt;We have been very irresponsible in going down this AI path — and we&#39;re doing irreversible damage to the planet while at it. I hate AI for the reasons outlined, and it is useless to me, as a member of the LLVM community. However, I cannot deny that the technology is widely useful and has increased the productivity of many orgs.&lt;/p&gt;
&lt;p&gt;That said, there are also many corporations that have adopted AI with no material benefit.
Perhaps the long-term effect on corporations that have adopted AI will be the accumulation of technical debt, leading to shorter-lived corporations.&lt;/p&gt;</summary>
    <title>AI and the war-time economy</title>
    <updated>2025-12-20T13:18:05+00:00</updated>
    <dc:date>2025-12-20T13:18:05+00:00</dc:date>
  </entry>
  <entry>
    <id>art/banter</id>
    <link href="art/banter"/>
    <summary>&lt;p&gt;My heart started racing the moment I saw her. She was standing right there by the coffee machine. The first thing I noticed about her was her hair. Curly hair, that was neatly combed back, with a couple of ornamental clips, pinned haphazardly. Neatly trimmed in line at the neck. She was short, had soft glowing skin, and was speaking very softly, in Russian, with another Russian girl who worked there, that I was acquainted with. She had beautiful legs, dressed in tight jeans, and she was wearing a beautiful red top that day. Exceptionally well-groomed and fit. This was a woman who took great care of herself. In short, stunningly beautiful. I walked rapidly up to the coffee machine, not because I was in a hurry to meet her, but because I always walked rapidly.&lt;/p&gt;
&lt;p&gt;&quot;Is the coffee machine broken again?&quot;, I asked. &quot;Oh, it just needs some love and taking care of, like a cat.&quot; &quot;Purr, Purr&quot;, she whispered, as she stroked the coffee machine. I started laughing immediately, and without inhibition. I&#39;m a tall well-built French man, and I was dressed in a plain black North Face tee and cargos. Since my friend had introduced me to it, I always wore jet black Adidas boots, and that always helped making a big entrance.&lt;/p&gt;
&lt;p&gt;She was smiling gently at me. Terribly shy, I could tell. &quot;See, it&#39;s fixed now?&quot;, she said, pointing to her full cup of black coffee. &quot;Do you work here?&quot;, I asked gently. &quot;Yes, I&#39;m Irena&quot;, she responded, gently turning away in shyness. I recalled that there was an office on our floor with the name Irena that was unoccupied. People didn&#39;t talk about her much at work, but I knew that she&#39;d been on vacation. &quot;I&#39;m Etienne. It&#39;s nice to finally meet you.&quot; &quot;So, you&#39;re back from vacation?&quot;, I said trying to hide the eagerness in my voice. &quot;Yeah, you know vacations are like that&quot;, she said, feigning boredom. She then collected her coffee, and returned to her office with Katina, the other Russian girl she was with. It was post-lunch, and we, as the French, have long lunch breaks. Irena was in the same team as me, and we&#39;d be meeting each other multiple times over the coming months, over multiple lunches and coffee breaks. I was mostly just looking forward to the next day.&lt;/p&gt;
&lt;p&gt;There was a talk at IRIF that day, that one of my team members was delivering. I spotted Irena sitting in the front row, feeling uncomfortable because Katina wasn&#39;t by her side. Then, as Katina entered the room, Irena waved and tried to get her attention. It was then that she noticed me sitting in the rear, and staring at this amusing ordeal. I merely smiled, but she immediately turned away, embarrassed, and stop waving.&lt;/p&gt;
&lt;p&gt;The very next day, I noticed thumping footsteps outside my office, and realized that both Irena and Katina had taken to wearing boots.&lt;/p&gt;
&lt;p&gt;Over the next couple of months, our relationship into light casual banter over coffee and lunch. Then, one day, Irena decided to sit next to me at lunch, with Katina by her side. We had a joyful conversation on Master and Margarita. At this point, she decided to sit next to me everyday over all the lunch sessions over the coming months, but for the occasions on which she was cross with me. We were definitely more fond of each other than with the others on the team.&lt;/p&gt;
&lt;p&gt;It was my morning routine. Waking up at 5a, and arriving in the office before everyone else, occupying the lounge, and studying mathematics on my tablet. I would wait for Irena to arrive at around 8a, and get my fourth or fifth morning coffee with her, with nobody else watching, and not even Katina by her side. After that, I&#39;d walk to the nearby bakery and get a croissant aux amande, my usual breakfast. On that particular day, I was feeling particularly hungry, and Irena was probably running a little late. I decided to get the croissant myself, and hoped to catch Irena afterward. As I took the stairs to the ground floor, we noticed each other. She had just entered the elevator, and I was walking past it. At this point, she lowered her glasses, and looked at me, definitely feeling a little cross for not having waited for her.&lt;/p&gt;
&lt;p&gt;I missed work on three consecutive days, because I had a bout of food poisoning. The next day, when I turned up at work, Irena turned up to get her her coffee, with ruffled hair. She looked distressed, and it seemed to be because she had been missing me. &quot;Where have you been?&quot;, she opened with. &quot;Oh, you know. Food poisoning.&quot; &quot;Sorry I missed Katina&#39;s birthday.&quot; &quot;Oh, it&#39;s alright, I&#39;m glad you&#39;re fine.&quot;, she responded. After the usual morning coffee, and somewhat subdued banter, she returned to her office. Moments later, it occurred to me that I could have brought up her hair, so I quietly tiptoed to her office, and peered in. She seemed to have combed her hair at this point, and was no longer looking distressed.&lt;/p&gt;
&lt;p&gt;I grew really fond of Irena over the next few months. After carefully evaluating I ought to proceed, I decided to gift her a book. Since I knew her taste in reading at this point, I inked a freshly purchased copy of Vulcan&#39;s Hammer with my beautiful cursive handwriting in blue fountain-pen ink. A slightly personal &quot;To Irena, the Fencing-Salsa-Japanese girl, from Etienne&quot; is what I inked, recalling her three primary hobbies.&lt;/p&gt;
&lt;p&gt;I wore my favorite shirt to work that day, with excitement. When she arrived for her morning coffee, I opened with &quot;I have a gift for you&quot;, and presented her the book. She panicked, and in an attempt to downplay it, she asked me to wait for just a second, rushed to her office, found a copy of an old Systems Engineering textbook, presented it to me and said &quot;So, it&#39;s a book exchange&quot;, with a serious expression. I smiled politely, disappointed.&lt;/p&gt;</summary>
    <title>Banter</title>
    <updated>2021-09-05T14:16:39+02:00</updated>
    <dc:date>2021-09-05T14:16:39+02:00</dc:date>
  </entry>
  <entry>
    <id>art/bhutan</id>
    <link href="art/bhutan"/>
    <summary>&lt;p&gt;I woke up feeling like I had a brand new body and mind. We were asleep in a little cabin in the middle of nowhere, in a little village in Bhutan. We&#39;d arrived the previous day, by air, and ridden on top of a bus while jet-lagged to get to find this cabin. We&#39;d all arrived from different countries: Sven from Svalbard, Aamod from Brooklyn, and I&#39;d made it from Montpellier. To add to the chaos of our flights arriving at different times, we had no mobile connectivity in the Thimphu airport, and it took the better part of the previous day to find each other roaming around randomly in various tea shops. There was no plan, we hadn&#39;t booked anything in advance, and none of us knew Dzongkha. Yet, somehow, with Aamod&#39;s broken Hindi-Urdu, we decided to take a random bus going to an unknown destination, only to find that the bus was full. That&#39;s the story of how we ended up on top of the bus. Alright, there was one crucial preparatory step I&#39;m skipping here: we&#39;d gone to our respective banks and exchanged our currencies for Indian rupees, since no bank had heard of Ngultrum; we&#39;d read online that Indian rupees would work in Bhutan. With a limited supply of these Indian rupees in hand, we would manage our expenses over our week-long vacation. When we got off the bus, we found ourselves literally in the middle of nowhere, and trekked a bit until we found a house with a family staying in it. They were very welcoming to us, served us tea, and put us up in their cabin for a small sum.&lt;/p&gt;
&lt;img src=&quot;/art/bhutan/cabin.jpeg&quot; /&gt;
&lt;p&gt;Aamod was already awake, and gently strumming his ukulele, while Sven was slowly waking up. &quot;Bonjour, Hugo&quot;, he sang with a broad smile. &quot;Bonjour!&quot;, I responded, cheerfully. Sven had started stirring now, and was nearly awake. We were three very unlikely friends, with very different personalities and vocations. Sven was a jazz musician, Aamod was a student in linguistics and sociology, and I was a mathematician. As an upcoming musician in Svalbard, Sven was the person who was most in touch with nature, and the least in touch with people. Aamod, on the other hand, was a very sociable person, and we were relying on him to handle most of the logistical challenges of this trip. I was a soft-spoken mathematician who had an adventurous streak, but had no creative talent to speak of. Aamod and I had met in San Fransisco, quite randomly at a pizzeria at 4am. We were immediately drawn toward each other, and spent the following day roaming the streets and smoking weed. We&#39;d decided to go to Rejavik the following summer, without a plan, and found Sven playing jazz at a bar there. We loved Sven&#39;s music, and spent the better part of that week with him, skinny-dipping in the ice-cold waters, and enjoying the sounds of nature. To be honest, we didn&#39;t know each other very well, but both Sven and I were immediately enthusiastic when Aamod proposed that we go backpacking in Bhutan. Many years down the line, we would become close friends, and we&#39;d realize that this week spent together in Bhutan would establish a very strong bond between us.&lt;/p&gt;
&lt;p&gt;&quot;Hej, Sven!&quot;, I chimed, as Sven sat up in his bed, with a start. &quot;Morning, both. I need some tea&quot;, he responded. Aamod stopped strumming, and started scratching his unruly beard. Sven was a heavy coffee drinker, and he was slowly getting accustomed to the fact that only tea would be available in Bhutan. &quot;Get dressed, then. We&#39;ll head over to the house — they&#39;ll be happy to see us up so early&quot;, I said. Indeed, my watch read 6:30a, and we hadn&#39;t gone to sleep until 10 the previous day; yet, we all felt like we&#39;d been asleep for a week. We all suited up for the cold, and went knocking on our host&#39;s door. The kind old woman who greeted us the previous day appeared at the door and was noticeably surprised. We all smiled and bowed — no words were exchanged. She led us into the large dining area and seated us on the floor. She then automatically proceeded to serve us a milky tea mixed with butter and salt. Sven preferred the milky tea with sugar, and Aamod and I smiled in amusement as he sipped his tea with some discomfort. &quot;You&#39;ll get used to it — it&#39;s a good drink for the cold weather&quot;, said Aamod, gently patting him on his shoulder. When we&#39;d all finished the tea, Sven managed to utter something that sounded like &quot;Dhanyavaad&quot; to the woman, emulating the sound Aamod was constantly making the previous day, to convey his gratitude; this was a warm surprise. The woman smiled generously, and disappeared into the kitchen again to fetch breakfast. When the plates were placed before us, we recognized the food as some sort of barbecued meat along with some boiled and salted peas, with the skin still on. After taking a bite, Aamod and I couldn&#39;t recognize the meat; Sven noticed our confusion, and said &quot;Oh, it&#39;s really tough sheep meat&quot;.&lt;/p&gt;
&lt;p&gt;We were eager to get to a nearby village, where we could meet some people, so we caught another random bus from the same spot as which we&#39;d gotten off the previous day. Thankfully, we were riding inside the bus this time, and we kept a lookout for small towns. Once we reached a small town, we got off, and roamed around a bit observing the people and the the unpaved streets. People seemed to be observing us with curiosity, and some of them walked up to us, and asked us where we were from. Aamod is mixed-race Indian-American, Sven is Nordic, and I&#39;m German-French. Sven looks especially curious with his prominent tattoos, facial piercings, long hair, and long well-maintained beard. I have a typical mathematician&#39;s beard, and Aamod has an especially unruly one. Neither of us have any visible tattoos or piercings. We were all wearing some kind of jacket, which in itself was enough to make us stand out: everyone there was dressed in some kind of indigenous woolen top garment. There were very few automobiles, and even those were motorcycles. The town wasn&#39;t electrified of course, although we did spot some diesel generators at the shops.&lt;/p&gt;
&lt;img src=&quot;/art/bhutan/ppl-town.jpeg&quot; /&gt;
&lt;p&gt;I&#39;d brought along a dSLR camera, with which I was awkwardly taking pictures. We decided to make camp in a tea shop, whence Aamod and Sven decided to take turns playing the ukulele. Little by little, people from the town started gathering around us, out of curiosity. At one point, Aamod and Sven began singing, in what would be a long performance for the town. Soon, most of the town was at the tea shop, and everyone was brimming with joy.&lt;/p&gt;
&lt;img src=&quot;/art/bhutan/uke.jpeg&quot; /&gt;
&lt;p&gt;On the next day, we headed to a garment shop, and spent the entire morning curiously looking at the various kinds of garments. I picked a shawl with bright colors on it, while Sven picked something tasteful and expensive, and Aamod settled on a long gray flowing top garment. The reason Sven and I didn&#39;t pick anything other than shawls is because the garments were somewhat ill-fitting: as Europeans, we were tall and well-built with broad shoulders; Aamod didn&#39;t seem to mind the ill-fitting purchase as much though. We did away with our jackets, and got dressed up, excited to see how we&#39;d be perceived now.&lt;/p&gt;
&lt;img src=&quot;/art/bhutan/shawls.jpeg&quot; /&gt;
&lt;p&gt;As a light late-afternoon snack, we tried some curious yellow rice-based dish, and all three of us were feeling unreasonably sleepy after that. We&#39;d later discover that it was a poppy-based dish, and is meant to be had in the afternoon before a siesta. At this point, we&#39;d found a lake and taken a boat, but none of us was in any condition to swim the cold waters, so we decided to relax for some time in the middle of the lake, and go for a swim another day.&lt;/p&gt;
&lt;p&gt;Initially, I was slightly uncomfortable about the fact that we hadn&#39;t talked much — I&#39;d come to realize that we never would say more than a few words to each other on this trip; there was an unspoken agreement between us that we&#39;d leave our lives behind on this vacation.&lt;/p&gt;
&lt;p&gt;On the fourth day, we discovered that people here smoked opium for leisure, and both Aamod and I were shocked at the prospect of smoking opium. Sven laughed generously, and convinced us to try it. The host had brought us something called a &quot;chillum&quot;, a sort of long pipe made of stone, with a piece of cork holding the substance the person wants to smoke in place. Then, he took out his handkerchief, and used it as a filter. A very crude setup overall, but it suffices to say that we had a very relaxing evening on the porch of his house. I enjoyed myself so much, in fact, that I&#39;d buy a chillum and take it back with me, as a reminder of that evening.&lt;/p&gt;
&lt;p&gt;We decided to spend the last couple of days of our vacation in Thimphu. We&#39;d made a friend, who spoke English. He told us that he was an ex-con, who&#39;d escaped from prison, under the false pretext of insanity. We all laughed together over his wild stories.&lt;/p&gt;
&lt;img src=&quot;/art/bhutan/excon.jpeg&quot; /&gt;
&lt;p&gt;When it was time to take our flights back home, we promised each other that we&#39;d plan a longer vacation the next time around. The airport security personnel freaked out a bit when she saw my chillum, mistaking it for some kind of pipe bomb. I calmed her down, and explained to her what the thing she was holding in her hand was.&lt;/p&gt;</summary>
    <title>Bhutan</title>
    <updated>2022-01-06T17:02:32+01:00</updated>
    <dc:date>2022-01-06T17:02:32+01:00</dc:date>
  </entry>
  <entry>
    <id>art/insomniac</id>
    <link href="art/insomniac"/>
    <summary>&lt;p&gt;I couldn&#39;t sleep that night. Tired and frustrated, I got out of bed, took a shower, and dressed for the snowy streets of Boston. Thermals, t-shirt, jeans, and a quirky jacket I&#39;d picked up at the thrift store, that I was quite fond of. I started making plans in my head. I&#39;d take the 5:30am train to Natick after finishing breakfast with a Bloody Mary. There was a diner close to my place that was open through the night. The feeling of frustration was fading, and was quickly being overtaken by a feeling of excitement. I was used to this: I often slept poorly, and had the habit of turning up at work at ungodly hours.&lt;/p&gt;
&lt;p&gt;As I opened the front door of my building, a gush of cold air blew in. It was 2a, and the streets were empty, covered in a few inches of snow. Perfect timing. I&#39;d probably run into the most random and interesting people. Picking out my first smoke from the pack, I noticed the first human being ambling about. There was no rush to get to the 24-hour diner.&lt;/p&gt;
&lt;p&gt;He looked a bit shabby, but was dressed comfortably for the winter. In his mid-40s, I&#39;d say. Definitely not homeless. A little tipsy, he was drinking a Lagunitas, and was carrying a few more with him. &quot;Hey there, you wanna trade some smokes for a beer, mate?&quot;, I said as I approached. &quot;Sure, man. What&#39;re you doing up so late?&quot;, he said, handing me a beer. &quot;I don&#39;t get much sleep anyway. Might as well roam about, am I right?&quot;, I said with a smile, as I handed over three Lucky Strikes. &quot;Bloody hell man. My wife kicked me out, and I&#39;m taking the 7a train to Washington.&quot; I suspected as much. &quot;Tough luck, mate. No luggage, eh?&quot;, I said, with a little sympathy. &quot;No, man. Didn&#39;t have enough time to pack. Gonna visit my sis.&quot; &quot;I&#39;m heading to South Street to get breakfast. Cherios.&quot;, I said, ending the conversation with a wave.&lt;/p&gt;
&lt;p&gt;I was already feeling the rush of being out in the cold on no sleep. I&#39;d make the most of my walk to the diner, I thought to myself, as I plugged into my earphones. Bowie, I figured, as I shuffled through my Spotify. It would be a long and satisfying walk, I thought to myself, as I took another swing of the Lagunitas. I&#39;d have some time to think about breakfast, and the new compiler transform I was developing at work. I spotted few other people, who didn&#39;t seem to be interested in picking up conversation. There were few homeless people in this part of the world, as the winters were so inhospitable.&lt;/p&gt;
&lt;p&gt;As I approached the diner, I unplugged my earphones, and noticed a bunch of people outside smoking and chatting. I loved South Street, especially at odd hours, because it had such weird mix of people: people working night-shifts, strippers, the unemployed, and people who had trouble sleeping. I took a seat at the bar next to a goth girl, and started scanning the menu for items I&#39;d not tried in the past. The diner was cheap, and the food was decent. And, as was the case with all diners, bottomless coffee. It was always lively, but never noisy. This was probably the only 24-hour diner in Boston, and I lived close to it. I felt so lucky.&lt;/p&gt;
&lt;p&gt;Within thirty seconds of taking a seat at the bar, the waiter had filled my mug with fresh coffee. &quot;What&#39;ll ya have?&quot;, she said, in a completely no-nonsense manner. &quot;I&#39;ll have the scrambled eggs and bacon, with a side of sausage. And a Bloody Mary to finish off.&quot; I&#39;d ordered the usual, realizing that I&#39;d tried everything on the menu already. She made a quick note, and concluded with a &quot;Comin&#39; right up.&quot; Although I visited this place a lot, I wasn&#39;t acquainted with the waiters. They had a lot of customers, and were constantly working. There was nothing special about me. &quot;Come here often?&quot;, I quipped, turning to the goth girl. She had tattoos all over, and was dressed in black overalls. &quot;Yeah, it&#39;s my jam.&quot;, she said, turning away. She didn&#39;t seem to be interested in any further conversation, so I dropped it.&lt;/p&gt;
&lt;p&gt;The bacon was tasty, as were the sausages. The servings were all generous, and I was content with my heavy breakfast. The Bloody Mary had just the right amount of salt and celery, and I took my time to finish. I paid by card, and left without saying another word. I was probably the most square person at South Street, if you were to judge by appearances: I didn&#39;t have a single tattoo or piercing, and was employed in a well-paid software company. Every now and then, I&#39;d pick up a short conversation with someone there, but in general, I had little in common with the people there. Yet, I enjoyed their presence.&lt;/p&gt;
&lt;p&gt;I was really enjoying the mix of the Mary and nicotine, as I noticed the first rays of light from dawn streaming into the streets. As I approached the train station, I noticed an aging woman from the distance. My watch read 5a, and I&#39;d packed a book to read on the station and train, but she seemed to be a little distressed. As she approached me, I realized that the winter air must be a little harsh on her. &quot;Excuse me, but when is the next train?&quot;, she asked, politely. I told her that the first Purple line train wouldn&#39;t be for another thirty minutes. &quot;Aren&#39;t you feeling cold?&quot;, I asked her, with concern. &quot;A little&quot;, she admitted. She must have been downplaying it to be polite. At this point, I showed her how to enter the station and take a seat in a sheltered area. I then proceeded to offer her my coat, to which she shook her head and said, &quot;It&#39;s very kind of you, young man, but I don&#39;t want you freezing.&quot; &quot;I thought the first train was at 5, but why are you here so early?&quot;, she asked, after a brief pause. I explained that I often didn&#39;t get sleep, and this was routine for me. We then proceeded to make pleasant conversation about family, friends, and life in Massachusetts.&lt;/p&gt;
&lt;p&gt;At forty past five, we started seeing other passengers. Nearly all of them were going to work. Time passed quickly, and I was soon on the train. After a quick visit to the washroom, I took a seat beside the woman, and started reading Infinite Jest. It was superbly written, and would take me weeks to finish.&lt;/p&gt;
&lt;p&gt;I got off at Natick at forty past six, and bid the woman goodbye. I smiled to myself for another satisfying morning, as I walked towards the office.&lt;/p&gt;</summary>
    <title>The Insomniac</title>
    <updated>2021-09-05T09:31:15+02:00</updated>
    <dc:date>2021-09-05T09:31:15+02:00</dc:date>
  </entry>
  <entry>
    <id>art/ml</id>
    <link href="art/ml"/>
    <summary>&lt;p&gt;We investigate the limitations of statistical methods, a subclass of which is called &quot;machine learning&quot;, taking the opportunity to touch on several aspects of the industry, including the future of employment, various industry practices, and privacy. It&#39;s written as a wide-audience article, and only assumes a passing familiarity with software and statistics. We start from a seemingly hardline stance, and follow a line of flawed reasoning leading up to the point where humans become near-obsolete, an event commonly known as the &quot;singularity&quot;. Finally, we step back to see where we stumbled.&lt;/p&gt;
&lt;p&gt;We use the following starting point: using any combination of statistical methods, of any complexity, it is impossible to develop any sort of &quot;understanding&quot; that resembles human intelligence. Instead of trying to tackle questions about the nature of intelligence, or entering a deep philosophical rabbit-hole about whether &quot;intelligence is computable&quot;, we start with the modest goal of understanding what statistical methods are.&lt;/p&gt;
&lt;p&gt;As a starting point, one might argue that the world is made of up of a collection of &quot;facts&quot; that need to be &quot;memorized&quot; after having seen them stated multiple times correctly. A variation of this is the &quot;monkey brain&quot;, in which you train the monkey by asking it to perform a certain task, rewarding it every time it gets it right, and penalizing it every time it gets it wrong. This is the basic idea behind &quot;reinforcement learning&quot;, the kind used to get machines to play &quot;games&quot;. Speed up the task-to-[reward or penalty] cycle exponentially, and you have a &quot;smart monkey&quot;. While the &quot;smart monkey&quot; might make silly mistakes on a bad day for irrational reasons, a &quot;bad day&quot; for a statistical model is the event when it is presented with data that it doesn&#39;t know how to fit. The monkey&#39;s emotional engine can arguably be emulated by weighting the penalty that the machine receives, based on how fundamental the mistake was, and how many hours of training it had received. The procedure we&#39;ve described of &quot;training&quot; a machine like this falls under the class of &quot;supervised learning&quot;, which, as one might argue, is the same way a human learns from an assignment or exam.&lt;/p&gt;
&lt;p&gt;Let us assume that a machine can successfully memorize trillions of &quot;facts&quot;, and look into how these might be represented. In most commonly-used applications today, they are encoded in the form of matrices of floating-point numbers, with some weighted arithmetic operations connecting them, as chosen by the person building the model. The model is fed a matrix of floating-point numbers, and outputs a matrix of floating-point numbers. We might argue that the inability to interpret these individual numbers is akin to not being able to interpret the voltages of the individual neurons in the brain, and this doesn&#39;t seem to be a problem in practice. The said &quot;facts&quot;, now lost in a soup of numbers, can be generalized into a broader class of &quot;things that can be inferred from data&quot;. With every attempt at being able to handle a new situation, the model simply does arithmetic on the soup (a large class of which are just matrix multiplications), and the numbers in the soup adjust themselves with every &quot;feedback&quot; we give it. This is the basic idea behind &quot;neural networks&quot;. While it&#39;s easy to get lost in the details, note that we&#39;re still doing statistical analysis. The additional &quot;frills&quot; haven&#39;t changed the essential nature of the method: the machine is &quot;learning by example&quot;, and attempting to &quot;generalize&quot; it.&lt;/p&gt;
&lt;p&gt;Among human beings, learning by example is a very effective way to learn, when starting out. Most programmers would attest to the fact that they started out by copying examples, tweaking them, and checking them with a program (these programs are known as &quot;compilers&quot;). Some would argue that this approach doesn&#39;t scale in human beings, because they don&#39;t have the computational power to continue learning by example, and &quot;cheat&quot; by reading some kind of specification as they become more experienced. Does it mean that classical programmers (aka. those not engaged in building statistical models) could be replaced by machines in the future?&lt;/p&gt;
&lt;p&gt;The key to seeing the viability of this argument is to consider two things: (1) the structural complexity of the task, and (2) the number of examples available to concretely reinforce the patterns, and nullify the anti-patterns. It&#39;s no secret that there are several good tools for aiding with &quot;simple&quot; programming languages (otherwise called IDEs), which a reductionist would phrase as &quot;machines are good at dumb tasks&quot;. Using simple frequency analysis, the IDE can order its auto-complete suggestions and corrections intelligently. To date, there is no IDE that can assist with the help of the vast repositories of open-source code, but it doesn&#39;t require a big leap in imagination to assume that this will be possible in the future. In fact, we should be open to the possibility that compilers start building repositories of error-messages, and run in the background, suggesting even more intelligent fixes, based on how others who encountered a similar error fixed it. A philosophically-minded reader would be interested in whether the &quot;intent&quot; of the programmer can be dissected, and if, by labelling various segments of publicly available code with some kind of abstract &quot;function&quot;, the machine can write entire programs with a few prompts. Assuming for a minute that this might be possible, can classical programmers stay relevant by simply moving to newer languages or technologies, on which there are few examples?&lt;/p&gt;
&lt;p&gt;This poses a quandary: are we playing some kind of primal game, where the prey constantly has to come up with new strategies to outrun the predator? Some would argue that by refining our statistical methods, one can emulate the process of generalization effectively enough to beat the prey&#39;s creativity on the &quot;search space&quot; completely. What if this is the nature of every human specialization? An event, commonly referred to as the &quot;singularity&quot;, whereby humans become near-obsolete, is predicted in 2040. Why is this claim so ludicrous?&lt;/p&gt;
&lt;p&gt;To better understand where statistical models are successful, let us enumerate some recent accomplishments in the field.&lt;/p&gt;
&lt;p&gt;Beating the best human player at Go, a program referred to as AlphaGo. The problem is well-defined, and there are very few starting rules. How does a human become good at Go? Just like in Chess, the rules play an insignificant role in the player&#39;s learning, and most of the training is about analyzing previous games. There are huge databases of expertly-played games available, and human players usually try to follow a semi-systematic approach. It could be argued that the machine is inefficient, because it doesn&#39;t follow a systematic approach, but the raw computational power makes this handicap look irrelevant. It&#39;s a little like arguing that a machine doesn&#39;t know the decimal system, or the tables of multiplication, and simply flips 0s and 1s to perform arithmetic. Humans here are the disadvantaged class in both cases, and it is completely unsurprising that, despite certain &quot;inefficiencies&quot;, AlphaGo essentially does what a human player does to beat them at it: analyzing lots of games.&lt;/p&gt;
&lt;p&gt;A language engine, referred to as GPT-3. How do humans master a natural language? They do it semi-systematically, starting from the association of simple words to real-world objects, then moving on to phrases describing something, learning some construction rules and absorbing culture along the way; and finally by reading a lot of good literature. Of course, the grammar rules play a very small part of the overall learning, so it is unsurprising that GPT-3 is able to produce grammatically correct responses to human-supplied prompts. However, literature talks about things in the real world, and for it to make sense, sufficient interaction with the real world is a prerequisite. It&#39;s not a bounded game, where all the necessary information is contained on a map or a board. It is, therefore, entirely unsurprising that GPT-3 can&#39;t &quot;know&quot; whether dropping a metallic plate would cause it to melt. It cannot infer the relationship between real-world objects, nor can it differentiate between factual and fictional human experiences. Producing good literature requires a whole lot more than that. This landmark achievement, despite having access to terabytes of text, and an unimaginable amounts of compute power, has failed to infer much more than grammar, sentence construction, and context.&lt;/p&gt;
&lt;p&gt;The translation engine behind Google Translate. Someone who has just started using the product with no knowledge of the underlying technology would be puzzled about why this is chalked up as an achievement. Indeed, it&#39;s unlikely that we&#39;ll even have a half-decent translation engine using purely statistical methods. Translation engines have been around for a long time, and their latest iteration might be a significant improvement over the previous ones, but on an absolute scale, something seems to be off about relying on a pure statistical method to learn natural language.&lt;/p&gt;
&lt;p&gt;Medical diagnostics. In this field, it is absolutely imperative to organize every little piece of data about every patient in a highly systematic manner: a missing entry is a life-or-death situation. On millions of these remarkably well-organized records, it should come as no surprise that a machine can serve as a valuable aid to a doctor. Statistical models have been a resounding success in this area. The achievement here, perhaps, should be attributed to the subfield of &quot;computer vision&quot;, which studies the best way to encode medical images and videos in the aforementioned number soup.&lt;/p&gt;
&lt;p&gt;Proof-search on a well-defined problem phrased in a computer language, using well-defined operations to go from one step of the mathematical proof to the next (in other words, aiding proof-search in programs known as &quot;proof assistants&quot;). These are classic combinatorial problems, with huge search spaces, lots of rules at each node, and clear end goals. Sort of like a video game on steroids. Some progress has been made, and the IDEs are expected to get better. At first glance, this might seem a bit alarming to those who don&#39;t understand how little mathematics can be written down in this form, or how painful it is to do so.&lt;/p&gt;
&lt;p&gt;Finding protein-folding structures, referred to as AlphaFold. Another classic combinatorial problem, with well-defined rules. The landmark achievement here is that this problem has an enormous search space, and a solution to an important problem in computational biology has been found, which is sure to accelerate research in the area. Statistical models are an unabashed success here, and it has done what humans could only dream of doing using other methods.&lt;/p&gt;
&lt;p&gt;Facial recognition. A classic pattern-recognition problem, which can only be learnt by example. It suffices to say that this technology is a resounding success, with the unfortunate side-effect of opening the door to various abusive ways in which it can be used.&lt;/p&gt;
&lt;p&gt;Automated support over voice and text. The little &quot;domain knowledge&quot; needed here is all encapsulated within a very narrow context. There are few simple rules of the type &quot;if the human says this, then say that&quot; (the model used to make such decisions are called &quot;decision trees&quot;), and humans learn to identify voice by example. The landmark achievement here is in &quot;speech synthesis&quot;, or making the machine do text-to-human-like-speech. Despite that, it should be noted that speech-to-text and speech synthesis is still an unsolved problem for non-standard accents. We could argue that there isn&#39;t enough data on the non-standard accents, and yes, that&#39;s what this particular problem boils down to.&lt;/p&gt;
&lt;p&gt;More classical problems. Statistical methods have been used to improve upon classical data structures and algorithms in computer science (there was one beating quicksort recently). Analyzing the numbers for patterns, then building a data structure that&#39;s best suited for those patterns, before deciding how to handle them, sounds pretty sensible. The landmark achievement here is that this model can be trained and executed faster than the corresponding classical algorithm.&lt;/p&gt;
&lt;p&gt;Now, we&#39;re ready to see machines fall flat on their faces when presented with problems that are effortless for humans.&lt;/p&gt;
&lt;p&gt;You&#39;re given a sequence of stones, and each stone is represented by a unique symbol. What can you say about the following sequence?&lt;/p&gt;
&lt;pre&gt;[.*, %\!, &amp;^#?]&lt;/pre&gt;
&lt;p&gt;A kindergartner would simply say that there are more stones on the right. Open-ended problems like this present a formidable challenge to machines. How is it supposed to begin approaching the problem? It is already stuck with the concrete, which it is looking at much too closely.&lt;/p&gt;
&lt;p&gt;Two identical twins, jump off from a height of 10ft simultaneously. The first time, they jump without touching each other, and the second time, they hold hands. What is the difference between the two flight timings?&lt;/p&gt;
&lt;p&gt;This thought experiment, if not already familiar, should be a simple task for any human to simulate in their heads. It is often used to illustrate the elegance of a simple physical law. Machines have no idea what to do other than to try some kind of correlation on existing data, or if height of 10ft is relevant.&lt;/p&gt;
&lt;p&gt;I&#39;ve drawn a certain kind of matrix here. Do you see what I&#39;m trying to show you?&lt;/p&gt;
&lt;pre&gt;*
**
***
****
*****&lt;/pre&gt;
&lt;p&gt;Anyone with minimal exposure to linear algebra would immediately say that it&#39;s a lower-triangular matrix, even if they&#39;ve never seen it presented that way. Yes, it&#39;s vague, but this is a classic abstraction problem, working across domains. The machine, in this case, might identify some kind of right-triangle in the textual picture, but what&#39;s the next step? How does this connect to a rectangle filled with numbers? Where are the numbers?&lt;/p&gt;
&lt;p&gt;Notice that very little knowledge is needed to solve the above problems, and collecting more data isn&#39;t going to change a thing.&lt;/p&gt;
&lt;p&gt;Solving these seemingly childish problems might not be of much consequence, but they are prerequisites for tackling more complicated problems:&lt;/p&gt;
&lt;p&gt;Given that a hedgehog is a rodent that some people keep as pets, which of these six pictures is the picture of a hedgehog?
Derive the equation of motion for a simple pendulum from the axioms of classical mechanics.
Watch a film, and critically comment on the acting, screenplay, direction, and storyline.
Deliver a talk on black holes, and gauge the level of understanding of the audience from the questions you receive.
Check the correctness of the proof of the abc conjecture, by directly reading the document uploaded on arXiv.&lt;/p&gt;
&lt;p&gt;To claim that there even is such as thing as a &quot;singularity&quot;, requires, at the very least, some kind of strategy to tackle the last problem.&lt;/p&gt;
&lt;p&gt;At this point, the data-zealots would interject. If we collected all the data of every second of every human&#39;s life for a year, given enough storage space and compute power, we&#39;d be able to tackle at least some of these problems using current methods, and our methods are only going to get better over time, they&#39;d argue. Even if it were true, it is a ridiculous claim, akin to something along the lines of &quot;given enough time, I can write a graphical web browser that runs on bare-metal, from scratch, by writing a sequence of 0s and 1s on a piece of paper&quot;. Actually, it&#39;s even more ridiculous than that, because you&#39;d need entire galaxies of low-wage unskilled workers to &quot;clean&quot; and &quot;annotate&quot; the collected data to spoon-feed the machine. Is this the &quot;singularity&quot; you talk about, where humans are doing the equivalent of cleaning ditches to keep the omniscient being happy? If you can&#39;t do kindergartner-level problems today without human assistance, with so much compute power at your disposal, what hope is there of claiming any &quot;intelligence&quot;? But, they&#39;d argue, what if that machine has an intelligence that&#39;s &quot;different&quot;, but somehow &quot;subsumes&quot; human intelligence? This is the kind of pseudoscientific rubbish that&#39;s spewed by nutty cult leaders. Statistical methods have a firm place in modern society, but as it currently stands, machines are the ones with the dunce hats in play-school.&lt;/p&gt;
&lt;p&gt;We&#39;re currently in a data-warzone era, where all the big players are racing to collect more data on their users. What kind of data? Boring, inconsequential, everyday lives of human beings. To put it uncharitably, go through everyone&#39;s garbage with computing clusters, and you&#39;re bound to find some half-eaten chocolates. The models behind AlphaGo, GPT-3, and AlphaFold have the same essential nature as the ones used to keep us endlessly hooked onto social platforms, and to sell us unwanted products via sweet-talking voice-assistants. A lot of industrial AI research is enormously expensive, but the dirty secret is that it is paid for with the privacy of decent unassuming folk.&lt;/p&gt;
&lt;p&gt;Let strangers sift through your garbage if you please, but don&#39;t do it while being drunk on the &quot;singularity&quot; kool-aid. $\Box$&lt;/p&gt;</summary>
    <title>What machines can and can&#39;t do</title>
    <updated>2020-12-01T07:41:57+01:00</updated>
    <dc:date>2020-12-01T07:41:57+01:00</dc:date>
  </entry>
  <entry>
    <id>art/pedestrian</id>
    <link href="art/pedestrian"/>
    <summary>&lt;p&gt;We argue that, underneath all the large-language model hype, there is a pedestrian technology that has the potential to automate a class of problems that classical software can never do.&lt;/p&gt;
&lt;p&gt;To study the capabilities of large-language models in the context of writing code, we study two extreme cases. First, the application to a critical project with high cognitive complexity, consisting of 40 million lines of code, and second, the application to a simple from-scratch toy project.&lt;/p&gt;
&lt;p&gt;For the first study, I tried incorporating the technology into everyday-contributions to LLVM. The suggestions have over a 95% reject-rate, and the good suggestions appear when you&#39;re editing one instance of a mechanical pattern, and want to change all instances.&lt;/p&gt;
&lt;p&gt;For example, consider the following transformation:&lt;/p&gt;
&lt;pre&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_c_Xor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;m_CombineOr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_ZextOrTrunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_Specific&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_Specific&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;m_CombineOr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_ZextOrTrunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_Specific&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_Specific&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_c_Xor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_CastOrSelf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_Specific&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;m_CastOrSelf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_Specific&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This can, in theory, be done by a find-and-replace with a regex, but nobody ever does that for a couple instances.&lt;/p&gt;
&lt;p&gt;As another example, consider updating argument names and corresponding comments like:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;/// Checks that \p L and \p R are used together in an XOR in the use-def chain&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// of \p SI&#39;s condition, ignoring any casts. The purpose of this function is to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// ensure that LHSAux from the SimpleRecurrence is used correctly in the CRC&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// computation. We cannot check the correctness of casts at this point, and&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// rely on the KnownBits propagation to check correctness of the CRC&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// computation.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isConditionalOnXorOfPHIs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SelectInst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PHINode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PHINode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Loop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;/// Checks that \p P1 and \p P2 are used together in an XOR in the use-def chain&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// of \p SI&#39;s condition, ignoring any casts. The purpose of this function is to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// ensure that LHSAux from the SimpleRecurrence is used correctly in the CRC&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// computation. We cannot check the correctness of casts at this point, and&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// rely on the KnownBits propagation to check correctness of the CRC&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// computation.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isConditionalOnXorOfPHIs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SelectInst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PHINode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PHINode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Loop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;A find-and-replace would match the &lt;code&gt;L&lt;/code&gt; in the &lt;code&gt;Loop&lt;/code&gt; argument, erroneously replacing it with &lt;code&gt;P1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You could say that all the automation boils down to a smart and automatic find-and-replace in this study, but it is important to note this class of problems can never be automated by classical software.&lt;/p&gt;
&lt;p&gt;For the second study, I tried applying the technology to writing a tree-sitter based LLVM IR parser. The entire task is a mechanical chore of reading docs and ample examples in the test suite, and encoding the knowledge in the parser. To study the limitations, I tried generating the entire parser using a prompt, but the result was entirely unusable. When writing the parser from a clean-slate, the suggestions were actually quite good. Consider the auto-complete with the following snippet:&lt;/p&gt;
&lt;pre&gt;    binary_instruction: ($) =&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre&gt;    &lt;span class=&quot;nx&quot;&gt;binary_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_binary_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;_binary_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mul&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mod&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;shl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;shr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;call_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;tail&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;atname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;compare_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_compare_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;_compare_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ne&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;slt&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sgt&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sge&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ult&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ugt&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ule&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;uge&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;cast_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_cast_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;_cast_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;trunc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;zext&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sext&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fptrunc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fpext&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fp_to_ui&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fp_to_si&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;uitofp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sitofp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ptrtoint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;inttoptr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;bitcast&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;extract_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;extractvalue&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;insert_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;insertvalue&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;load_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;phi_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;phi&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;store_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;switch_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;branch_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;br&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;return_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssa_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;unreachable_instruction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;which is actually a smarter version of a copy-paste with some knowledge from the internet. Of course the code needs editing, but this is the kind of copy-pasting you&#39;d normally do before making edits.&lt;/p&gt;
&lt;p&gt;The technology was also able to generate 300 tests to exercise the parser, and the tests needed little tweaking to pass: this task can be boiled down to copying reduced-case LLVM IR from the test-suite, and matching them with parser nodes. Of course the generated tests aren&#39;t high-quality, but about half the tests are usable as-is, and a lot of tedium has been eliminated.&lt;/p&gt;
&lt;p&gt;To conclude, the technology is at alpha-stage, as the automation comes at the cost of putting up with bad visual feedback and fighting the auto-complete nearly all the time, but promises a new class of mechanical automation, whose utility is higher in small codebases following mechanical patterns.&lt;/p&gt;</summary>
    <title>The pedestrian technology underneath the hype</title>
    <updated>2025-07-02T14:18:51+01:00</updated>
    <dc:date>2025-07-02T14:18:51+01:00</dc:date>
  </entry>
  <entry>
    <id>art/pl</id>
    <link href="art/pl"/>
    <summary>&lt;p&gt;We illustrate how different programming languages influnced each other, and include a quick FAQ write up.&lt;/p&gt;
&lt;p&gt;An FAQ follows.&lt;/p&gt;
&lt;p&gt;Why would someone pick C++ over Rust today?&lt;/p&gt;
&lt;p&gt;C++ templates are incredibly powerful, and with the introduction of compile-time expressions, vast portions of modern C++ programs are just compile-time tables. Examples like this make Rust look very tiny:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CurTy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;recurseFillChildren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurTy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PackTy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TyL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variant_alternative_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PackTy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static_assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_same_v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurTy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TyL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TyR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variant_alternative_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PackTy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i32&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NChildren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;miniParser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TyR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constexpr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;recurseFillChildren&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Is there anything that Rust can do that C++ can&#39;t?&lt;/p&gt;
&lt;p&gt;Rust didn&#39;t restrict what macros can do as much as C++ did. As a result, it&#39;s possible to do more with them. The particular example of the Pest parser is especially enlightening:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;#[derive(Parser)]&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;#[grammar&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;grammar.pest&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;]&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Essentially, &quot;grammar.pest&quot; is processed at compile-time, and you can use definitions parsed from it in your code. However, there are trade-offs; Rust&#39;s macros are very slow, and your compile-times blow up if you have recursive macros. &lt;code&gt;std::embed&lt;/code&gt; in C++23 will probably do it right.&lt;/p&gt;
&lt;p&gt;Why is Haskell classified as a dying language?&lt;/p&gt;
&lt;p&gt;Haskell is pleasant to get started with, and write relatively simple programs in. In the 2010-2015 period, there was a lot of intellectual discourse and PL research around it. The high-brow crowd was obsessed with transactional memory, parser combinators, and lenses. Online resources were exploding: LYAH and CatProg enjoyed their bouts of popularity. Several people and companies invested in Haskell heavily in that period. The language is easy to get started with, and has a pleasant development experience for relatively simple programs. The problems started when codebases started growing in size and complexity.&lt;/p&gt;
&lt;p&gt;You either need to be able to interactively debug your program or prove that it is correct: in Haskell, you can&#39;t do either; the best you can do is to write some QuickCheck tests. Then there&#39;s Liquid Haskell that allows you to pepper your Haskell code with invariants that it will check using Z3. Unfortunately, it is very limited in what it can do: good luck checking your monadic combinator library with LH. Moreover, there are no tools to help you debug the most notorious kind of bug seen in a complicated codebase: memory blowups caused by laziness. It suffices to say that tooling is weak. In Atom, the Haskell add-on was terrible, and even today, in VSCode, the Haskell extension is among the most buggy language plugins.&lt;/p&gt;
&lt;p&gt;There are &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/blob/a1f34d37b47826e86343e368a5c00f1a4b1f2bce/compiler/GHC/Driver/Session.hs#L3729-3876&quot;&gt;over 120&lt;/a&gt; language extensions, which can be turned on/off in each &lt;code&gt;.hs&lt;/code&gt; file. The issue is that different extensions interact in subtle ways to produce bugs, and it&#39;s very difficult to tell if a new language extension will play well with the others (it often doesn&#39;t, until all the bugs are squashed, which can take a few years). The best case scenario plays out like this: GHC rejects your program, and suggests that you turn on some other language extensions; you turn them on, and you&#39;re left with a cryptic error message coming from a language extension you&#39;re not as familiar with; you spend the next N hours reading whatever little information is available about the more recent language extension, and decide to throw in the towel. The worst case plays out as follows: the type-checker hangs or crashes, and you&#39;re on the issue tracker searching for the issue; if you&#39;re lucky, you&#39;ll find a bug filed using 50~60% of the language extensions you used in your program, and you&#39;re not sure if it&#39;s the same issue; you file a new issue. In either case, your work has been halted.&lt;/p&gt;
&lt;p&gt;There is almost zero documentation on language extensions. Hell, you can&#39;t even find the list of available language extensions with some description on any wiki. Looking at the big picture: first, this is a poor way to do software development; as the number of language extensions increase, your testing burden increases exponentially. Second, the problem of having a good type system is already solved by a simple dependent type theory; you study the core, and every new feature is just a small delta that fits in nicely with the overall model. As opposed to having to read detailed papers on each new language extension. And yes, there&#39;s a good chance that very few people will be able to understand your code if you&#39;re using some esoteric extensions. In summary, language extensions are complicated hacks to compensate for the poverty of Haskell&#39;s type system.&lt;/p&gt;
&lt;p&gt;In practice, you&#39;ll be familiar with ~20 language extensions, and use various combinations of them over and over again, so the problem might not seem as acute as a regular Haskell programmer. However, PL research has shifted away from Haskell for the most part, and the little that happens tends to be &lt;a href=&quot;https://www.microsoft.com/en-us/research/uploads/prod/2019/03/ho-haskell-5c8bb4918a4de.pdf&quot;&gt;unnecessarily complex nonsense&lt;/a&gt; that never sees the light of day.&lt;/p&gt;
&lt;p&gt;Here&#39;s a sample of some simple Haskell code pieced together. I&#39;ve intentionally left out examples using &lt;code&gt;LinearTypes&lt;/code&gt;, because it&#39;s unfair to find faults with such a recent language feature.&lt;/p&gt;
&lt;p&gt;What does the code mean? What is the intent?
Can you specifically tell how each language extension was useful in the snippet?
Guess what the code will do on GHC 8.10.1. What will an older version of GHC do?
How many more language features are missing?&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE MagicHash #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE TypeFamilies #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE TypeInType #-}&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;GHC.Exts&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;family&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;MatchInt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;MatchInt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;&#39;I&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE PolyKinds #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE RankNTypes #-}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE PolyKinds #-}&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE DataKinds              #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE FlexibleContexts       #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE PolyKinds              #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE TypeFamilyDependencies #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# LANGUAGE TypeOperators, AllowAmbiguousTypes          #-}&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;family&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;family&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OfDim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!*^&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OfDim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Dim&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OfDim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!*^&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Doesn&#39;t Go feature a solid compiler/runtime?&lt;/p&gt;
&lt;p&gt;It does, but the author didn&#39;t feel that it was worthy of an asterisk, because the compiler is working with a really dumb language. Nevertheless, the GC and scheduler are praise-worthy, as is the overall experience with ultra-low compile-times.&lt;/p&gt;</summary>
    <title>An opinionated history of programming languages</title>
    <updated>2020-09-30T12:43:32+02:00</updated>
    <dc:date>2020-09-30T12:43:32+02:00</dc:date>
  </entry>
  <entry>
    <id>art/ra</id>
    <link href="art/ra"/>
    <summary>&lt;p&gt;A picture of artwork.&lt;/p&gt;
&lt;img src=&quot;/art/ra.jpg&quot; /&gt;</summary>
    <title>Ra: Egyptian ink on parchment</title>
    <updated>2020-12-27T05:50:10+01:00</updated>
    <dc:date>2020-12-27T05:50:10+01:00</dc:date>
  </entry>
  <entry>
    <id>art/wet-dream</id>
    <link href="art/wet-dream"/>
    <summary>&lt;p&gt;Capitalism works by getting a small number of skilled humans to produce something or offer some service that can then be marketed and sold to a vast consumer class. We live in very exciting times, for corporations have stumbled on a piece of technology that will take the capitalist wet dream to its absolute end: eliminating a vast number of skilled humans from the process, generating vast amounts of low-quality content instantaneously. Yes, generative AI will take jobs away from artists, writers, journalists, doctors, therapists, programmers, musicians, actors, lawyers, and several other professions. Anyone who tells you otherwise is lying. Capitalism has always been a race to the bottom: if your product or service offers something valuable at a competitive price, consumers will give you their money. Amazon and Uber are prime examples of this, and both create a sharp divide between the workers they exploit and the customers who&#39;re paying them. Whatever happens next with generative AI should therefore come as no surprise to anyone familiar with the basics of capitalism.&lt;/p&gt;
&lt;p&gt;In this race to the bottom, there will be a vast number of people who can&#39;t afford human labor and are stuck in the free tier of ad-supported AI-generated content. The amount of such content available will explode by five or ten orders of magnitude, leading to greater consumption, and hence higher ad revenues. Most ads in this tier will be similarly AI-generated, as advertisers would also want to cut costs. Of course, corporations will say that the vast majority&#39;s quality of life has improved, as these poor people would now have access to a free AI doctor, therapist, and companion, AI summaries of content they can&#39;t afford, in addition to the vast amounts of low-quality misinformation and entertainment. The number of skilled humans required will shrink, as will the output: for the average person, buying such content will become a luxury. Wealthy people today already live in separate worlds, and they&#39;re already a different class of consumer, so it&#39;s not very hard to imagine what the world will be like once this technology becomes widespread.&lt;/p&gt;
&lt;p&gt;Lengthy articles and debates on the internet seriously evaluating generative AI technology amuse me. It&#39;s supposed to be cheap unglamorous rubbish that you peddle to the masses, and I&#39;m sure the people making the calls at corporations are chuckling too.&lt;/p&gt;
&lt;p&gt;AI is something you pay to avoid, just like ads. $\Box$&lt;/p&gt;</summary>
    <title>The capitalist wet dream</title>
    <updated>2025-01-04T19:18:03+00:00</updated>
    <dc:date>2025-01-04T19:18:03+00:00</dc:date>
  </entry>
  <entry>
    <id>compilers/2025-llvm</id>
    <link href="compilers/2025-llvm"/>
    <summary>&lt;p&gt;As the year draws to a close, it helps to look back and reflect on some key changes in LLVM. The article is written from my perspective, summarizing work I landed, along with adjacent work, in chronological order.&lt;/p&gt;
&lt;p&gt;In September 2024, Nikita Popov proposed &lt;a href=&quot;https://discourse.llvm.org/t/rfc-signedness-independent-icmps/81423&quot;&gt;signedness-independent integer-compares&lt;/a&gt;, and the necessary work for enabling optimizations with it occupied the first two months of my 2025. In January, Florian Hahn introduced the initial version of a &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Analysis/ScalarEvolutionPatternMatch.h&quot;&gt;pattern-matcher for ScalarEvolution&lt;/a&gt;, which I would flesh out and use to improve code over the course of the year.&lt;/p&gt;
&lt;p&gt;March and April were not very productive, as I was on vacation and attending EuroLLVM. In the little time I had, I fixed a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/137005&quot;&gt;vectorization bug&lt;/a&gt; and improved code by &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/134373&quot;&gt;introducing a new iterator in a fundamental data structure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In May, I introduced a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/125365&quot;&gt;constant folder&lt;/a&gt; in VPlan, guided by Florian, and fixed another &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/136858&quot;&gt;vectorization bug&lt;/a&gt;. In collaboration with Mel Chen, I made a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/118393&quot;&gt;small improvement to the routine that checks patterns for vectorization&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In June, an &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/HashRecognize.cpp&quot;&gt;analysis to recognize cyclic-redundancy-check loops&lt;/a&gt; landed, but required several months of improvements, before finally &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/143208&quot;&gt;enabling optimization of CRC loops&lt;/a&gt; in September: the work was done in close collaboration with Piotr Fusik. While reviewing one of Florian&#39;s patches, I also &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/141752&quot;&gt;extended a pattern for vectorization&lt;/a&gt;, which Florian built upon.&lt;/p&gt;
&lt;p&gt;In July, I was occupied with instruction selection and &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/146058&quot;&gt;cost-modeling work&lt;/a&gt; for the intrinsics &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/145898&quot;&gt;lrint&lt;/a&gt;, &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/147713&quot;&gt;lround&lt;/a&gt;, and &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/152476&quot;&gt;ldexp&lt;/a&gt; on RISC-V, guided by Craig Topper.&lt;/p&gt;
&lt;p&gt;In August, Luke Lau used parameter packs to &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/152272&quot;&gt;greatly improve the pattern-matcher&lt;/a&gt; in VPlan. Inspired by another of his patches, I would introduce a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/154771&quot;&gt;integer/floating-point compare matcher&lt;/a&gt;, using it for optimization benefit. I would also fix some issued related to wrap-flags in VPlan.&lt;/p&gt;
&lt;p&gt;In September, I introduced a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/151872&quot;&gt;common-subexpression-elimination transform&lt;/a&gt; in VPlan, guided by Florian. I also picked up and completed one of Luke&#39;s abandoned patches, a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/159386&quot;&gt;match functor&lt;/a&gt;. Nikita would introduce &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp&quot;&gt;a new transform&lt;/a&gt; to strip unnecessary &lt;code&gt;llvm.assume&lt;/code&gt; instructions.&lt;/p&gt;
&lt;p&gt;In October, I would obsess over the loop-invariant code motion in VPlan, and &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/162674&quot;&gt;factor out the legality check for hoisting/sinking&lt;/a&gt;, fixing a miscompile. My routine would bail out on memory operations due to aliasing issues, and I was thinking about how to get aliasing information in VPlan.&lt;/p&gt;
&lt;p&gt;In November, I would &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/168354&quot;&gt;fix long-standing issues related to wrap-flags&lt;/a&gt; in VPlan, and make an improvement to a routine to undo sub-optimal widening decisions in VPlan. Florian would build upon my improvement to yield the &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/168246&quot;&gt;final version&lt;/a&gt;. He would also create specialized hoisting/sinking routines for memory operations, based on the &lt;code&gt;noalias&lt;/code&gt; metadata: I plan to re-use the legality checks to improve the general case.&lt;/p&gt;
&lt;p&gt;Finally, we&#39;re in December. The main outstanding patches are &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/168886&quot;&gt;directly unrolling a recipe&lt;/a&gt; in VPlan, and introducing a &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/168731&quot;&gt;carry-less multiply intrinsic&lt;/a&gt;, whose design was guided by Craig and Piotr. Both will hopefully land soon.&lt;/p&gt;
&lt;p&gt;Although I wasn&#39;t either directly or indirectly involved, &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/153821&quot;&gt;llvm-lit --update-tests&lt;/a&gt; introduced in August, has completely eliminated the tedium associated with mass test-updates!&lt;/p&gt;</summary>
    <title>My 2025 in LLVM: samesign, HashRecognize, and VPlan</title>
    <updated>2025-12-08T18:13:01+00:00</updated>
    <dc:date>2025-12-08T18:13:01+00:00</dc:date>
  </entry>
  <entry>
    <id>compilers/abibug</id>
    <link href="compilers/abibug"/>
    <summary>&lt;p&gt;Our custom max function returns the maximum of two positive integers, and returns the negative integer, given a positive and negative integer. Classic signed wrapping, you&#39;d think. It&#39;s not so simple, as the problem reproduces only under the following circumstances:&lt;/p&gt;
&lt;p&gt;LLVM code is calling the max function.
The library containing the max function is compiled without debugging information.
The entire world has been built with XCode 6+.&lt;/p&gt;
&lt;p&gt;More information: The LLVM IR is exactly the same between an XCode 5 sandbox, an XCode 6 sandbox, and a GNU/Linux sandbox. The corresponding assembly diff is also clean.&lt;/p&gt;
&lt;p&gt;The corresponding C++ code (is actually specialized with short) is:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FORCEINLINE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;While in lldb, the assembly instructions look like:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;---------------&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;XCode&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x108af1930&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;pushq&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rbp&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108af1931&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;movq&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rbp&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108af1934&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cmpw&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;di&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108af1937&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cmovgew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;di&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108af193b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;movswl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108af193e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;popq&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rbp&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108af193f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;retq&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;---------------&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;XCode&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x108d1ac10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;pushq&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rbp&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108d1ac11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;movq&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rbp&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108d1ac14&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cmpl&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108d1ac16&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cmovgew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;di&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108d1ac1a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;movswl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108d1ac1d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;popq&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rbp&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x108d1ac1e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;retq&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;So, it&#39;s comparing the extended registers, but cmpl/cmpw difference is
messing up somehow.&lt;/p&gt;
&lt;p&gt;After execution of the cmpl/cmpw:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;---------------&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;XCode&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;di&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;di&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;si&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7103&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7103&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rflags&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rflags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mb&quot;&gt;0b0000000000000000000000000000000000000000000000000000001010010010&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;---------------&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;XCode&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;di&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;di&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;si&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rflags&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rflags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mb&quot;&gt;0b0000000000000000000000000000000000000000000000000000001000010010&lt;/span&gt;
                                                                     &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;
                                                             &lt;span class=&quot;n&quot;&gt;Sign&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;different&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;---------------&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;XCode&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calling&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;di&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;di&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;si&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;si&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;edi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                 &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;In&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LLVM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zero&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;In conclusion, this is a Clang/LLVM version mismatch. It&#39;s compiling muIntScalarMax_sint16 to emit a compl instead of a compw. The fact that the bug only reproduces with LLVM is because: LLVM doesn&#39;t set up the extended form of the register correctly for negative numbers, when calling a function with a word-sized register.&lt;/p&gt;
&lt;p&gt;The SysV ABI does not guarantee that the i16 will be sext&#39;ed to i32. Clang ABI is probably an enhancement over the SysV ABI, and LLVM 3.5 doesn&#39;t know about this.&lt;/p&gt;</summary>
    <title>An ABI-mismatch bug</title>
    <updated>2015-08-23T16:25:56-05:00</updated>
    <dc:date>2015-08-23T16:25:56-05:00</dc:date>
  </entry>
  <entry>
    <id>compilers/backend</id>
    <link href="compilers/backend"/>
    <summary>&lt;p&gt;Any modern compiler has three main components: a front-end that parses the source language, and translates it to a middle-end intermediate representation, a middle-end that operates on this IR, performing target-independent optimizations with a bit of target-specific information, and a backend that takes the final optimized middle-end IR and emits target-specific assembly. In this article, we illustrate the operation of a the main components of a compiler&#39;s backend, namely instruction selection, instruction scheduling, and register allocation, using LLVM as the reference compiler. LLVM is especially good for the purposes of illustration, as it has, in addition to a clean human-readable middle-end IR, a relatively clean human-readable backend IR. We use the RISC-V target for the purposes of concrete illustration, chosen once again for its clean design.&lt;/p&gt;
&lt;p&gt;Let us start with a simple C program as our guiding example, and have a look at each step of the backend lowering after running the entire middle-end optimization pipeline, all the way up to the final assembly.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;#define N 64
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;matmul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;First, we run the front-end, and the full middle-end optimization pipeline to obtain the optimized LLVM IR that&#39;s handed off to the backend. Running &lt;code&gt;clang --target=riscv64 -march=rv64gc -O3 -emit-llvm -S&lt;/code&gt; emits:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;@matmul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;noalias&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;noalias&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;noalias&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;entry:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%ph&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;ph:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.outer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.outer.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common.exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%shl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;shl&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nsw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common.ph&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;exit:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;common.ph:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.middle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%ph&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.middle.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%inner.loop.exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;disjoint&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.middle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%shl&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.res&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%or&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.res&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.res&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.middle&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%inner.loop&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;common.exit:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.outer.next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nsw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%exit.cond.outer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;icmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.outer.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit.cond.outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%ph&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;inner.loop.exit:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%conv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.res&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;middle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nsw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.middle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%exit.cond.middle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;icmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.middle.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit.cond.middle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common.exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common.ph&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;inner.loop:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common.ph&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%inner.loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%conv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common.ph&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%conv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%inner.loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;disjoint&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%shl&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%or&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%shl.iv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;shl&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nsw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.y.2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%shl.iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y.2&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%conv.next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;@llvm.fmuladd.f32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
               &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%conv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nsw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%exit.cond&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;icmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit.cond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%inner.loop.exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%inner.loop&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The astute reader will note that we have strategically omitted the vector extension of RISC-V (we use &lt;code&gt;-march=rv64gc&lt;/code&gt; instead of &lt;code&gt;-march=rv64gcv&lt;/code&gt;) to avoid unnecessarily complicating the exposition due to the vectorization passes in LLVM. Auto-vectorization has already been discussed &lt;a href=&quot;/compilers/intro-vec&quot;&gt;previously&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first thing to notice is that the body of the function is cleanly separated into basic blocks: entry, ph, common.ph, inner.loop, inner.loop.exit, common.exit, and exit. Next, notice that the IR is in single-static-assignment (SSA) form, which means is that variables like &lt;code&gt;%iv&lt;/code&gt; are only ever defined once. Since this is a loop that requires incrementing the induction variable, a fresh &lt;code&gt;%iv.next&lt;/code&gt; variable is created, and &lt;code&gt;%iv&lt;/code&gt; is a &lt;code&gt;phi&lt;/code&gt; node that selects between the values &lt;code&gt;0&lt;/code&gt; when jumping into the &lt;code&gt;loop&lt;/code&gt; block from &lt;code&gt;entry&lt;/code&gt;, and &lt;code&gt;%iv.next&lt;/code&gt; when jumping to the &lt;code&gt;inner.loop&lt;/code&gt; block from the back-edge of the inner loop. All the instructions (load, getelementptr, store, or, shl etc.) are target-independent instructions that are used throughout the LLVM middle-end. The target-specific instructions will only be seen after instruction selection.&lt;/p&gt;
&lt;p&gt;The first step in the lowering process is instruction selection. We can look at the output of this step by running &lt;code&gt;llc --print-after-isel&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;Function Live Ins: $x10 in %18, $x11 in %19, $x12 in %20

bb.0 (%ir-block.3):
  successors: %bb.1(0x80000000); %bb.1(100.00%)
  liveins: $x10, $x11, $x12
  %20:gpr = COPY $x12
  %19:gpr = COPY $x11
  %18:gpr = COPY $x10
  %22:gpr = COPY $x0
  %21:gpr = COPY %22:gpr

bb.1 (%ir-block.4):
  successors: %bb.3(0x80000000); %bb.3(100.00%)
  %0:gpr = PHI %18:gpr, %bb.0, %9:gpr, %bb.4
  %1:gpr = PHI %21:gpr, %bb.0, %8:gpr, %bb.4
  %2:gpr = nuw nsw SLLI %1:gpr, 6
  %24:gpr = COPY $x0
  %23:gpr = COPY %24:gpr
  PseudoBR %bb.3

bb.2 (%ir-block.7):
  PseudoRET

bb.3 (%ir-block.8):
  successors: %bb.6(0x80000000); %bb.6(100.00%)
  %3:gpr = PHI %19:gpr, %bb.1, %11:gpr, %bb.5
  %4:gpr = PHI %23:gpr, %bb.1, %10:gpr, %bb.5
  %25:gpr = nuw nsw SLLI %4:gpr, 2
  %26:gpr = ADD killed %25:gpr, %19:gpr
  %27:gpr = LUI 4
  %5:gpr = ADD killed %26:gpr, killed %27:gpr
  %28:gpr = OR %4:gpr, %2:gpr
  %29:gpr = SLLI killed %28:gpr, 2
  %6:gpr = ADD %20:gpr, killed %29:gpr
  %7:fpr32 = FLW %6:gpr, 0
  PseudoBR %bb.6

bb.4 (%ir-block.15):
  successors: %bb.2(0x04000000), %bb.1(0x7c000000);
              %bb.2(3.12%), %bb.1(96.88%)
  %8:gpr = nuw nsw ADDI %1:gpr, 1
  %9:gpr = ADDI %0:gpr, 256
  %33:gpr = ADDI $x0, 64
  BEQ %8:gpr, killed %33:gpr, %bb.2
  PseudoBR %bb.1

bb.5 (%ir-block.18):
  successors: %bb.4(0x04000000), %bb.3(0x7c000000);
              %bb.4(3.12%), %bb.3(96.88%)
  FSW %15:fpr32, %6:gpr, 0
  %10:gpr = nuw nsw ADDI %4:gpr, 1
  %11:gpr = ADDI %3:gpr, 4
  %32:gpr = ADDI $x0, 64
  BEQ %10:gpr, killed %32:gpr, %bb.4
  PseudoBR %bb.3

bb.6 (%ir-block.21):
  successors: %bb.5(0x04000000), %bb.6(0x7c000000);
              %bb.5(3.12%), %bb.6(96.88%)
  %12:gpr = PHI %0:gpr, %bb.3, %17:gpr, %bb.6
  %13:gpr = PHI %3:gpr, %bb.3, %16:gpr, %bb.6
  %14:fpr32 = PHI %7:fpr32, %bb.3, %15:fpr32, %bb.6
  %30:fpr32 = FLW %12:gpr, 0
  %31:fpr32 = FLW %13:gpr, 0
  %15:fpr32 = nofpexcept FMADD_S killed %30:fpr32,
              killed %31:fpr32, %14:fpr32, 7, implicit $frm
  %16:gpr = ADDI %13:gpr, 256
  %17:gpr = ADDI %12:gpr, 4
  BEQ %16:gpr, %5:gpr, %bb.5
  PseudoBR %bb.6&lt;/pre&gt;
&lt;p&gt;What we see is a relatively straight-forward translation of the middle-end LLVM IR to machine IR (MIR), preserving the basic block structure and SSA-form. The purpose of instruction selection is to select a combination of instructions available on the target that optimally represents the middle-end semantics. Its two primary functions are to replace middle-end SSA variables by virtual registers, and to replace middle-end instructions by target-specific instructions.&lt;/p&gt;
&lt;p&gt;Each virtual register has a suffix of either gpr (general-purpose register) or fpr (floating-point register). There are also physical registers in this MIR: &lt;code&gt;$x0&lt;/code&gt;, &lt;code&gt;$x10&lt;/code&gt;, &lt;code&gt;$x11&lt;/code&gt;, &lt;code&gt;$x12&lt;/code&gt;, &lt;code&gt;$frm&lt;/code&gt;. Per the RISC-V calling convention, the three arguments to the function are in general-purpose registers &lt;code&gt;$x10&lt;/code&gt;, &lt;code&gt;$x11&lt;/code&gt;, and &lt;code&gt;$x12&lt;/code&gt; (pretty-printed as &lt;code&gt;a0&lt;/code&gt;, &lt;code&gt;a1&lt;/code&gt;, and &lt;code&gt;a2&lt;/code&gt;). &lt;code&gt;$x0&lt;/code&gt; is a special register on RISC-V that always holds the value &lt;code&gt;0&lt;/code&gt;. &lt;code&gt;$frm&lt;/code&gt; is the floating-point rounding-mode register. None of these can be virtual registers. A minor point to notice is the annotations on the virtual registers, &lt;code&gt;killed&lt;/code&gt; and &lt;code&gt;implicit&lt;/code&gt;. The operands of the &lt;code&gt;FMADD_S&lt;/code&gt;, &lt;code&gt;%30:fpr32&lt;/code&gt; and &lt;code&gt;%31:fpr32&lt;/code&gt;, are marked as &lt;code&gt;killed&lt;/code&gt;, meaning that this is the final definition/use of those registers (these annotations are preliminary: the final annotations will be determined at a later stage). The register &lt;code&gt;$frm&lt;/code&gt; is marked as &lt;code&gt;implicit&lt;/code&gt;, meaning that it implicitly uses this register, and that this argument will be absent in the final assembly. The virtual registers must be turned into physical registers by the register allocator before emitting the final assembly.&lt;/p&gt;
&lt;p&gt;Middle-end instructions like &lt;code&gt;@llvm.fmuladd&lt;/code&gt; have been replaced by target-specific instructions like &lt;code&gt;FMADD_S&lt;/code&gt; (pretty-printed as &lt;code&gt;fmadd.s&lt;/code&gt;), and several pseudo-instructions like &lt;code&gt;PseudoBR&lt;/code&gt;, &lt;code&gt;PseudoRET&lt;/code&gt;, and &lt;code&gt;COPY&lt;/code&gt; have been inserted in the process. The pseudo-instructions must be lowered to real instructions before emitting the final assembly.&lt;/p&gt;
&lt;p&gt;There is some minor additional information in this MIR: the live-ins, or registers that are live at the point of entry, and the branch frequency information: &lt;code&gt;bb.6&lt;/code&gt; is going to be the successor basic-block of &lt;code&gt;bb.6&lt;/code&gt; 97% of the time.&lt;/p&gt;
&lt;p&gt;Although the instruction selection infrastructure, SelectionDAG †, is target-independent, we can see that our MIR is clearly specialized for RISC-V. All the information about the registers available on RISC-V are defined in &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/RISCV/RISCVRegisterInfo.td&quot;&gt;RISCVRegisterInfo.td&lt;/a&gt;. The RISC-V instructions themselves come out of the specification &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/RISCV/RISCVInstrInfo.td&quot;&gt;RISCVInstrInfo.td&lt;/a&gt;, and the target-specific code that specifies how middle-end instructions should be lowered to instructions in this specification via SelectionDAG is &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/RISCV/RISCVISelLowering.cpp&quot;&gt;RISCVISelLowering.cpp&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order to understand the various steps after instruction selection, let us &lt;a href=&quot;https://godbolt.org/z/TxzjEMr5M&quot;&gt;inspect the diffs&lt;/a&gt; produced at each step by running &lt;code&gt;llc -print-changed=diff&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first significant pass to run after the instruction selection is &lt;code&gt;early-machinelicm&lt;/code&gt;, which is just a backend version of the middle-end loop invariant code motion transform. Next, we have &lt;code&gt;livevars&lt;/code&gt;, which analyzes live variables, and marks registers as &lt;code&gt;killed&lt;/code&gt; aggressively.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;phi-node-elimination&lt;/code&gt; runs next, which removes PHI nodes, leaving the MIR in SSA form by inserting pseudo COPY instructions:&lt;/p&gt;
&lt;pre&gt;  Function Live Ins: $x10 in %18, $x11 in %19, $x12 in %20

  bb.0 (%ir-block.3):
   successors: %bb.1(0x80000000); %bb.1(100.00%)
   liveins: $x10, $x11, $x12
   %20:gpr = COPY killed $x12
   %19:gpr = COPY killed $x11
   %18:gpr = COPY killed $x10
   %22:gpr = COPY $x0
   %21:gpr = COPY killed %22:gpr
   %27:gpr = LUI 4
   %32:gpr = ADDI $x0, 64
&lt;span class=&quot;gi&quot;&gt;+  %36:gpr = COPY killed %18:gpr
+  %37:gpr = COPY killed %21:gpr
&lt;/span&gt;
 bb.1 (%ir-block.4):
   successors: %bb.3(0x80000000); %bb.3(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %0:gpr = PHI %18:gpr, %bb.0, %9:gpr, %bb.4
-  %1:gpr = PHI %21:gpr, %bb.0, %8:gpr, %bb.4
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %1:gpr = COPY killed %37:gpr
+  %0:gpr = COPY killed %36:gpr
&lt;/span&gt;   %2:gpr = nuw nsw SLLI %1:gpr, 6
   %24:gpr = COPY $x0
   %23:gpr = COPY killed %24:gpr
&lt;span class=&quot;gi&quot;&gt;+  %38:gpr = COPY %19:gpr
+  %39:gpr = COPY killed %23:gpr
&lt;/span&gt;   PseudoBR %bb.3

 bb.2 (%ir-block.7):
   PseudoRET

 bb.3 (%ir-block.8):
   successors: %bb.6(0x80000000); %bb.6(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %3:gpr = PHI %19:gpr, %bb.1, %11:gpr, %bb.5
-  %4:gpr = PHI %23:gpr, %bb.1, %10:gpr, %bb.5
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %4:gpr = COPY killed %39:gpr
+  %3:gpr = COPY killed %38:gpr
&lt;/span&gt;   %25:gpr = nuw nsw SLLI %4:gpr, 2
   %26:gpr = ADD killed %25:gpr, %19:gpr
   %5:gpr = ADD killed %26:gpr, %27:gpr
   %28:gpr = OR %4:gpr, %2:gpr
   %29:gpr = SLLI killed %28:gpr, 2
   %6:gpr = ADD %20:gpr, killed %29:gpr
   %7:fpr32 = FLW %6:gpr, 0
&lt;span class=&quot;gi&quot;&gt;+  %40:gpr = COPY %0:gpr
+  %41:gpr = COPY %3:gpr
+  %42:fpr32 = COPY killed %7:fpr32
&lt;/span&gt;   PseudoBR %bb.6

 bb.4 (%ir-block.15):
   successors: %bb.2(0x04000000), %bb.1(0x7c000000);
               %bb.2(3.12%), %bb.1(96.88%)
   %8:gpr = nuw nsw ADDI killed %1:gpr, 1
   %9:gpr = ADDI killed %0:gpr, 256
&lt;span class=&quot;gd&quot;&gt;-  BEQ %8:gpr, %32:gpr, %bb.2
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %36:gpr = COPY killed %9:gpr
+  %37:gpr = COPY %8:gpr
+  BEQ killed %8:gpr, %32:gpr, %bb.2
&lt;/span&gt;   PseudoBR %bb.1

 bb.5 (%ir-block.18):
   successors: %bb.4(0x04000000), %bb.3(0x7c000000);
               %bb.4(3.12%), %bb.3(96.88%)
   FSW killed %15:fpr32, killed %6:gpr, 0
   %10:gpr = nuw nsw ADDI killed %4:gpr, 1
   %11:gpr = ADDI killed %3:gpr, 4
&lt;span class=&quot;gd&quot;&gt;-  BEQ %10:gpr, %32:gpr, %bb.4
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %38:gpr = COPY killed %11:gpr
+  %39:gpr = COPY %10:gpr
+  BEQ killed %10:gpr, %32:gpr, %bb.4
&lt;/span&gt;   PseudoBR %bb.3

 bb.6 (%ir-block.21):
   successors: %bb.5(0x04000000), %bb.6(0x7c000000);
               %bb.5(3.12%), %bb.6(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  %12:gpr = PHI %0:gpr, %bb.3, %17:gpr, %bb.6
-  %13:gpr = PHI %3:gpr, %bb.3, %16:gpr, %bb.6
-  %14:fpr32 = PHI %7:fpr32, %bb.3, %15:fpr32, %bb.6
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %14:fpr32 = COPY killed %42:fpr32
+  %13:gpr = COPY killed %41:gpr
+  %12:gpr = COPY killed %40:gpr
&lt;/span&gt;   %30:fpr32 = FLW %12:gpr, 0
   %31:fpr32 = FLW %13:gpr, 0
   %15:fpr32 = nofpexcept FMADD_S killed %30:fpr32,
               killed %31:fpr32, killed %14:fpr32,
               7, implicit $frm
   %16:gpr = ADDI killed %13:gpr, 256
   %17:gpr = ADDI killed %12:gpr, 4
&lt;span class=&quot;gd&quot;&gt;-  BEQ %16:gpr, %5:gpr, %bb.5
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %40:gpr = COPY killed %17:gpr
+  %41:gpr = COPY %16:gpr
+  %42:fpr32 = COPY %15:fpr32
+  BEQ killed %16:gpr, %5:gpr, %bb.5
&lt;/span&gt;   PseudoBR %bb.6&lt;/pre&gt;
&lt;p&gt;The next pass &lt;code&gt;liveintervals&lt;/code&gt; undoes many of the &lt;code&gt;killed&lt;/code&gt; annotations inserted by &lt;code&gt;livevars&lt;/code&gt;, by performing a more sophisticated analysis to determine the actual virtual registers killed in the loop-nest.&lt;/p&gt;
&lt;p&gt;The final preparatory step before instruction scheduling and register allocation is &lt;code&gt;register-coalescer&lt;/code&gt;, which eliminates many of the COPY instructions, taking the MIR out of SSA form:&lt;/p&gt;
&lt;pre&gt; Function Live Ins: $x10 in %18, $x11 in %19, $x12 in %20

 bb.0 (%ir-block.3):
   successors: %bb.1(0x80000000); %bb.1(100.00%)
   liveins: $x10, $x11, $x12
   %20:gpr = COPY $x12
   %19:gpr = COPY $x11
&lt;span class=&quot;gd&quot;&gt;-  %18:gpr = COPY $x10
-  %22:gpr = COPY $x0
-  %21:gpr = COPY %22:gpr
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %0:gpr = COPY $x10
&lt;/span&gt;   %27:gpr = LUI 4
   %32:gpr = ADDI $x0, 64
&lt;span class=&quot;gd&quot;&gt;-  %36:gpr = COPY %18:gpr
-  %37:gpr = COPY %21:gpr
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %1:gpr = COPY $x0
&lt;/span&gt;
 bb.1 (%ir-block.4):
   successors: %bb.3(0x80000000); %bb.3(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %1:gpr = COPY %37:gpr
-  %0:gpr = COPY %36:gpr
&lt;/span&gt;   %2:gpr = nuw nsw SLLI %1:gpr, 6
&lt;span class=&quot;gd&quot;&gt;-  %24:gpr = COPY $x0
-  %23:gpr = COPY %24:gpr
-  %38:gpr = COPY %19:gpr
-  %39:gpr = COPY %23:gpr
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %3:gpr = COPY %19:gpr
+  %4:gpr = COPY $x0
&lt;/span&gt;   PseudoBR %bb.3

 bb.2 (%ir-block.7):
   PseudoRET

 bb.3 (%ir-block.8):
   successors: %bb.6(0x80000000); %bb.6(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %4:gpr = COPY %39:gpr
-  %3:gpr = COPY %38:gpr
&lt;/span&gt;   %25:gpr = nuw nsw SLLI %4:gpr, 2
   %26:gpr = ADD %25:gpr, %19:gpr
   %5:gpr = ADD %26:gpr, %27:gpr
   %28:gpr = OR %4:gpr, %2:gpr
   %29:gpr = SLLI %28:gpr, 2
   %6:gpr = ADD %20:gpr, %29:gpr
&lt;span class=&quot;gd&quot;&gt;-  %7:fpr32 = FLW %6:gpr, 0
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %42:fpr32 = FLW %6:gpr, 0
&lt;/span&gt;   %40:gpr = COPY %0:gpr
   %41:gpr = COPY %3:gpr
&lt;span class=&quot;gd&quot;&gt;-  %42:fpr32 = COPY %7:fpr32
&lt;/span&gt;   PseudoBR %bb.6

 bb.4 (%ir-block.15):
   successors: %bb.2(0x04000000), %bb.1(0x7c000000);
               %bb.2(3.12%), %bb.1(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  %8:gpr = nuw nsw ADDI %1:gpr, 1
-  %9:gpr = ADDI %0:gpr, 256
-  %36:gpr = COPY %9:gpr
-  %37:gpr = COPY %8:gpr
-  BEQ %8:gpr, %32:gpr, %bb.2
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %1:gpr = nuw nsw ADDI %1:gpr, 1
+  %0:gpr = ADDI %0:gpr, 256
+  BEQ %1:gpr, %32:gpr, %bb.2
&lt;/span&gt;   PseudoBR %bb.1

 bb.5 (%ir-block.18):
   successors: %bb.4(0x04000000), %bb.3(0x7c000000);
               %bb.4(3.12%), %bb.3(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  FSW %15:fpr32, %6:gpr, 0
-  %10:gpr = nuw nsw ADDI %4:gpr, 1
-  %11:gpr = ADDI %3:gpr, 4
-  %38:gpr = COPY %11:gpr
-  %39:gpr = COPY %10:gpr
-  BEQ %10:gpr, %32:gpr, %bb.4
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  FSW %42:fpr32, %6:gpr, 0
+  %4:gpr = nuw nsw ADDI %4:gpr, 1
+  %3:gpr = ADDI %3:gpr, 4
+  BEQ %4:gpr, %32:gpr, %bb.4
&lt;/span&gt;   PseudoBR %bb.3

 bb.6 (%ir-block.21):
   successors: %bb.5(0x04000000), %bb.6(0x7c000000);
               %bb.5(3.12%), %bb.6(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  %14:fpr32 = COPY %42:fpr32
-  %13:gpr = COPY %41:gpr
-  %12:gpr = COPY %40:gpr
-  %30:fpr32 = FLW %12:gpr, 0
-  %31:fpr32 = FLW %13:gpr, 0
-  %15:fpr32 = nofpexcept FMADD_S %30:fpr32,
-              %31:fpr32, %14:fpr32, 7, implicit $frm
-  %16:gpr = ADDI %13:gpr, 256
-  %17:gpr = ADDI %12:gpr, 4
-  %40:gpr = COPY %17:gpr
-  %41:gpr = COPY %16:gpr
-  %42:fpr32 = COPY %15:fpr32
-  BEQ %16:gpr, %5:gpr, %bb.5
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  %30:fpr32 = FLW %40:gpr, 0
+  %31:fpr32 = FLW %41:gpr, 0
+  %42:fpr32 = nofpexcept FMADD_S %30:fpr32,
+              %31:fpr32, %42:fpr32, 7, implicit $frm
+  %41:gpr = ADDI %41:gpr, 256
+  %40:gpr = ADDI %40:gpr, 4
+  BEQ %41:gpr, %5:gpr, %bb.5
&lt;/span&gt;   PseudoBR %bb.6&lt;/pre&gt;
&lt;p&gt;The purpose of the instruction scheduler, &lt;code&gt;machine-scheduler&lt;/code&gt;, is to re-order instructions to minimize hazards and stalls. The optimal schedule depends on micro-architectural details, and an example of a scheduler descriptor is &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/RISCV/RISCVSchedSiFive7.td&quot;&gt;RISCVSchedSiFive7.td&lt;/a&gt;, for the SiFive 7 CPU. In our invocation of Clang, we did not specify a particular CPU, so some generic information for RISC-V is used. The optimal schedule can be seen in the following diff:&lt;/p&gt;
&lt;pre&gt; Function Live Ins: $x10 in %18, $x11 in %19, $x12 in %20

 bb.0 (%ir-block.3):
   successors: %bb.1(0x80000000); %bb.1(100.00%)
   liveins: $x10, $x11, $x12
   %20:gpr = COPY $x12
   %19:gpr = COPY $x11
   %0:gpr = COPY $x10
&lt;span class=&quot;gi&quot;&gt;+  %1:gpr = COPY $x0
&lt;/span&gt;   %27:gpr = LUI 4
   %32:gpr = ADDI $x0, 64
&lt;span class=&quot;gd&quot;&gt;-  %1:gpr = COPY $x0
&lt;/span&gt;
 bb.1 (%ir-block.4):
   successors: %bb.3(0x80000000); %bb.3(100.00%)
&lt;span class=&quot;gi&quot;&gt;+  %4:gpr = COPY $x0
&lt;/span&gt;   %2:gpr = nuw nsw SLLI %1:gpr, 6
   %3:gpr = COPY %19:gpr
&lt;span class=&quot;gd&quot;&gt;-  %4:gpr = COPY $x0
&lt;/span&gt;   PseudoBR %bb.3

 bb.2 (%ir-block.7):
   PseudoRET

 bb.3 (%ir-block.8):
   successors: %bb.6(0x80000000); %bb.6(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %25:gpr = nuw nsw SLLI %4:gpr, 2
-  %26:gpr = ADD %25:gpr, %19:gpr
-  %5:gpr = ADD %26:gpr, %27:gpr
&lt;/span&gt;   %28:gpr = OR %4:gpr, %2:gpr
   %29:gpr = SLLI %28:gpr, 2
   %6:gpr = ADD %20:gpr, %29:gpr
   %42:fpr32 = FLW %6:gpr, 0
&lt;span class=&quot;gi&quot;&gt;+  %25:gpr = nuw nsw SLLI %4:gpr, 2
+  %26:gpr = ADD %25:gpr, %19:gpr
+  %5:gpr = ADD %26:gpr, %27:gpr
&lt;/span&gt;   %40:gpr = COPY %0:gpr
   %41:gpr = COPY %3:gpr
   PseudoBR %bb.6

 bb.4 (%ir-block.15):
   successors: %bb.2(0x04000000), %bb.1(0x7c000000);
               %bb.2(3.12%), %bb.1(96.88%)
   %1:gpr = nuw nsw ADDI %1:gpr, 1
   %0:gpr = ADDI %0:gpr, 256
   BEQ %1:gpr, %32:gpr, %bb.2
   PseudoBR %bb.1

 bb.5 (%ir-block.18):
   successors: %bb.4(0x04000000), %bb.3(0x7c000000);
               %bb.4(3.12%), %bb.3(96.88%)
   FSW %42:fpr32, %6:gpr, 0
   %4:gpr = nuw nsw ADDI %4:gpr, 1
   %3:gpr = ADDI %3:gpr, 4
   BEQ %4:gpr, %32:gpr, %bb.4
   PseudoBR %bb.3

 bb.6 (%ir-block.21):
   successors: %bb.5(0x04000000), %bb.6(0x7c000000);
               %bb.5(3.12%), %bb.6(96.88%)
   %30:fpr32 = FLW %40:gpr, 0
   %31:fpr32 = FLW %41:gpr, 0
   %42:fpr32 = nofpexcept FMADD_S %30:fpr32, %31:fpr32,
               %42:fpr32, 7, implicit $frm
   %41:gpr = ADDI %41:gpr, 256
   %40:gpr = ADDI %40:gpr, 4
   BEQ %41:gpr, %5:gpr, %bb.5
   PseudoBR %bb.6&lt;/pre&gt;
&lt;p&gt;We&#39;re now ready to run the &lt;code&gt;greedy&lt;/code&gt; register allocator †, whose purpose is to assign every virtual register a physical register, while re-using the limited number of physical registers on the machine, and minimizing register spills. The actual replacement is done by &lt;code&gt;virtregrewriter&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt; Function Live Ins: $x10, $x11, $x12

 bb.0 (%ir-block.3):
   successors: %bb.1(0x80000000); %bb.1(100.00%)
   liveins: $x10, $x11, $x12
&lt;span class=&quot;gd&quot;&gt;-  %20:gpr = COPY $x12
-  %19:gpr = COPY $x11
-  %0:gpr = COPY $x10
-  %1:gpr = COPY $x0
-  %27:gpr = LUI 4
-  %32:gpr = ADDI $x0, 64
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  renamable $x16 = COPY $x0
+  renamable $x17 = LUI 4
+  renamable $x5 = ADDI $x0, 64
&lt;/span&gt;
 bb.1 (%ir-block.4):
   successors: %bb.3(0x80000000); %bb.3(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %4:gpr = COPY $x0
-  %2:gpr = nuw nsw SLLI %1:gpr, 6
-  %3:gpr = COPY %19:gpr
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  liveins: $x5, $x10, $x11, $x12, $x16, $x17
+  renamable $x29 = COPY $x0
+  renamable $x6 = nuw nsw SLLI renamable $x16, 6
+  renamable $x28 = COPY renamable $x11
&lt;/span&gt;   PseudoBR %bb.3

 bb.2 (%ir-block.7):
 ; predecessors: %bb.4

   PseudoRET

 bb.3 (%ir-block.8):
   successors: %bb.6(0x80000000); %bb.6(100.00%)
&lt;span class=&quot;gd&quot;&gt;-  %28:gpr = OR %4:gpr, %2:gpr
-  %29:gpr = SLLI %28:gpr, 2
-  %6:gpr = ADD %20:gpr, %29:gpr
-  %42:fpr32 = FLW %6:gpr, 0
-  %25:gpr = nuw nsw SLLI %4:gpr, 2
-  %26:gpr = ADD %25:gpr, %19:gpr
-  %5:gpr = ADD %26:gpr, %27:gpr
-  %40:gpr = COPY %0:gpr
-  %41:gpr = COPY %3:gpr
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  liveins: $x5, $x6, $x10, $x11, $x12, $x16, $x17, $x28, $x29
+  renamable $x13 = OR renamable $x29, renamable $x6
+  renamable $x13 = SLLI killed renamable $x13, 2
+  renamable $x7 = ADD renamable $x12, killed renamable $x13
+  renamable $f15_f = FLW renamable $x7, 0
+  renamable $x13 = nuw nsw SLLI renamable $x29, 2
+  renamable $x13 = ADD killed renamable $x13, renamable $x11
+  renamable $x14 = ADD killed renamable $x13, renamable $x17
+  renamable $x15 = COPY renamable $x10
+  renamable $x13 = COPY renamable $x28
&lt;/span&gt;   PseudoBR %bb.6

 bb.4 (%ir-block.15):
   successors: %bb.2(0x04000000), %bb.1(0x7c000000);
               %bb.2(3.12%), %bb.1(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  %1:gpr = nuw nsw ADDI %1:gpr, 1
-  %0:gpr = ADDI %0:gpr, 256
-  BEQ %1:gpr, %32:gpr, %bb.2
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  liveins: $x5, $x10, $x11, $x12, $x16, $x17
+  renamable $x16 = nuw nsw ADDI killed renamable $x16, 1
+  renamable $x10 = ADDI killed renamable $x10, 256
+  BEQ renamable $x16, renamable $x5, %bb.2
&lt;/span&gt;   PseudoBR %bb.1

 bb.5 (%ir-block.18):
   successors: %bb.4(0x04000000), %bb.3(0x7c000000);
               %bb.4(3.12%), %bb.3(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  FSW %42:fpr32, %6:gpr, 0
-  %4:gpr = nuw nsw ADDI %4:gpr, 1
-  %3:gpr = ADDI %3:gpr, 4
-  BEQ %4:gpr, %32:gpr, %bb.4
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  liveins: $x5, $x6, $x7, $x10, $x11, $x12, $x16,
+           $x17, $x28, $x29, $f15_f
+  FSW killed renamable $f15_f, killed renamable $x7, 0
+  renamable $x29 = nuw nsw ADDI killed renamable $x29, 1
+  renamable $x28 = ADDI killed renamable $x28, 4
+  BEQ renamable $x29, renamable $x5, %bb.4
&lt;/span&gt;   PseudoBR %bb.3

 bb.6 (%ir-block.21):
   successors: %bb.5(0x04000000), %bb.6(0x7c000000);
               %bb.5(3.12%), %bb.6(96.88%)
&lt;span class=&quot;gd&quot;&gt;-  %30:fpr32 = FLW %40:gpr, 0
-  %31:fpr32 = FLW %41:gpr, 0
-  %42:fpr32 = nofpexcept FMADD_S %30:fpr32, %31:fpr32,
-              %42:fpr32, 7, implicit $frm
-  %41:gpr = ADDI %41:gpr, 256
-  %40:gpr = ADDI %40:gpr, 4
-  BEQ %41:gpr, %5:gpr, %bb.5
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+  liveins: $x5, $x6, $x7, $x10, $x11, $x12, $x13, $x14,
+           $x15, $x16, $x17, $x28, $x29, $f15_f
+  renamable $f14_f = FLW renamable $x15, 0
+  renamable $f13_f = FLW renamable $x13, 0
+  renamable $f15_f = nofpexcept FMADD_S killed renamable $f14_f,
+                     killed renamable $f13_f, killed renamable $f15_f,
+                     7, implicit $frm
+  renamable $x13 = ADDI killed renamable $x13, 256
+  renamable $x15 = ADDI killed renamable $x15, 4
+  BEQ renamable $x13, renamable $x14, %bb.5
&lt;/span&gt;   PseudoBR %bb.6&lt;/pre&gt;
&lt;p&gt;Before we emit the assembly, there are two pending steps: first, basic blocks need to be re-ordered, so that the final structure is flat and there are no unnecessary jumps; second, pseudo-instructions like COPY need to be replaced by real instructions. The final MIR after &lt;code&gt;branch-folder&lt;/code&gt; and &lt;code&gt;postrapseduos&lt;/code&gt; is:&lt;/p&gt;
&lt;pre&gt;Function Live Ins: $x10, $x11, $x12

bb.0 (%ir-block.3):
  successors: %bb.1(0x80000000); %bb.1(100.00%)
  liveins: $x10, $x11, $x12
  $x16 = ADDI $x0, 0
  renamable $x17 = LUI 4
  renamable $x5 = ADDI $x0, 64

bb.1 (%ir-block.4):
  successors: %bb.2(0x80000000); %bb.2(100.00%)
  liveins: $x5, $x10, $x11, $x12, $x16, $x17
  $x29 = ADDI $x0, 0
  renamable $x6 = nuw nsw SLLI renamable $x16, 6
  $x28 = ADDI $x11, 0

bb.2 (%ir-block.8):
  successors: %bb.3(0x80000000); %bb.3(100.00%)
  liveins: $x5, $x6, $x10, $x11, $x12, $x16, $x17, $x28, $x29
  renamable $x13 = OR renamable $x29, renamable $x6
  renamable $x13 = SLLI killed renamable $x13, 2
  renamable $x7 = ADD renamable $x12, killed renamable $x13
  renamable $f15_f = FLW renamable $x7, 0
  renamable $x13 = nuw nsw SLLI renamable $x29, 2
  renamable $x13 = ADD killed renamable $x13, renamable $x11
  renamable $x14 = ADD killed renamable $x13, renamable $x17
  $x15 = ADDI $x10, 0
  $x13 = ADDI $x28, 0

bb.3 (%ir-block.21):
  successors: %bb.4(0x04000000), %bb.3(0x7c000000);
              %bb.4(3.12%), %bb.3(96.88%)
  liveins: $x5, $x6, $x7, $x10, $x11, $x12, $x13, $x14,
           $x15, $x16, $x17, $x28, $x29, $f15_f
  renamable $f14_f = FLW renamable $x15, 0
  renamable $f13_f = FLW renamable $x13, 0
  renamable $f15_f = nofpexcept FMADD_S killed renamable $f14_f,
                     killed renamable $f13_f, killed renamable $f15_f,
                     7, implicit $frm
  renamable $x13 = ADDI killed renamable $x13, 256
  renamable $x15 = ADDI killed renamable $x15, 4
  BNE renamable $x13, renamable $x14, %bb.3

bb.4 (%ir-block.18):
  successors: %bb.5(0x04000000), %bb.2(0x7c000000);
              %bb.5(3.12%), %bb.2(96.88%)
  liveins: $x5, $x6, $x7, $x10, $x11, $x12, $x16, $x17, $x28, $x29, $f15_f
  FSW killed renamable $f15_f, killed renamable $x7, 0
  renamable $x29 = nuw nsw ADDI killed renamable $x29, 1
  renamable $x28 = ADDI killed renamable $x28, 4
  BNE renamable $x29, renamable $x5, %bb.2

bb.5 (%ir-block.15):
  successors: %bb.6(0x04000000), %bb.1(0x7c000000);
              %bb.6(3.12%), %bb.1(96.88%)
  liveins: $x5, $x10, $x11, $x12, $x16, $x17
  renamable $x16 = nuw nsw ADDI killed renamable $x16, 1
  renamable $x10 = ADDI killed renamable $x10, 256
  BNE renamable $x16, renamable $x5, %bb.1

bb.6 (%ir-block.7):
  PseudoRET&lt;/pre&gt;
&lt;p&gt;The assembly is produced from the final MIR by AsmPrinter, which doesn&#39;t do much more than pretty-printing registers (&lt;code&gt;$x10&lt;/code&gt; is &lt;code&gt;a0&lt;/code&gt;, &lt;code&gt;$x11&lt;/code&gt; is &lt;code&gt;a1&lt;/code&gt;), and instructions (&lt;code&gt;FMADD_S&lt;/code&gt; is &lt;code&gt;fmadd.s&lt;/code&gt;), while dropping auxiliary information. This output can be checked against the &lt;a href=&quot;https://github.com/riscv/riscv-isa-manual/&quot;&gt;RISC-V ISA manual&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;matmul:                                 # @matmul
# %bb.0:
  li a6, 0
  lui   a7, 4
  li t0, 64
.LBB0_1:                                # =&gt;This Loop Header: Depth=1
                                        #     Child Loop BB0_2 Depth 2
                                        #       Child Loop BB0_3 Depth 3
  li t4, 0
  slli  t1, a6, 6
  mv t3, a1
.LBB0_2:                                #   Parent Loop BB0_1 Depth=1
                                        # =&gt;  This Loop Header: Depth=2
                                        #       Child Loop BB0_3 Depth 3
  or a3, t4, t1
  slli  a3, a3, 2
  add   t2, a2, a3
  flw   fa5, 0(t2)
  slli  a3, t4, 2
  add   a3, a3, a1
  add   a4, a3, a7
  mv a5, a0
  mv a3, t3
.LBB0_3:                                #   Parent Loop BB0_1 Depth=1
                                        #     Parent Loop BB0_2 Depth=2
                                        # =&gt;    This Inner Loop Header: Depth=3
  flw   fa4, 0(a5)
  flw   fa3, 0(a3)
  fmadd.s fa5, fa4, fa3, fa5
  addi  a3, a3, 256
  addi  a5, a5, 4
  bne   a3, a4, .LBB0_3
# %bb.4:                                #   in Loop: Header=BB0_2 Depth=2
  fsw   fa5, 0(t2)
  addi  t4, t4, 1
  addi  t3, t3, 4
  bne   t4, t0, .LBB0_2
# %bb.5:                                #   in Loop: Header=BB0_1 Depth=1
  addi  a6, a6, 1
  addi  a0, a0, 256
  bne   a6, t0, .LBB0_1
# %bb.6:
  ret&lt;/pre&gt;
&lt;p&gt;There is an alternative instruction selection framework called GlobalISel, and alternative register allocation algorithms in LLVM.&lt;/p&gt;</summary>
    <title>A tour of the LLVM backend</title>
    <updated>2024-08-04T21:35:05+01:00</updated>
    <dc:date>2024-08-04T21:35:05+01:00</dc:date>
  </entry>
  <entry>
    <id>compilers/incrd</id>
    <link href="compilers/incrd"/>
    <summary>&lt;p&gt;An input program function is represented using a Control Flow Graph (CFG). It&#39;s composed of different Statements, which decompose into Expressions, but we will not concern ourselves with Expressions. The main control flow constructs are SplitStatement and MergeStatement. The SplitStatement has outgoing edges to N (N = 2 in the case of IfStatement) other Statements, and the MergeStatement has incoming edges from M other Statements.&lt;/p&gt;
&lt;p&gt;The Dominator is a data structure that holds &quot;domination relationship&quot; between any two Statements in the CFG. &quot;A dominates B&quot; means: all paths starting from the start of the CFG to end of the CFG, that flow through A, must necessarily flow through B. It&#39;s represented using a tree of things that progressively dominate their children. We want to incrementally update this structure.&lt;/p&gt;
&lt;h3&gt;Motivation&lt;/h3&gt;
&lt;p&gt;Any code motion transform will invalidate the Dominator at each step, and running Cooper or Lengauer-Tarjan on each invalidation is expensive even if the algorithm is near-linear. The number of queries is several times the number of reconstructions; we cannot trade off query-efficiency for ease-of-update.&lt;/p&gt;
&lt;h3&gt;Background&lt;/h3&gt;
&lt;p&gt;The main supporting data structure we will use for this feat is the Program Structure Tree, which is incrementally updated. The PST is a tree representation of structured control flow: all Control Flow Graph nodes belong to a Region in a nesting of single-entry single-exit Regions. Any control-flow that cannot be classified is boxed in an UnstructuredRegion, which we will not handle.&lt;/p&gt;
&lt;p&gt;This is a Region:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This is a ChainRegion comprising of an IfRegion and a BasicBlockRegion:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;quux&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This is an UnstructuredRegion, but it is very much SESE:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nl&quot;&gt;jump:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Updating a vanilla Dominator tree is relatively easy: simply add a child to the correct node. The problem at hand is that we have an O(1)-query Dominator object that we want to keep up to date as we make edits to the IR. How is it O(1)-query? Every node in the tree is assigned DFS start and end times: so if one interval nests within another, the corresponding node is dominated by the other node.&lt;/p&gt;
&lt;p&gt;Supporting arbitrary IR edits is both very hard and not a useful goal: we can reduce all our edits to two items, namely inserting a SESE Statement, and inserting a SESE PST Region. Removing a Statement or Region is not interesting, because it just leaves gaps in the numbering, and doesn&#39;t affect any existing Dominance relationships if we make no changes after removal. Modifying a Region can be easily expressed as the removal of the old Region/insertion of the new Region.&lt;/p&gt;
&lt;p&gt;The PST gives us an excellent mechanism to classify the blob we&#39;re injecting into the CFG. The interesting Regions begin with a SplitStatement, and end with a MergeStatement, or begin with a MergeStatement and end with a SpiltStatement: IfRegions, SwitchRegions, and LoopRegions. This is the key property we will use to do the incremental update.&lt;/p&gt;
&lt;h3&gt;Possible approaches&lt;/h3&gt;
&lt;p&gt;First, it must be noted that by using tight consecutive DFS start and end timers, we will have no choice but to renumber the descendant tree when something is inserted. So, we leave gaps of 64 between the numbering, to stuff our new SESE Statement or Region into. It may be argued that using fractions is profitable, but we found that space to fit intervals wasn&#39;t the bottleneck: the hard problem is determining dominance. When attempting to stuff a new Region into an existing gap, we can imagine centering around the midpoint of the gap, and leaving space for more Regions above and below. Bisecting each gap will exhaust the gaps quickly, and we decided to optimize for insertion only from top to bottom.&lt;/p&gt;
&lt;p&gt;One approach we could take is to assume that the Region-to-be-inserted has been removed from a different part of the tree, and has some numbers already that we simply need to adjust them (those numbers will be spaced with gaps of 64, and we need to compress them). This approach wouldn&#39;t be able to handle newly created Regions.&lt;/p&gt;
&lt;h3&gt;Our algorithm&lt;/h3&gt;
&lt;p&gt;The key insight in our algorithm is that we need to match a Split Statement with its Merge Statement(s), and need to partition our DFS start/end time intervals into two categories: intervals to trust (ie. ones that exist, and should not be modified), and intervals to assign. The DFS start time corresponds to DFS first-visit sequence, and end time corresponds to DFS final-visit sequence. &lt;code&gt;interval1.start_time &amp;gt; interval2.start_time&lt;/code&gt; and &lt;code&gt;interval1.end_time &amp;lt; interval2.end_time&lt;/code&gt; means that interval1 is nested within interval2, or that the node corresponding to interval2 dominates the node corresponding to interval1.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DFS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign_start_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// increment a clock as you assign&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outEdges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_time_not_assigned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DFS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign_end_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// increment a clock as you assign&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The reason we need to match a Split to a Merge is that there are two cases:&lt;/p&gt;
&lt;p&gt;The Merge dominates the Split, in which case, the Merge dominates everything lying on the outEdges of the Split leading to the Merge.
The Split dominates the Merge, in which case, the Split dominates everything on its outEdges leading to the Merge.&lt;/p&gt;
&lt;p&gt;The intervals of the each of the outEdges (&quot;branches&quot;) must stagger with each other so there&#39;s no false dominance relationship between them. Two intervals &quot;staggering&quot; means one not being nested within the other. In the case of Split-dominates-Merge, they must additionally stagger with the Merge.&lt;/p&gt;
&lt;p&gt;Our API looks like:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;assignHeads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Statement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branchHeads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Statement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headsToStaggerWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;Statement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nestWithin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Statement&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toEnclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;First, we assign intervals to the split and merge Statements in the Region, by looking at their predecessor and successor. The predecessor is something we need to nest within. Since we decided that we&#39;ll only optimize for the case of top-to-bottom insertion, we can simply add one to the start time, and subtract one from the end time to get the necessary start and end times for the Region entry. For the Region exit, it&#39;s a little more tricky: we need to leave gaps on either side, because there may be nodes along the inEdge(s) as well as nodes along the outEdge(s). For simplicity, let&#39;s simply assign an interval halfway between the Region entry and successor intervals.&lt;/p&gt;
&lt;p&gt;Then, we assign intervals to be &lt;code&gt;branchHeads&lt;/code&gt; (ie. successors of the SplitStatement whose intervals we need to assign), by staggering with the &lt;code&gt;headsToStaggerWith&lt;/code&gt; (ie. successors of the SplitStmt whose intervals we must trust + the MergeStatement if Split-dominates-Merge). &lt;code&gt;nestWithin&lt;/code&gt; is the SplitStatement, and &lt;code&gt;toEnclose&lt;/code&gt; is &lt;code&gt;nullptr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we trivially assign intervals to the rest of the Stmts in the Region, following the Split, by nesting them within the branch heads.&lt;/p&gt;
&lt;p&gt;Now, this API generalizes to SESE Statements as well. &lt;code&gt;branchHeads&lt;/code&gt; is the singular SESE Statement, &lt;code&gt;headsToStaggerWith&lt;/code&gt; may or may not include the containing Region&#39;s MergeStatement. &lt;code&gt;headsToStaggerWith&lt;/code&gt; will contain all the other successors of the &lt;code&gt;SplitStatement&lt;/code&gt;, if the SESE Statement is one of the successors, and may contain the MergeStatement. If the successor has one inEdge, it&#39;s used as &lt;code&gt;toEnclose&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The actual interval calculation is quite simple. Subtract the &lt;code&gt;staggerUnion&lt;/code&gt; interval (union of all the stagger intervals) from the &lt;code&gt;nestWithin&lt;/code&gt; interval: this produces two &quot;gaps&quot; which we need to &quot;dice up&quot; into N intervals (where N is the number of &lt;code&gt;branchHeads&lt;/code&gt;). The number of intervals in the left gap versus the right gap is dependent on the ratio of the sizes of the gaps. &lt;code&gt;toEnclose&lt;/code&gt; simply tells us whether to pick the left gap or right gap in the case of a single &lt;code&gt;branchHead&lt;/code&gt;. It&#39;s also useful to check interval exhaustion cases.&lt;/p&gt;
&lt;p&gt;There is an elegant way to catch all the cases when the interval has been exhausted. Just &lt;code&gt;throw&lt;/code&gt; an exception from the interval-construction class. Catch this exception and abort the incremental update: recompute the Dominator.&lt;/p&gt;
&lt;h3&gt;Closing notes&lt;/h3&gt;
&lt;p&gt;Conceptually, the algorithm is simple. The implementation, as leveraged by one transform, passes our entire testsuite (~6k tests).&lt;/p&gt;
&lt;p&gt;Our implementation of the Dominator incremental update relies on a correct implementation of the PST incremental update: incorrect information from one incremental update will propagate to the other incremental update and wreak havoc.&lt;/p&gt;
&lt;p&gt;The best way to test the implementation is to have a recomputed Dominator as reference, and checking that the dominates-relationship between every two nodes is the same in the incremental update and re-computation case.&lt;/p&gt;
&lt;p&gt;Thanks to Sanjoy Das for reviewing the draft.&lt;/p&gt;</summary>
    <title>Incrementally updating the Dominator</title>
    <updated>2016-10-09T16:28:58-05:00</updated>
    <dc:date>2016-10-09T16:28:58-05:00</dc:date>
  </entry>
  <entry>
    <id>compilers/intro-vec</id>
    <link href="compilers/intro-vec"/>
    <summary>&lt;p&gt;Most modern general purpose CPUs have a vector processing unit (VPU). This unit contains vector registers that can hold multiple integers or floats, and instructions that operate on vector registers. Given two vector registers containing N floats each †, the VPU can perform a single instruction to operate on these two vector registers and store the result in another vector register. Without a VPU, this operation would require N instructions operating on two floating-point registers each relying on the floating-point unit (FPU), or arithmetic logic unit (ALU) in the case of integers.&lt;/p&gt;
&lt;p&gt;Major instruction set architectures have vector extensions, and corresponding instructions for the VPU. Examples include x86&#39;s SSE/AVX, AArch64&#39;s SVE/Neon, and the latest entrant is RISC-V&#39;s RVV. In order to generate vector instructions, the programmer could adapt their code to use standardized vector intrinsics. To illustrate, suppose the programmer had the following source code:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;saxpy_golden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;If they wanted to use &lt;a href=&quot;https://github.com/riscv-non-isa/rvv-intrinsic-doc&quot;&gt;RISC-V vector intrinsics&lt;/a&gt; to vectorize it, this is how they would adapt the code:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;saxpy_vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__riscv_vsetvl_e32m8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vfloat32m8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__riscv_vle32_v_f32m8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vfloat32m8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__riscv_vle32_v_f32m8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;__riscv_vse32_v_f32m8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__riscv_vfmacc_vf_f32m8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;As is evident, this process of hand-vectorizing code is very difficult and error-prone for non-trivial programs. The process is analogous to writing assembly instead of writing the source language and letting the compiler generate assembly. Indeed, compilers today auto-vectorize code, and for the purposes of illustration, let us use Clang/LLVM. First, the source language is lowered to target-independent LLVM IR by Clang, which is the frontend. Next, the vectorizers in the middle-end of LLVM operate on this LLVM IR without vectors in them, and produce LLVM IR with vectors in them. The vectorized LLVM IR is finally lowered to target-specific assembly by the backend of LLVM.&lt;/p&gt;
&lt;p&gt;Let us take the same example of &lt;code&gt;saxpy_golden&lt;/code&gt;, and see how the loop looks in LLVM IR without vectorization:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nl&quot;&gt;loop:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%fmuladd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;@llvm.fmuladd.f32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%fmuladd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%exitcond&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;icmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%n&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exitcond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The first line, &lt;code&gt;loop:&lt;/code&gt;, is like a label in C, to which branch instructions (&lt;code&gt;br&lt;/code&gt;) can jump to. The next line is creating a new variable &lt;code&gt;%iv&lt;/code&gt; using a &lt;code&gt;phi&lt;/code&gt; to select either &lt;code&gt;0&lt;/code&gt; when jumping from the &lt;code&gt;entry&lt;/code&gt; block (not shown), or &lt;code&gt;%iv.next&lt;/code&gt; when jumping from the back-edge of the loop: this is the induction variable of the loop. Since &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are pointers (marked by the type &lt;code&gt;ptr&lt;/code&gt;), we see &lt;code&gt;getelementptr&lt;/code&gt; instructions that act as the address computations: so, &lt;code&gt;%gep.x&lt;/code&gt; is &lt;code&gt;%x + %iv&lt;/code&gt;, and &lt;code&gt;%gep.y&lt;/code&gt; is &lt;code&gt;%y + %iv&lt;/code&gt;. The &lt;code&gt;load&lt;/code&gt; instructions derefence the pointer: so, &lt;code&gt;%load.x&lt;/code&gt; is &lt;code&gt;x[iv]&lt;/code&gt; and &lt;code&gt;load.y&lt;/code&gt; is &lt;code&gt;y[iv]&lt;/code&gt;; both are of type &lt;code&gt;f32&lt;/code&gt;, or &lt;code&gt;float&lt;/code&gt;. &lt;code&gt;@llvm.fmuladd.f32&lt;/code&gt; is the computation, which does a &lt;code&gt;a * x[iv] + y[iv]&lt;/code&gt;, and the &lt;code&gt;store&lt;/code&gt; writes the result &lt;code&gt;%fmuladd&lt;/code&gt; back into &lt;code&gt;%gep.y&lt;/code&gt;. The last three instructions make the &lt;code&gt;loop&lt;/code&gt; block a loop: &lt;code&gt;%iv.next = %iv + 1&lt;/code&gt; is the &quot;next value&quot; of the loop induction variable, and &lt;code&gt;%exitcond&lt;/code&gt; is a boolean (marked by the type &lt;code&gt;i1&lt;/code&gt;, integer with bitwidth 1) that acts as the exit-condition of the loop. &lt;code&gt;%exitcond&lt;/code&gt; is computed as an integer-equal-comparison between &lt;code&gt;%iv.next&lt;/code&gt; and &lt;code&gt;%n&lt;/code&gt;, where &lt;code&gt;n&lt;/code&gt; is the total number of iterations of the loop. Finally, there is a branch instruction that jumps to either the &lt;code&gt;exit&lt;/code&gt; block (not shown), or back to the &lt;code&gt;loop&lt;/code&gt; block (this is the back-edge of the loop), depending on the exit condtion.&lt;/p&gt;
&lt;p&gt;This is how it changes after vectorization:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nl&quot;&gt;loop.preaheder:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%n.and.minus4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;-4&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%a.vec.tmp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;insertelement&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%a.vec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;shufflevector&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%a.vec.tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;zeroinitializer&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;loop:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop.preaheder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%fmuladd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;@llvm.fmuladd.v4f32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%a.vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%fmuladd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%exitcond&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;icmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%n.and.minus4&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exitcond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The loop now has a &lt;code&gt;loop.preheader&lt;/code&gt; block containing an &lt;code&gt;%n.and.minus4&lt;/code&gt; to handle the case when &lt;code&gt;n&lt;/code&gt; is not a multiple of four. It also contains an &lt;code&gt;insertelement&lt;/code&gt; and &lt;code&gt;shufflevector&lt;/code&gt;, which essentially fill the vector &lt;code&gt;%a.vec&lt;/code&gt; (that has type &lt;code&gt;&amp;lt;4 x float&amp;gt;&lt;/code&gt;) with four copies of &lt;code&gt;%a&lt;/code&gt;. The difference in the loop is that &lt;code&gt;%iv.next&lt;/code&gt; is now &lt;code&gt;%iv + 4&lt;/code&gt;, since it operates on four floats at a time, cutting the number of iterations by a factor of four. The &lt;code&gt;load&lt;/code&gt; instructions are now loading four floats at a time, and the vector variant of &lt;code&gt;@llvm.fmuladd.f32&lt;/code&gt;, which is &lt;code&gt;@llvm.fmuladd.v4f32&lt;/code&gt;, does a &lt;code&gt;%a.vec * %load.x + %load.y&lt;/code&gt;, operating on a vector of four floats at a time.&lt;/p&gt;
&lt;p&gt;The vectorizer in LLVM is quite sophisticated, and it is fascinating how it manages to vectorize non-trivial examples. To walk through a simple but non-trivial example, consider:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Inspecting the &lt;a href=&quot;https://godbolt.org/z/qq39c1PT7&quot;&gt;output&lt;/a&gt;, we can see what the vectorizer has done. First, we see a new &lt;code&gt;phi&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;%vec.ind&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%vector.ph&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%vec.ind.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%vector.body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;It has created a new vector induction variable vector, corresponding to &lt;code&gt;i&lt;/code&gt;, with four elements, since it has decided to vectorize with a factor of 4. Since &lt;code&gt;%vec.ind&lt;/code&gt; is an integer, and the vectors are &lt;code&gt;float&lt;/code&gt;, it has done a integer-to-floating-point conversion:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;%10&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;uitofp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%9&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;For the conditional itself, it has used a &lt;code&gt;select&lt;/code&gt; to choose either &lt;code&gt;0&lt;/code&gt; or the loaded value:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;%15&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;zeroinitializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%wide.load1&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;For the rest of this article, let us inspect some factors that could get in the way when the loop is expected to be vectorized, omitting cases where the loop is either obviously impossible or unprofitable to vectorize.&lt;/p&gt;
&lt;p&gt;The iteration count. In most real-world code, the exact iteration count is unknown and the auto-vectorizers can deal with this. Auto-vectorizers can also deal with non-power-of-2 iteration counts by inserting a scalar epilogue with the remaining iterations. However, if the iteration count of the loop is computable and too small, the loop might get unrolled instead of vectorized.
Aliasing information. If there isn&#39;t sufficient information to determine whether memory accesses in the loop are aliased to each other, runtime checks may be generated, or auto-vectorization might fail completely because insertion of runtime checks make it unprofitable to vectorize.&lt;/p&gt;
&lt;p&gt;To illustrate, let&#39;s modify &lt;code&gt;saxpy_golden&lt;/code&gt; as follows:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Then, running &lt;code&gt;clang -O3 -fno-unroll-loops -mllvm -vectorize-loops=false -emit-llvm -S test.c -o test.ll&lt;/code&gt; followed by &lt;code&gt;opt -passes=loop-vectorize -debug-only=loop-vectorize test.ll&lt;/code&gt; &lt;a href=&quot;https://godbolt.org/z/8jn95qbxT&quot;&gt;outputs&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;LV: Found a loop with a very small trip count.
  This loop is worth vectorizing only if no
  scalar iteration overheads are incurred.
LV: Found trip count: 3
LV: Not vectorizing&lt;/pre&gt;
&lt;p&gt;The overhead it is talking about is runtime checks it needs to add. Adding &lt;code&gt;restrict&lt;/code&gt; to the pointers would remove the overhead, and allow it to be vectorized:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saxpy_golden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Even if we were to ramp up the iteration count to &lt;code&gt;17&lt;/code&gt;, unrolling the loop would be preferred over vectorization. Forcing it not to unroll loops using &lt;code&gt;-fno-unroll-loops&lt;/code&gt; as before results in successful vectorization. The final &lt;a href=&quot;https://godbolt.org/z/3Torh4ddE&quot;&gt;output&lt;/a&gt; contains a scalar version of the loop as well, marked by &lt;code&gt;scalar.ph&lt;/code&gt;, which is required as 17 isn&#39;t divisible by 4.&lt;/p&gt;
&lt;p&gt;The memory access pattern. A good rule of thumb write loops with uniform row-major access, and avoid complex indexing arithmetic.&lt;/p&gt;
&lt;p&gt;The vectorizer has no issues with the following case:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&#39;s change the assignment statement in the loop to:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This is unfortunately not vectorized by LLVM, but there is no reason this is not theoretically vectorizable. The reason for this is that an analysis that is used to prove legality of vectorization in LLVM, called LoopAccessAnalysis, is unable to find the bounds of the memory access. Running &lt;code&gt;opt -passes=loop-vectorize test.ll -disable-output -debug-only=loop-accesses&lt;/code&gt; &lt;a href=&quot;https://godbolt.org/z/5T9docTfq&quot;&gt;outputs&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;LAA: We can&#39;t vectorize because we can&#39;t find the array bounds.&lt;/pre&gt;
&lt;p&gt;Conditionals within the loop. Certain conditionals are possible to vectorize by either using &lt;code&gt;select&lt;/code&gt;, or masking values in the vector using the condition. There is no way to tell if a certain conditional will be vectorized in advance, and depends on whether the pattern is implemented in LLVM&#39;s vectorizer.&lt;/p&gt;
&lt;p&gt;LLVM is able to vectorize the example discussed previously:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, it is unable to vectorize this:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rdx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rdx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rdx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rdx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://godbolt.org/z/Wfjr6ofrf&quot;&gt;reason&lt;/a&gt; is as good as &quot;it is unimplemented&quot;:&lt;/p&gt;
&lt;pre&gt;LV: Not vectorizing: Found an unidentified PHI
  %10 = phi i64 [ %16, %8 ], [ 3, %.preheader ]&lt;/pre&gt;
&lt;p&gt;Whether the loop is canonical. If, for instance, the loop has multiple exits, LLVM cannot auto-vectorize it.&lt;/p&gt;
&lt;p&gt;LLVM struggles with early-exit loops, although there is no reason this is not possible to vectorize:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://godbolt.org/z/Yfe3PxzPY&quot;&gt;reason&lt;/a&gt; is as good as &quot;it is unimplemented&quot;:&lt;/p&gt;
&lt;pre&gt;LV: Found an outside user for :   %.lcssa = phi float [ %11, %6 ]
LV: Not vectorizing: could not determine number of loop iterations.&lt;/pre&gt;
&lt;p&gt;Function calls within the loop. Except for calls to LLVM intrinsics (like the &lt;code&gt;@llvm.fmuladd&lt;/code&gt; in the example discussed previously), the auto-vectorizer will fail if there are function calls within the loop that it didn&#39;t inline.&lt;/p&gt;
&lt;p&gt;LLVM cannot vectorize:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;AArch64 and RISC-V don&#39;t include a vector instruction for &lt;code&gt;printf&lt;/code&gt; in their instruction set, and this is a fundamental limitation of the instruction set.&lt;/p&gt;
&lt;pre&gt;LV: Not vectorizing: Found a non-intrinsic callsite
  %13 = tail call i32 (ptr, ...) @printf(
    ptr noundef nonnull dereferenceable(1) @.str,
    double noundef %12)&lt;/pre&gt;
&lt;p&gt;An example of a vector instruction that&#39;s included in both AArch64 and RISC-V is &lt;code&gt;lrint&lt;/code&gt;, and vectorizing a program with it will use the vector variant of the &lt;code&gt;@llvm.lrint&lt;/code&gt; intrinsic in the target-independent LLVM IR. The output can be inspected on &lt;a href=&quot;https://godbolt.org/z/foG7GsxYh&quot;&gt;Godbolt&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lrint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;N is a power of two, bounded by vector register width.&lt;/p&gt;</summary>
    <title>An introduction to auto-vectorization with LLVM</title>
    <updated>2024-06-27T20:08:57+01:00</updated>
    <dc:date>2024-06-27T20:08:57+01:00</dc:date>
  </entry>
  <entry>
    <id>compilers/loops</id>
    <link href="compilers/loops"/>
    <summary>&lt;p&gt;Detecting loops in a directed graph can be tricky, depending on how you define your loop. If you only want to admit &quot;natural loops&quot;, where the header of the loop dominates every node in the body, as well as the footer, we have a simple algorithm. If you want to go to the other extreme, and define the most general &quot;strongly connected components&quot;, without regard for loops, you have Tarjan&#39;s SCC algorithm. However, I&#39;m going to discuss a definition of loop that admits strange loops, but only things we&#39;d intuitively call &quot;loops&quot;.&lt;/p&gt;
&lt;p&gt;There are five [†] reduced cases we must consider, where backedges are marked by dotted arrows:&lt;/p&gt;
&lt;p&gt;Now, let&#39;s employ a simple DFS:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DFS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign_start_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// increment a clock as you assign&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outEdges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_time_not_assigned&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DFS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign_end_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// increment a clock as you assign&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;We get the following start times and end times:&lt;/p&gt;
&lt;p&gt;Let&#39;s call the first number &quot;DFS number&quot;, and the second number &quot;topo number&quot;, to indicate that this is the order that topological sort would have produced, in the absence of backedges (topological sort is meaningless when there are loops).&lt;/p&gt;
&lt;p&gt;First pass: do the dfs, and number everything.&lt;/p&gt;
&lt;p&gt;Second pass: find the backedge. When &lt;code&gt;start_time[destination] &amp;lt; start_time[source]&lt;/code&gt; and &lt;code&gt;end_time[destination] &amp;gt; end_time[source]&lt;/code&gt;, we have a backedge from source to destination.&lt;/p&gt;
&lt;p&gt;Third pass: find all the nodes in the loop. Here, we walk backwards from the source of the backedge until the loop header, and take everything that&#39;s &quot;nested within&quot; the loop header start and end times to be within the loop.&lt;/p&gt;
&lt;p&gt;In the no loop case, there&#39;s nothing to do since no backedges were detected. Note that in the &lt;code&gt;6/7&lt;/code&gt;-&lt;code&gt;2/5&lt;/code&gt; and &lt;code&gt;6/7&lt;/code&gt;-&lt;code&gt;3/4&lt;/code&gt; combinations, both start times and end times are greater in one pair; this is how we identify crossedges.&lt;/p&gt;
&lt;p&gt;In the early exit case, &lt;code&gt;2/7&lt;/code&gt; and &lt;code&gt;4/5&lt;/code&gt; are nested within &lt;code&gt;1/8&lt;/code&gt;, and we never reach &lt;code&gt;exit target&lt;/code&gt; by walking backward from the source of the backedge.&lt;/p&gt;
&lt;p&gt;In the multi-entry case, we correctly detect that &lt;code&gt;1/8&lt;/code&gt; is not nested within &lt;code&gt;2/7&lt;/code&gt;, while &lt;code&gt;3/6&lt;/code&gt; and &lt;code&gt;4/5&lt;/code&gt; are: when a node reached via a backward walk doesn&#39;t nest within the header, the loop is classified as &lt;em&gt;irreducible&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In the cuddled loops case, everything nests within &lt;code&gt;1/8&lt;/code&gt;, and the inner loop consists of &lt;code&gt;4/5&lt;/code&gt;, &lt;code&gt;3/6&lt;/code&gt;, and &lt;code&gt;2/7&lt;/code&gt;, all of which nest within &lt;code&gt;2/7&lt;/code&gt;. Finally, the shared header case is detected as two nested loops as well: a loop is identified by a unique backedge, not a unique header [‡]. The analysis is weak in that these cases are indistinguishable from normal nested loops.&lt;/p&gt;
&lt;p&gt;Hat tip to Sanjoy Das for pointing out the fifth case.
You might want to merge loops that share a header in a post-pass.&lt;/p&gt;</summary>
    <title>Detecting loops</title>
    <updated>2016-07-16T16:26:50-05:00</updated>
    <dc:date>2016-07-16T16:26:50-05:00</dc:date>
  </entry>
  <entry>
    <id>compilers/regalloc</id>
    <link href="compilers/regalloc"/>
    <summary>&lt;p&gt;We are going to be discussing LLVM&#39;s Fast Register Allocator: you might like to open &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/RegAllocFast.cpp&quot;&gt;RegAllocFast.cpp&lt;/a&gt; and refer to it as we go through the article.&lt;/p&gt;
&lt;p&gt;FastRegAlloc allocates linearly, going through instructions and their operands in order. It uses &lt;code&gt;PhysRegState&lt;/code&gt; to keep track of the state of various physical registers: they can be 0 (&lt;code&gt;regDisabled&lt;/code&gt;), 1 (&lt;code&gt;regFree&lt;/code&gt;), 2 (&lt;code&gt;regReserved&lt;/code&gt;), or a virtual register number (a large number). At the time of allocation, the full UseDef information is available (so you have information like &lt;code&gt;LR.LastUse&lt;/code&gt;); a register can either be a &lt;code&gt;&amp;lt;def&amp;gt;&lt;/code&gt; or a use. If &lt;code&gt;IsImplicit&lt;/code&gt; is flipped, it could also be a implicit-def (&lt;code&gt;&amp;lt;imp-def&amp;gt;&lt;/code&gt;) or implicit-use (&lt;code&gt;&amp;lt;imp-use&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;%vreg349&lt;def&gt; = MOVZX32rm8 %vreg351, 1, %noreg, 0, %noreg&lt;/pre&gt;
&lt;p&gt;turns into&lt;/p&gt;
&lt;pre&gt;%ESI&lt;def&gt; = MOVZX32rm8 %RDX&lt;kill&gt;, 1, %noreg, 0, %noreg&lt;/pre&gt;
&lt;p&gt;after allocation. The &lt;code&gt;&amp;lt;kill&amp;gt;&lt;/code&gt; indicates that the instruction is the last use of &lt;code&gt;%RDX&lt;/code&gt;. In another example,&lt;/p&gt;
&lt;pre&gt;CQO %RAX&lt;imp-def&gt;, %RDX&lt;imp-def&gt;, %RAX&lt;imp-use&gt;&lt;/pre&gt;
&lt;p&gt;turns into&lt;/p&gt;
&lt;pre&gt;CQO %RAX&lt;imp-def&gt;, %RDX&lt;imp-def&gt;, %RAX&lt;imp-use,kill&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the instruction references physical registers even before the allocation. That&#39;s because this instruction specifically wants to sign extend &lt;code&gt;%RAX&lt;/code&gt; into &lt;code&gt;%RDX&lt;/code&gt; (not any other register) for use in a later &lt;code&gt;IDIV&lt;/code&gt;. Remember that &lt;code&gt;IDIV&lt;/code&gt; operates on &lt;code&gt;%RDX:%RAX&lt;/code&gt; as the numerator, and writes the quotient in &lt;code&gt;%RAX&lt;/code&gt;, reminder in &lt;code&gt;%RDX&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The instruction is modeled as &lt;code&gt;MachineInstr&lt;/code&gt;, and the operands as &lt;code&gt;MachineOperand&lt;/code&gt;. Note that a &lt;code&gt;MO&lt;/code&gt; doesn&#39;t have to be a register: it could also be an immediate value; we use &lt;code&gt;MO.isReg()&lt;/code&gt; to find out if it&#39;s a register, physical or virtual. In addition to the states shown in the pretty-print, &lt;code&gt;MO&lt;/code&gt; can also be &lt;code&gt;EarlyClobber&lt;/code&gt;, &lt;code&gt;Dead&lt;/code&gt;, or &lt;code&gt;Undef&lt;/code&gt;. A Dead &lt;code&gt;MO&lt;/code&gt; implies Def, and indicates that the value defined is used no longer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AllocateBasicBlock&lt;/code&gt;, which operates on &lt;code&gt;MachineBasicBlock&lt;/code&gt;, can be separated into three different scans, that operate on register MOs. Before the first scan, we set up the &lt;code&gt;LiveIns&lt;/code&gt; (registers coming in live from the previous &lt;code&gt;MBB&lt;/code&gt;) as &lt;code&gt;regReserved&lt;/code&gt; so they aren&#39;t clobbered. The first scan operates on physical registers that are allocatable Uses; it calls &lt;code&gt;usePhysReg&lt;/code&gt; on them. At this stage, the physical register must be either &lt;code&gt;regDisabled&lt;/code&gt;, &lt;code&gt;regReserved&lt;/code&gt;, or &lt;code&gt;regFree&lt;/code&gt;. It cannot be allocated to a virtual register. Why? Imagine you see:&lt;/p&gt;
&lt;pre&gt;CQO %RAX&lt;imp-def&gt;, %RDX&lt;imp-def&gt;, %RAX&lt;imp-use&gt;&lt;/pre&gt;
&lt;p&gt;Now, if &lt;code&gt;%RAX&lt;/code&gt; were already allocated to a virtual register, we&#39;re basically screwed in this linear walk. Otherwise, kill it, mark it as &lt;code&gt;regFree&lt;/code&gt;, and move on: we have done our part by completing the use of the register that was reserved earlier.&lt;/p&gt;
&lt;p&gt;The second scan operates only on virtual register Uses. We add the register to &lt;code&gt;LiveVirtRegs&lt;/code&gt;, via &lt;code&gt;reloadVirtReg&lt;/code&gt;. If it didn&#39;t already exist in the map, we &lt;code&gt;allocVirtReg&lt;/code&gt; it, which essentially gets the first &lt;code&gt;regFree&lt;/code&gt; register not used in an instruction, and calls &lt;code&gt;assignVirtToPhysReg&lt;/code&gt; on it. &lt;code&gt;assignVirtToPhysReg&lt;/code&gt; is very simple: it just updates the &lt;code&gt;PhysRegState&lt;/code&gt; mapping. Finally,
&lt;code&gt;reloadVirtReg&lt;/code&gt; updates the &lt;code&gt;UsedInInstr&lt;/code&gt; map.&lt;/p&gt;
&lt;p&gt;The third scan operates on physical and virtual registers that are Defs. If the register is a physical register, it does &lt;code&gt;definePhysReg&lt;/code&gt; with &lt;code&gt;regReserved&lt;/code&gt; unless &lt;code&gt;MO.isDead()&lt;/code&gt;, in which case it&#39;s regFree. &lt;code&gt;definePhysReg&lt;/code&gt; is very simple: it just puts the register in the state that was requested (&lt;code&gt;regReserved&lt;/code&gt; or &lt;code&gt;regFree&lt;/code&gt;, in this case).&lt;/p&gt;
&lt;p&gt;To think about the problem, if we have,&lt;/p&gt;
&lt;pre&gt;%RAX&lt;def&gt; = COPY %vreg342&lt;/pre&gt;
&lt;p&gt;we should always &lt;code&gt;regReserve&lt;/code&gt; &lt;code&gt;%RAX&lt;/code&gt;, right? Except if &lt;code&gt;%RAX&lt;/code&gt; is dead. What about if it&#39;s an &lt;code&gt;&amp;lt;imp-def&amp;gt;&lt;/code&gt;?&lt;/p&gt;
&lt;pre&gt;CQO %RAX&lt;imp-def&gt;, %RDX&lt;imp-def&gt;, %RAX&lt;imp-use&gt;&lt;/pre&gt;
&lt;p&gt;We didn&#39;t pass &lt;code&gt;CQO&lt;/code&gt; &lt;code&gt;%RAX&lt;/code&gt; explicitly, but that doesn&#39;t mean that a later instruction (for instance, &lt;code&gt;IDIV&lt;/code&gt;) is not relying on this register&#39;s value. If we have an instruction between &lt;code&gt;CQO&lt;/code&gt; and &lt;code&gt;IDIV&lt;/code&gt;, that can potentially clobber &lt;code&gt;%RAX&lt;/code&gt;, leading to a regalloc crash. Hence, we &lt;code&gt;regReserve&lt;/code&gt; even if &lt;code&gt;MO.isImplicit()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The third scan does &lt;code&gt;defineVirtReg&lt;/code&gt; on virtual registers, to grab the first free physical register for the virtual register.&lt;/p&gt;
&lt;p&gt;Note: the &quot;pretty-prints&quot; are generated by setting a breakpoint in &lt;code&gt;AllocateBasicBlock&lt;/code&gt; and executing &lt;code&gt;p MBB-&amp;gt;dump()&lt;/code&gt;.&lt;/p&gt;</summary>
    <title>Inside a register allocator</title>
    <updated>2016-03-24T17:36:35-05:00</updated>
    <dc:date>2016-03-24T17:36:35-05:00</dc:date>
  </entry>
  <entry>
    <id>compilers/vplan</id>
    <link href="compilers/vplan"/>
    <summary>&lt;p&gt;In a follow-up to the &lt;a href=&quot;/compilers/intro-vec&quot;&gt;introductory article on auto-vectorization&lt;/a&gt;, we discuss how the loop vectorizer works internally. Nearly all transforms in LLVM work by directly manipulating IR, using the results of various analyses on the IR, while the loop vectorizer operates on a layer of abstraction above the IR: it lifts the LLVM IR to an overlay IR, analyzes and transforms the overlay IR, and finally removes the original IR entirely, replacing it with a final LLVM IR from the direct concretization of the final overlay IR. It also plans various vectorization strategies, costing each one until it finds a winning strategy. This infrastructure is called VPlan.&lt;/p&gt;
&lt;p&gt;Let us start with a variant of the example program from the previous article:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;saxpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;restrict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;As the vectorizer runs near the end of the pipeline, LLVM applies various scalar transforms to yield target-independent IR that the vectorizer gets as input:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;nl&quot;&gt;loop:&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.x&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getelementptr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inbounds&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%fmuladd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;@llvm.fmuladd.f32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%load.y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%fmuladd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ptr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%gep.y&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nuw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%exitcond&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;icmp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%iv.next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exitcond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%loop&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The planning stage of the vectorizer normally decides two key factors when attempting to find the winning plan: the vectorization factor (VF), which determines the width of the instructions on the VPU, and interleave count (UF, referring to the old name &quot;unrolling factor&quot;), which determines how many copies of each instruction to create. These decisions are predicated on the cost of the final instructions, which only makes sense when a specific target is provided: for the purposes of this article, let us force the vectorizer to run in a target-independent fashion without interleaving using &lt;code&gt;-force-vector-width=4 -force-vector-interleave=1&lt;/code&gt;, and inspect the lifting of the LLVM IR to the VPlan:&lt;/p&gt;
&lt;pre&gt;VPlan &#39;Initial VPlan for VF={4},UF&gt;=1&#39; {
Live-in vp&lt;%0&gt; = VF
Live-in vp&lt;%1&gt; = VF * UF
Live-in vp&lt;%2&gt; = vector-trip-count
Live-in ir&lt;1024&gt; = original trip-count

vector.ph:
Successor(s): vector.body

vector.body:
  EMIT vp&lt;%3&gt; = CANONICAL-INDUCTION ir&lt;0&gt;, vp&lt;%index.next&gt;
  vp&lt;%4&gt; = SCALAR-STEPS vp&lt;%3&gt;, ir&lt;1&gt;, vp&lt;%0&gt;
  CLONE ir&lt;%gep.x&gt; = getelementptr inbounds ir&lt;%x&gt;, vp&lt;%4&gt;
  vp&lt;%5&gt; = vector-pointer ir&lt;%gep.x&gt;
  WIDEN ir&lt;%load.x&gt; = load vp&lt;%5&gt;
  CLONE ir&lt;%gep.y&gt; = getelementptr inbounds ir&lt;%y&gt;, vp&lt;%4&gt;
  vp&lt;%6&gt; = vector-pointer ir&lt;%gep.y&gt;
  WIDEN ir&lt;%load.y&gt; = load vp&lt;%6&gt;
  WIDEN-INTRINSIC ir&lt;%fmuladd&gt; =
    call llvm.fmuladd(ir&lt;%a&gt;, ir&lt;%load.x&gt;, ir&lt;%load.y&gt;)
  vp&lt;%7&gt; = vector-pointer ir&lt;%gep.y&gt;
  WIDEN store vp&lt;%7&gt;, ir&lt;%fmuladd&gt;
  EMIT vp&lt;%index.next&gt; = add nuw vp&lt;%3&gt;, vp&lt;%1&gt;
  EMIT branch-on-count vp&lt;%index.next&gt;, vp&lt;%2&gt;
}&lt;/pre&gt;
&lt;p&gt;First, we notice that each variable has an &lt;code&gt;ir&amp;lt;&amp;gt;&lt;/code&gt; or &lt;code&gt;vp&amp;lt;&amp;gt;&lt;/code&gt; annotation. The &lt;code&gt;ir&lt;/code&gt; variables are variables present in the original LLVM IR or some kind of constants, and the &lt;code&gt;vp&lt;/code&gt; variables are fresh variables that are created in the VPlan. Next, we notice new annotations like &lt;code&gt;EMIT&lt;/code&gt;, &lt;code&gt;CLONE&lt;/code&gt;, and &lt;code&gt;WIDEN&lt;/code&gt; in each line in the vector loop: these are termed &quot;recipes&quot;, from which the final LLVM IR will be emitted, post transformations.&lt;/p&gt;
&lt;p&gt;Near the beginning of the vector loop, we can see that the vectorizer has analyzed the trip-count of the original loop (1024), along with a canonical induction-variable (&lt;code&gt;%iv&lt;/code&gt;), and emitted a &lt;code&gt;CANONICAL-INDUCTION&lt;/code&gt; recipe along with a &lt;code&gt;SCALAR-STEPS&lt;/code&gt; that increments it by &lt;code&gt;VF&lt;/code&gt; to account for the fact that the vectorized loop has width VF, and executes 1024 / VF times. This means that certain instructions must either be width VF, or duplicated VF number of times with different steps for correctness: in our snippet, we see that loads and stores were widened, along with the intrinsic &lt;code&gt;fmuladd&lt;/code&gt;. &lt;code&gt;getelementptr&lt;/code&gt; should not be widened: it should add VF times the original offset to the base pointer, and this is indeed what is done. For instructions that should not be widened, we see an &lt;code&gt;EMIT&lt;/code&gt;/&lt;code&gt;CLONE&lt;/code&gt;, or &quot;replicate&quot; recipes. This is also where the interleaving-factor would have come in, in a different example, when something that needs to be widened couldn&#39;t be widened.&lt;/p&gt;
&lt;p&gt;Notice that the final line, &lt;code&gt;branch-on-count&lt;/code&gt;, is predicated on an abstract vector-trip-count: since the vectorizer could make different decisions about VF and UF as it plans, the vector-trip-count is only materialized after a decision is made.&lt;/p&gt;
&lt;p&gt;We see some cryptic &lt;code&gt;vector-pointer&lt;/code&gt; recipes, but these will be optimized out by the time we get to the final VPlan. Also notice a minor detail in the operands of &lt;code&gt;fmuladd&lt;/code&gt;: the first operand is &lt;code&gt;%a&lt;/code&gt;, which is a scalar, while the other two operands, &lt;code&gt;%load.x&lt;/code&gt; and &lt;code&gt;%load.y&lt;/code&gt;, are widened; if the first operand isn&#39;t fixed up, vectorization of the entire loop would be inhibited for correctness reasons.&lt;/p&gt;
&lt;p&gt;The final VPlan is produced post optimizations and materializations:&lt;/p&gt;
&lt;pre&gt;VPlan &#39;Final VPlan for VF={4},UF={1}&#39; {
vector.ph:
  EMIT vp&lt;%1&gt; = broadcast ir&lt;%a&gt;
Successor(s): vector.body

vector.body:
  EMIT-SCALAR vp&lt;%index&gt; =
    phi [ ir&lt;0&gt;, vector.ph ], [ vp&lt;%index.next&gt;, vector.body ]
  CLONE ir&lt;%gep.x&gt; = getelementptr inbounds ir&lt;%x&gt;, vp&lt;%index&gt;
  WIDEN ir&lt;%load.x&gt; = load ir&lt;%gep.x&gt;
  CLONE ir&lt;%gep.y&gt; = getelementptr inbounds ir&lt;%y&gt;, vp&lt;%index&gt;
  WIDEN ir&lt;%load.y&gt; = load ir&lt;%gep.y&gt;
  WIDEN-INTRINSIC ir&lt;%fmuladd&gt; = call llvm.fmuladd(
    vp&lt;%1&gt;, ir&lt;%load.x&gt;, ir&lt;%load.y&gt;)
  WIDEN store ir&lt;%gep.y&gt;, ir&lt;%fmuladd&gt;
  EMIT vp&lt;%index.next&gt; = add nuw vp&lt;%index&gt;, ir&lt;4&gt;
  EMIT branch-on-count vp&lt;%index.next&gt;, ir&lt;1024&gt;
}&lt;/pre&gt;
&lt;p&gt;Notice that the first operand of the &lt;code&gt;fmuladd&lt;/code&gt; is now a broadcast of &lt;code&gt;%a&lt;/code&gt;, which is essentially a way to fill a vector with a scalar. It lowers to the following LLVM IR:&lt;/p&gt;
&lt;pre&gt;  &lt;span class=&quot;nv&quot;&gt;%broadcast.splatinsert&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;insertelement&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i64&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;%broadcast.splat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;shufflevector&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%broadcast.splatinsert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;zeroinitializer&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;At this point, the VPlan is &quot;executed&quot; to produce the final LLVM IR. The full example can be seen on &lt;a href=&quot;https://godbolt.org/z/Ga3E4b7jT&quot;&gt;Godbolt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;VPlan allows us to focus on semantic details of the vectorization, and operate at an abstraction level that is easier to inspect and optimize, and less error-prone, than concrete LLVM IR.&lt;/p&gt;</summary>
    <title>The Vectorization-Planner (VPlan) in LLVM</title>
    <updated>2025-09-19T20:59:39+01:00</updated>
    <dc:date>2025-09-19T20:59:39+01:00</dc:date>
  </entry>
  <entry>
    <id>logic/equality</id>
    <link href="logic/equality"/>
    <summary>&lt;p&gt;Here, we talk about equalities, and provide illustrative examples in vanilla Rocq, SProp, and HoTT.&lt;/p&gt;
&lt;h3&gt;Equality in Mathematics&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;/logic/zfc&quot;&gt;zfc-based mathematics&lt;/a&gt;, say in abelian groups, $A \oplus B \simeq B \oplus A$, where the equality is a set-based equality. In mathematics based on category theory, equality is too strong a notion on objects, and only speak about objects &quot;upto unique isomorphism&quot;; morphisms in a $\mathrm{1}$-category can be equal though. In higher categories, and in particular, homotopy theory, we talk about &quot;weak homotopy equivalences&quot; almost fully replacing equality. However, it can be tricky to mechanize a theory based on $\infty$-categories; the best dependent-type-theory model we have is homotopy type theory, commonly referred to as HoTT, which we will discuss in the last section.&lt;/p&gt;
&lt;h3&gt;Universes in Rocq&lt;/h3&gt;
&lt;p&gt;First, let us briefly talk about the cumulative universe of Rocq. &lt;code&gt;Prop&lt;/code&gt; is a &lt;code&gt;Set&lt;/code&gt; that can be promoted to &lt;code&gt;Type&lt;/code&gt; seamlessly. The reason for the distinction between &lt;code&gt;Prop&lt;/code&gt; and &lt;code&gt;Set&lt;/code&gt; is an engineering one: &lt;code&gt;Prop&lt;/code&gt; is impredicative, while &lt;code&gt;Set&lt;/code&gt; is not, and proofs are erased during extraction.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SetTypeIncl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropTypeIncl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropSetIncl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;There is an $\infty$ hierarchy within the &lt;code&gt;Type&lt;/code&gt; universe, and types of Types are Types themselves.&lt;/p&gt;
&lt;p&gt;Inhabitants of a &lt;code&gt;Set&lt;/code&gt; are sets of primitive things like $\mathbb{N}$ and $\mathbb{R}$, while inhabitants of a &lt;code&gt;Prop&lt;/code&gt; are propositions, which could be $\top$, $\bot$, or some arbitrary term, the inhabitant of which acts as the proof.&lt;/p&gt;
&lt;h3&gt;Propositions&lt;/h3&gt;
&lt;p&gt;There are two kinds of equalities in vanilla Rocq. The difference is as follows: propositional equality roughly translates to &quot;requires proof obligation to be discharged by the user&quot;, whereas definitional equality is a simple syntactic rewriting in the metatheory. A propositional equality between propositions can be formalized as:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Axiom&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropositionalProofIrrelevance&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;We then get a proof obligation which we discharge using the axiom:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropEquality&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropositionalProofIrrelevance&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Qed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;In the general case, two different inhabitants of &lt;code&gt;Prop&lt;/code&gt; are unequal. There is, however, a propositional equality existing between two equal propositions:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropRefl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;exact&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;eq_refl&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Qed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;eq_refl&lt;/code&gt; is simply the sole inhabitant of an Inductive:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Inductive&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;eq_refl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;h3&gt;The proof-irrelevant SProp&lt;/h3&gt;
&lt;p&gt;There are three inhabitants of &lt;a href=&quot;https://coq.inria.fr/refman/addendum/sprop.html&quot;&gt;SProp&lt;/a&gt;: &lt;code&gt;sUnit&lt;/code&gt; corresponding to $\top$, &lt;code&gt;sEmpty&lt;/code&gt; corresponding to $\bot$, and &lt;code&gt;sProposition&lt;/code&gt; corresponding to a definitionally proof-irrelevant term. The way &lt;code&gt;SProp&lt;/code&gt; implements definitional proof-irrelevance is a simple engineering detail: there is hard-coding in Rocq to render two inhabitants of &lt;code&gt;sProposition&lt;/code&gt; trivially inter-convertible.&lt;/p&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;=&lt;/code&gt; doesn&#39;t work as expected:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SPropIrr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SProp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;reflexivity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Abort&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;(* Type-check fails at Qed.
        * (=) : ∀ A, A -&amp;gt; A -&amp;gt; Prop, but we want to return an SProp. *)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This is because the &lt;code&gt;SProp&lt;/code&gt; universe is disjoint from the &lt;code&gt;Prop&lt;/code&gt; universe:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SPropToProp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SProp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;intros&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;exact&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Abort&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;(* Type-check fails at Qed.
        * SProp is not convertible to Prop. *)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Fortunately, we can do better.&lt;/p&gt;
&lt;h3&gt;Mere propositions in homotopy type theory&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/HoTT/HoTT&quot;&gt;HoTT&lt;/a&gt;, there is just one $\infty$-ladder:&lt;/p&gt;
&lt;p&gt;$\mathbb{1}$, and anything that&#39;s contractible to it, is the ($\mathrm{-2}$)-truncated Type.
A &quot;mere proposition&quot;, an inhabitant of &lt;code&gt;hProp&lt;/code&gt;, is simply a ($\mathrm{-1}$)-truncated Type.
&lt;code&gt;hSet&lt;/code&gt; is the $\mathrm{0}$-truncated Type.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Notation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Contr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IsTrunc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;minus_two&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Notation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IsHProp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IsTrunc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;minus_two&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Notation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IsHSet&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IsTrunc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;minus_two&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The notion of truncation is central to HoTT, where $A : \mathrm{Type}_n$ can be truncated to a $\mathrm{Type}_m$, whence higher-than-$m$ morphisms are rendered uninteresting. Any two hProps are propositionally equal:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;hPropEquality&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;hProp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;path_ishprop&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Qed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Conceptually, this is as simple and elegant as &lt;code&gt;PropEquality&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Big thanks to &lt;a href=&quot;https://kenji.maillard.blue&quot;&gt;Kenji Maillard&lt;/a&gt; for the scintillating discussion, and for helping with the examples.
Kudos to Hugo Moeneclaey for giving a wonderful introduction to truncation in the last HoTT class.
Thanks to &lt;a href=&quot;https://www.pédrot.fr&quot;&gt;Pierre-Marie Pédrot&lt;/a&gt; for pointing out some very serious errors.&lt;/p&gt;</summary>
    <title>Equality in Mechanized Mathematics</title>
    <updated>2020-02-15T18:12:59+01:00</updated>
    <dc:date>2020-02-15T18:12:59+01:00</dc:date>
  </entry>
  <entry>
    <id>logic/fom</id>
    <link href="logic/fom"/>
    <summary>&lt;p&gt;Starting from the question of what consequence Gödel&#39;s incompleteness theorem has on the foundations of mathematics, we argue for new foundations, and build some intuition for these new foundations in Coq.&lt;/p&gt;
&lt;p&gt;Mathematics can be thought of as a game where you start with some objects (say, sets), some axioms on the objects (typically, ZFC), and use a calculus of logical deductions (such as classical logic) to prove things. To mechanize this game in a proof assistant, one would either use a proof-search or tactic system, and check subject reduction. However, mechanized mathematics is done differently from classical mathematics, and we first investigate whether building new foundations is justifiable.&lt;/p&gt;
&lt;p&gt;Gödel&#39;s second incompleteness theorem states that any formal system, that can express elementary arithmetic, cannot prove its own consistency, assuming à priori that the system is consistent. It doesn&#39;t destroy the platonic view of mathematics as such, but does destroy the view that there is only one correct foundation for mathematics. Further, one would argue that it is precisely this result that makes mathematics exciting: we can keep rewriting foundations to better suit our abstract intuitions, and build higher abstractions, without worrying about whether there is &quot;one true foundation&quot;.&lt;/p&gt;
&lt;h3&gt;Departing from ZFC foundations&lt;/h3&gt;
&lt;p&gt;Some mathematicians would then argue that we&#39;ve settled on ZFC and classical logic as foundations, but this is only true of $\sim$80% of recent mathematical literature. Category theory, in particular, breaks away from set-theoretic foundations; objects and morphisms aren&#39;t sets. Indeed, set-theoretic questions about categories are ill-formed, although one can encode boolean algebras using topoi.&lt;/p&gt;
&lt;p&gt;Moreover, one should aim for a foundation that is conducive to mechanization, so proofs can be checked for correctness in an automated fashion. The strategy that Voevodsky et al. used was to extend Martin-Löf type theory, and build a branch of mechanized mathematics, homotopy type theory, which we will refer to henceforth as &lt;a href=&quot;https://github.com/HoTT/HoTT&quot;&gt;HoTT&lt;/a&gt;. It is formalized in Coq, whose foundations are based in Martin-Löf Type Theory.&lt;/p&gt;
&lt;h3&gt;Preliminaries&lt;/h3&gt;
&lt;p&gt;What the following proposition says, is that, for every inhabitant of $\mathbb{N}$ that you supply, $f$ will supply an inhabitant of $\mathbb{1}$:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;intros&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;exact&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Qed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The proof is witness that we can always supply an inhabitant of the type $\mathbb{N} \rightarrow \mathbb{1}$. By Curry-Howard isomorphism:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&#39;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;In type theory, a function is just a non-dependent version of the $\Pi$ type, where the codomain $B$ is fixed:&lt;/p&gt;
&lt;p&gt;The logical connective $\neg$, which we will use in the next section, has the following definition in type theory:&lt;/p&gt;
&lt;h3&gt;Two intuitions in classical mathematics broken&lt;/h3&gt;
&lt;p&gt;Our first example is the classic proof-by-contradiction. A proof in constructive mathematics cannot proceed in the following logical sequence for a proposition $P$:&lt;/p&gt;
&lt;p&gt;In other words,&lt;/p&gt;
&lt;p&gt;This is in line with the general philosophy of constructive mathematics, where non-existence of an inhabitant of a type cannot be proved; to supply a witness is to supply a construction of the inhabitant, and indeed, no such construction might exist. Nevertheless, an axiom of excluded middle can be axiomatized and used to construct-via-contradiction, just like any other axiom:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Axiom&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LEM&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;forall&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;~P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;To understand this better, let us take the example of the constructive equivalent of $\mathbb{0} \Rightarrow \textrm {anything}$ in classical mathematics:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;FalseImpliesAnything&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;forall&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;intros&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;exact&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Qed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Since $\mathbb{0}$ has no inhabitants, the construction of any inhabitant of any type can be proved from it.&lt;/p&gt;
&lt;p&gt;It is perhaps prudent to supply another example of a classical statement to illustrate Coq&#39;s type-checker:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TrueDoesNotImplyFalse&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Proof&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;(* Due to enforced exhaustive pattern-matching on inhabitants of the LHS,
   * we&#39;d need to match up an inhabitant of True (there is only I)
   * to some inhabitant of False, but there are no inhabitants of False.
   *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Abort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;In category theory, $\mathbb{0}$ would be the initial object, and there is at most one arrow from the initial object to every other object in the category; $\mathbb{1}$ would be the final object, and there is at most one arrow from every other object in the category to it. The above theorem hypothesizes the existence of a morphism from the final object to the initial object, which of course, cannot exist.&lt;/p&gt;
&lt;p&gt;For the second example, let us investigate the classical notion of proof irrelevance. In ZFC, sets and propositions are in different universes of discourse, as opposed to type theory, where proofs objects are first-class. Over the course of its development, the question of proof relevance was raised in type theory. In the following example, $p$ and $q$ are inhabitants of the type $x = y$, and the question is whether $p$ is different from $q$:&lt;/p&gt;
&lt;p&gt;The answer, as supplied by HoTT, is: yes, proofs are relevant, and $p$ is different from $q$; a proof is viewed as a homotopy path between two homotopy types, and there is a notion of homotopy equivalence between homotopy paths. In classical mathematics, $p$ would always be equal to $q$.&lt;/p&gt;</summary>
    <title>An inquiry into the Foundations of Mathematics</title>
    <updated>2020-02-02T11:11:41+01:00</updated>
    <dc:date>2020-02-02T11:11:41+01:00</dc:date>
  </entry>
  <entry>
    <id>logic/leancoq</id>
    <link href="logic/leancoq"/>
    <summary>&lt;p&gt;Both Lean and Rocq are proof assistants based on pCIC. Here, we argue that what sets them apart are, in essence, cultural differences.&lt;/p&gt;
&lt;img src=&quot;/computing/coq/leancoq-lean.png
&quot; /&gt;
&lt;img src=&quot;/computing/coq/leancoq-coq.png&quot; /&gt;
&lt;p&gt;Lean has much lower startup-cost for pure mathematicians, since its built-in features and &lt;a href=&quot;https://github.com/leanprover-community/mathlib&quot;&gt;math library&lt;/a&gt; are great for doing undergraduate-level group theory &amp;amp; topology, masters-level commutative algebra &amp;amp; category theory, but it plateaus quickly thereafter.&lt;/p&gt;
&lt;p&gt;Lean seems to have taken a top-down approach, by focusing on writing real proofs as quickly as possible, without compromising on &lt;a href=&quot;https://github.com/digama0/lean-type-theory/releases/download/v1.0/main.pdf&quot;&gt;soundness&lt;/a&gt;. There are three axioms in Lean: &lt;code&gt;propositional extensionality&lt;/code&gt;, &lt;code&gt;quotient soundness&lt;/code&gt;, and &lt;code&gt;choice&lt;/code&gt;; however, these don&#39;t block computation, since computation is done in a VM. They do, however, break good type theoretic properties like &lt;code&gt;strong normalization&lt;/code&gt;, &lt;code&gt;subject reduction&lt;/code&gt;, and &lt;code&gt;canonicity&lt;/code&gt; — this was a conscious design choice.&lt;/p&gt;
&lt;p&gt;Rocq, on the other hand, has always been very particular about sound type theoretic foundations. The recent &lt;a href=&quot;https://www.irif.fr/~sozeau/research/publications/drafts/Coq_Coq_Correct.pdf&quot;&gt;&quot;Coq Coq Correct!&quot;&lt;/a&gt; formalizes the Rocq engine proving metatheoretic properties about it, in Rocq, and &lt;a href=&quot;https://github.com/HoTT/HoTT&quot;&gt;HoTT&lt;/a&gt; is being actively developed to fix many of Rocq&#39;s issues.&lt;/p&gt;
&lt;p&gt;Working mathematicians have only just started using software for their work, and they often rely on unverified (and sometimes proprietary) tools like magma, sage, and mathematica. Lean is a big step-up, and the good type theoretic properties preserved by Rocq don&#39;t seem as important to them.&lt;/p&gt;
&lt;p&gt;Lean supports both constructive and classical reasoning, but quotienting in Rocq is painful due to &lt;a href=&quot;http://www.cs.nott.ac.uk/~psztxa/talks/types-17-hell.pdf&quot;&gt;&quot;setoid-hell&quot;&lt;/a&gt;; something that would be fixed when types are modeled as $\infty$-groupoids instead of setoids, as in the HoTT line of work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/leanprover-community/mathlib/blob/master/docs/tutorial/Zmod37.lean&quot;&gt;Quotient-reasoning&lt;/a&gt; makes formalizing commutative algebra painless, and it&#39;s baked into the Lean kernel. However, quotients are tricky to implement without breaking certain metatheoretic properties that Rocq&#39;ers cherish; nevertheless, there is an &lt;a href=&quot;https://math-comp.github.io/htmldoc/mathcomp.ssreflect.generic_quotient.html&quot;&gt;implementation&lt;/a&gt; in Rocq&#39;s &lt;a href=&quot;https://github.com/math-comp/math-comp&quot;&gt;math-comp&lt;/a&gt;, albeit, without a reduction rule.&lt;/p&gt;
&lt;p&gt;Lean&#39;s &lt;a href=&quot;https://leanprover.github.io/theorem_proving_in_lean/structures_and_records.html#inheritance&quot;&gt;inheritance&lt;/a&gt; is another good feature; it disallows diamond-inheritance, and seems like a bit of a hack, but Rocq is definitely missing some form of a well-thought-out ad-hoc polymorphism.&lt;/p&gt;
&lt;p&gt;Category theory in Lean has not been &lt;a href=&quot;https://github.com/leanprover-community/mathlib/blob/master/docs/theories/category_theory.md&quot;&gt;developed&lt;/a&gt; with higher categories in mind; I&#39;m not sure how one would define $\infty$-categories, since universes are explicit, and since there are no coinductive types: Rocq&#39;s cumulativity seems to have been a better design choice.&lt;/p&gt;
&lt;p&gt;One would think that Lean is an engineering feat, since it&#39;s written in C++: Rocq&#39;s math-comp (90k loc) compares to Lean&#39;s mathlib (150k loc); math-comp builds in under ten minutes, while mathlib takes over thirty minutes to build! Indeed, due to their design decision to use a VM for computations, computation happens at a speed comparable to Python-bytecode evaluation — they seem to be overhauling this in Lean4 though, by compiling Lean code down to C before execution.&lt;/p&gt;
&lt;p&gt;Another reason for the relative slowness of Lean is that they do a lot of automation under the hood, figuring out, for instance, that when the user writes $X \times Y$, $X$ and $Y$ are topological spaces, and that $\times$ here means product topology.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/digama0/mm0&quot;&gt;Metamath Zero&lt;/a&gt; might be of interest to readers of this article.
This article has developed over several discussions on coq-club and Lean Zulip.&lt;/p&gt;</summary>
    <title>Lean versus Rocq: The cultural chasm</title>
    <updated>2020-01-04T15:38:56+01:00</updated>
    <dc:date>2020-01-04T15:38:56+01:00</dc:date>
  </entry>
  <entry>
    <id>logic/predicativity</id>
    <link href="logic/predicativity"/>
    <summary>&lt;p&gt;Today, we write a quick specialized note on what impredicativity exactly means, for those reasonably familiar with the Rocq syntax.&lt;/p&gt;
&lt;p&gt;Historically speaking, Rocq started out with making &lt;code&gt;Set&lt;/code&gt; impredicative and they still carry around the flag &lt;code&gt;--set-impredicative&lt;/code&gt; to maintain impredicativity in Sets. Let&#39;s check it quickly:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;(* Set is predicative. *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Fail&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SetPred&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;forall&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;We use a little macro to check the impredicativity of various types, since an equivalent definition wouldn&#39;t type-check:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;(* Checks that all inhabitants of U are of type V. *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Notation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&#39;check&#39; U V&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;forall&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;All inhabitants of &lt;code&gt;Prop&lt;/code&gt; are of type Prop, for good reason.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;(* Prop is impredicative. *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PropImpr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Attempt to check the predicativity of &lt;code&gt;Type&lt;/code&gt; naïvely:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;(* Is Type impredicative? This is misleading. *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TypeNaive&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;forall&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The previous example was misleading, and we clarify it in the next example:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;(* In the previous definition, Type is really Type@{i},
 * and the following definition fails with: Universe {Predicativity.153} is unbound. *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Fail&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TypePred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The Type universe is cumulative, not impredicative. We show the cumulativity using algebraic universe notation:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;(* Fails due to a bug in Rocq: Unable to handle arbitrary u+k &amp;lt;= v constraints? *)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TypePred&#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;forall&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TypePred&#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}.&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SkySkimmer&quot;&gt;Gaëtan Gilbert&lt;/a&gt;: intricacies of universes in Rocq
&lt;a href=&quot;http://pauillac.inria.fr/~herbelin/&quot;&gt;Hugo Herbelin&lt;/a&gt;: syntactic mastery over Rocq&lt;/p&gt;</summary>
    <title>Predicativity in Rocq</title>
    <updated>2020-03-08T07:27:41+01:00</updated>
    <dc:date>2020-03-08T07:27:41+01:00</dc:date>
  </entry>
  <entry>
    <id>logic/zfc</id>
    <link href="logic/zfc"/>
    <summary>&lt;p&gt;Using a mélange of mathematical syntaxes, we mechanize some exercises from Tao&#39;s excellent book&lt;/p&gt;
&lt;h3&gt;Overture&lt;/h3&gt;
&lt;p&gt;Let us informally define sets and set membership $\in$. A set is an unordered collection of &lt;code&gt;objects&lt;/code&gt;, with the set itself being an object. Set membership checks whether a given object is contained within a set:&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;axiom of substitution&lt;/code&gt; uses the definition of equality:&lt;/p&gt;
&lt;p&gt;The axiom of substitution is preserved for all sets only defined in terms of $\in$ and $=$.&lt;/p&gt;
&lt;img src=&quot;/logic/zfc-3.3.4.png&quot; /&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://sites.google.com/view/chaitanyals&quot;&gt;Chaitanya Leena Subramanium&lt;/a&gt; for suggesting the exercises and pushing for the use of natural deductions in the last exercise.
Thanks to &lt;a href=&quot;http://pauillac.inria.fr/~herbelin/&quot;&gt;Hugo Herbelin&lt;/a&gt; for patiently going through many proofs and pointing out the errors.&lt;/p&gt;</summary>
    <title>ZFC and propositional logic</title>
    <updated>2020-01-18T08:02:23+01:00</updated>
    <dc:date>2020-01-18T08:02:23+01:00</dc:date>
  </entry>
  <dc:date>2026-02-16T15:13:35+00:00</dc:date>
</feed>