It&#x27;s been pretty common for compilers to require 3 different intermediate representations (parse tree, MIR, and LIR).  My copy of <i>Advanced Compiler Design and Optimization</i> [1] (over 10 years old at this point) lists the 3-IR architecture on page 8.  It references Sun&#x27;s SPARC compilers, DEC&#x27;s Alpha compilers, Intel&#x27;s x86 compilers, and SGI&#x27;s MIPS compilers as implementations that use it.<p>What <i>has</i> changed are the boundaries.  Traditionally, semantic analysis (including typechecking) operated on the parse tree, which resembled the human-written language extensively.  Optimization operated on MIR, then it&#x27;d be lowered to an architecture-specific LIR via register allocation and instruction selection, and another round of optimization (instruction scheduling, etc.) would be applied.  The purpose of all of this was to provide multiple language front-ends on top of a single compiler.  In the 80s and 90s, compilers were often written by the hardware vendor, so they would tightly optimize the MIR and LIR for their own architecture, and use the parse-tree =&gt; MIR lowering to support multiple surface languages.<p>LLVM chose a LIR that&#x27;s closer to what many compilers had been using as MIR, and then moved the optimization passes into the LIR, and hid the architecture-specific backends within the LLVM project itself, out of the eyes of language designers.  It could do this because of open-source: with a shared body of compiler code owned by everyone and gradual consolidation of the hardware market, it became easier to contribute your backend to LLVM than to maintain your own compiler stack and fight for adoption.  (GCC actually had a fairly similar architecture first, but the GCC IR was very difficult to comprehend if you weren&#x27;t a GCC maintainer, which made it impractical as a compilation target for outside projects.  They generated C code instead and let GCC compile it.)  That in turn made it much easier to write a compiler and experiment with language design, since you only had to figure out how to translate your language to LLVM&#x27;s IR rather than work out the details of scheduling and register allocation.  <i>That</i>, in turn, allowed greater complexity in language features: Swift and Rust have language features that go beyond what cutting-edge research was &lt;10 years ago, and do so in a production language that you can use <i>now</i>.  And so it&#x27;s not surprising that they&#x27;re now re-introducing a MIR to manage the additional complexity introduced by the new language features.<p>[1] <a href="http:&#x2F;&#x2F;www.amazon.com&#x2F;Advanced-Compiler-Design-Implementation-Muchnick&#x2F;dp&#x2F;1558603204" rel="nofollow">http:&#x2F;&#x2F;www.amazon.com&#x2F;Advanced-Compiler-Design-Implementatio...</a>