<p>Using something like <a href="https://llvm.org/" rel="noreferrer">LLVM</a> when designing a compiler has a lot of advantages, since tons of work can be saved by using an existing optimizer and code generation for a variety of platforms. Even large, popular languages like Rust and Julia use LLVM, and LLVM implementations of languages like Go and Kotlin exist.</p>
<p>However, I'd assume some downsides exist to using an existing back-end. Compile time is one I've seen mentioned in the context of Rust, and I'd assume you lose some flexibility in how you compile and optimize your code when using a pre-existing compiler infrastructure.</p>
<p>What are some pitfalls/downsides of using an existing IR/optimizer/compiler infrastructure for a compiled language (as opposed to writing your own, rather than transpilation/bytecode)?</p>

<compilers><optimization><backend><llvm>
What are the pitfalls of using an existing IR/compiler infrastructure like LLVM?
CC BY-SA 4.0
2023-07-01T18:32:15.670Z
It's worth noting that the Kotlin compiler isn't "just another third party compiler." It's the official backend for Kotlin/Native
Seggan
<h1>Very large and very complicated</h1>
<p>The LLVM project has <a href="https://news.ycombinator.com/item?id=34580907#34586552" rel="noreferrer">over 2 million lines, or 1.3 GB, of code</a>. It's one of the largest projects on Github. It's so large that <a href="https://discourse.llvm.org/t/fyi-llvm-project-repo-has-exceeded-github-upload-size-limit/63293" rel="noreferrer">(at least at one point) you couldn't even push it to GitHub without workarounds</a>.</p>
<p>With this, LLVM has a lot of <strong>unnecessary complexity</strong>. There are a lot of features your compiler isn't going to use unless it's C++, and a hobbyist or prototype compiler is <em>definitely</em> not going to use.</p>
<p>LLVM was created and is maintained by lots of talented developers, but nonetheless, a repo that large and complex is going to have issues. <em>The following don't just apply to LLVM, but any large and complicated existing IR</em>:</p>
<ul>
<li><p><strong>Steep learning curve:</strong> Because LLVM is so complex, it takes a lot of effort to understand how to use. See the <a href="https://llvm.org/doxygen/classllvm_1_1Value.html" rel="noreferrer">reference for llvm::Value</a>: there are so many methods and subclasses it's hard to figure out which ones you want and which ones to ignore. There are also many subtle details which can trip up beginners (though off the top of my head I can't think of any examples, I remember this was the case).</p>
</li>
<li><p><strong>Lack of freedom:</strong> If you use LLVM as an IR you're practically required to adhere to LLVM conventions: e.g. <code>Module</code>/<code>Function</code>/<code>BB</code>/<code>Instruction</code>, using <code>...Builder</code>s like <code>IRBuilder</code> to construct values, using llvm <code>Type</code>s and <code>Value</code>s and <code>Metadata</code>. If you use your own IR, you can implement techniques and optimizations which are hard or straight-up impossible in LLVM.</p>
</li>
<li><p><strong>Framework problem (AKA more lack of freedom):</strong> It's not just in the IR. LLVM provides many generic types in the <a href="https://llvm.org/doxygen/dir_32453792af2ba70c54e3ccae3a790d1b.html" rel="noreferrer">ADT</a> module, including its own <a href="https://llvm.org/doxygen/classllvm_1_1StringRef.html" rel="noreferrer">string</a> and <a href="https://llvm.org/doxygen/BitVector_8h.html" rel="noreferrer">bit-vector</a>; though you don't have to, it can be hard avoiding <code>StringRef</code> and <code>BitVector</code> in your own, non-IR code. More likely, you'll unintentionally write your AST and other earlier phases to be easier to translate into LLVM, which may make your language less unique more like C++. Like with most big frameworks, you could accidentally make your entire project revolve around using LLVM, especially if it's a small project and the majority of its code ends up being IR generation and LLVM integration.</p>
</li>
<li><p><strong>Large dependency:</strong> LLVM is 1.3 GB in source, but its install build is about <em>12 GB</em>. This can probably be stripped and minified for a language which only relies on IR and assembly generation, but still, LLVM is going to take up a lot of space in your app's distribution.</p>
</li>
<li><p><strong>Bugs:</strong> In over 2 million lines of code there are definitely a lot of bugs. The GitHub repo has <a href="https://github.com/llvm/llvm-project/issues" rel="noreferrer">over 20,000 open issues</a>.</p>
</li>
<li><p><strong>Hard to debug:</strong> Because LLVM is so large, when there's an internal bug or even when there's not, it's hard to figure out where the bug originated and how to fix it, because you don't understand LLVM's inner workings.</p>
</li>
</ul>
<p>As mentioned, these problems don't just apply to LLVM, but any other large general-purpose IR. If you write your own IR, <strong>you have control</strong>: you can make a small IR which only supports your language's features, and is written in your compiler's code style and design philosophy. This IR will be easier to understand, easier to integrate, easier to extend with features which would be challenging or impossible with LLVM, and easier to debug.</p>
<hr />
<p>Of course this skips over the many benefits of LLVM and other popular IRs, and challenges using a custom IR, like:</p>
<ul>
<li><p>Writing your own IR is hard</p>
</li>
<li><p>LLVM has a very good design philosophy and encourages good practices which may be better than the ones you would use</p>
</li>
<li><p>LLVM has plenty of general-purpose features and optimizations which would be hard to implement yourself</p>
</li>
<li><p>LLVM has a team of experts fixing bugs and constantly making improvements, you won't have to maintain the IR yourself if you use LLVM</p>
</li>
<li><p>and so on</p>
</li>
</ul>
<p>But there are good reasons why you may want to write your own IR. And even if you do end up using LLVM, they are good issues to prepare for and avoid.</p>

CC BY-SA 4.0
2023-07-01T06:01:24.810Z
2023-07-01T06:01:24.810Z
tarzh
CC BY-SA 4.0
2023-07-02T07:05:09.933Z
OK, it's very large and very complicated: but what are the alternatives?
Mark Morgan Lloyd
CC BY-SA 4.0
2023-07-02T19:51:55.273Z
Speaking from real experience: develop your own IR or multiple IRs, and *lower that* to LLVM. This is what Rust (https://rustc-dev-guide.rust-lang.org/overview.html#mir-lowering), Zig (https://github.com/ziglang/zig/blob/master/src/Air.zig), and I believe most other languages do.
tarzh
CC BY-SA 4.0
2023-07-02T19:52:06.177Z
I just listed the downsides. In practice LLVM is usually much easier and better than generating your own assembly, hence why many production languages use it. You often just want to make sure not to be too dependent on LLVM, and simplify the IR generation so there's less room for bugs and it's easier to debug.
tarzh
CC BY-SA 4.0
2023-07-02T20:05:36.300Z
Thanks for that. I find myself wondering whether there's scope for an "LLVM-lite" which uses basically the same code generation stuff but has a simplified API with a less brutal learning curve.
Mark Morgan Lloyd
CC BY-SA 4.0
2023-07-03T09:54:44.253Z
@MarkMorganLloyd obvious alternatives to LLVM: [libFIRM](https://pp.ipd.kit.edu/firm/), [Cranelift](https://github.com/bytecodealliance/wasmtime/tree/main/cranelift), [asmJIT](https://asmjit.com/), [libJIT](https://www.gnu.org/software/libjit/). Also MLIR provides a nice middle-ground between building your own IR completely from scratch and using predefined one, but it's based on LLVM anyway.
Alex Chichigin
CC BY-SA 4.0
2023-07-03T10:08:42.880Z
@AlexChichigin thanks, I always like being instructed in the obvious :-)
Mark Morgan Lloyd
CC BY-SA 4.0
2023-07-03T10:13:42.777Z
@MarkMorganLloyd yeah, sorry for the "obvious"...  I meant these alternatives are very well-known in compilers community and easy to find, I'm not sharing any secrets here. 
Alex Chichigin
CC BY-SA 4.0
2023-07-03T11:48:20.087Z
@AlexChichigin please: I am in no way criticising you. They were obvious in that I should have done a bit more homework before asking about it... but I still feel it's a fair question in the current context.
Mark Morgan Lloyd
CC BY-SA 4.0
2023-07-04T08:07:26.203Z
@MarkMorganLloyd no worries, I don't take it as offensive in any way or capacity.  Yeah, you'd probably find all the same links and some more simply searching for an "LLVM alternative", but this is a question answering site, so your question is 100% fair in my eyes, besides one can hope to get most meaningful links here, from people who already know the answers (not me ). But at the same time I should choose words with more care...
Alex Chichigin
<p>Well, for <a href="https://aecforwebassembly.sourceforge.io" rel="nofollow noreferrer">my AEC-to-WebAssembly compiler</a>, I decided not to use LLVM because I think WebAssembly is an even easier compilation target than LLVM is. To target LLVM, you need to understand what PHI is and what SSA is, whereas you don't need to understand those things if you are targetting WebAssembly.<br/>
Had I targeted x86 and/or ARM, I would have used LLVM, since x86 and ARM are not designed to be easy compilation targets (x86 and ARM are designed to be easy to implement in hardware, without a lot of consideration for the ease of making a compiler targeting them), but WebAssembly is designed to be an easy compilation target.</p>

CC BY-SA 4.0
2023-07-02T15:33:32.097Z
2024-04-23T08:54:24.673Z
2024-04-23T08:54:24.673Z
FlatAssembler
<p>Languages which use a back end like LLVM will be limited to the choice of optimization semantics offered thereby.  In LLVM, for example, seems to analyze the possibility of pointer aliasing by assuming that if a X can be shown to equal some pointer Y, and Y is not based upon Z, then X isn't based upon Z.  That's a silly useless definition of &quot;based upon&quot;, but I a langauge that uses LLVM as a back end will be stuck with those broken semantics unless it foregoes whata should be useful pointer aliasing optimizations.</p>

CC BY-SA 4.0
2023-07-01T05:49:42.200Z
2023-07-01T05:49:42.200Z
supercat
CC BY-SA 4.0
2023-07-01T08:27:46.927Z
A lot of projects use LLVM as middle IR and provide their own back-ends instead. So you're not really that limited, you can cherry-pick what you want from LLVM and do the rest on your own.
SK-logic
CC BY-SA 4.0
2023-07-02T15:05:22.123Z
@SK-logic:  I thought the whole idea of using LLVM was to avoid the need for a machine-dependent back-end.
supercat
CC BY-SA 4.0
2023-07-02T16:14:53.907Z
why? The whole idea is to have a framework of common compiler components, middle-layer and back-end included, but since LLVM is quite opinionated on how back-ends should be organised, it is often more reasonable to have your own back-end outside of LLVM. You still get all of the optimisations and analysis passes LLVM can do, but write your own platform-specific back-end. Also, keep in mind that even LLVM IR from the very top is not platform-independent at all.
SK-logic
CC BY-SA 4.0
2023-07-02T16:24:25.357Z
@SK-logic: I thought compilers targeted LLVM so they could be used to generate code for any architecture which LLVM supports, without having to individually write a code generator for each such platform.  In any case, I've noticed that language implementations which target LLVM tend to have some common limitations on the kinds of useful optimizations they can perform without also performing broken and useless "optimizing" transforms.  If all of the optimizations performed by clang are really performed by LLVM, that would suggest that such limitations are probably inherent to LLVM...
supercat
CC BY-SA 4.0
2023-07-02T16:26:34.430Z
...unless there would be some other way of generating metatada which would result in LLVM being able to process save and useful transformations while avoiding dangerous ones which are less likely to offer useful payoff.
supercat
CC BY-SA 4.0
2023-07-02T17:45:38.700Z
LLVM is a flexible framework. You can run whatever passes you want, and avoid running passes you don't need.
SK-logic
<p>Speed (and other resource usage) probably is the biggest factor in many cases. LLVM, specifically, is slow.</p>
<p>Unfortunately, &quot;help speed up the slow bits&quot; is not a realistic answer, because LLVM's whole infrastructure is slow for an extremely good reason: It was designed primarily as a research and development platform.</p>
<p>You see, LLVM is not a compiler backend. It is a toolkit of pieces that you can build your own compiler backend from. It is designed for flexibility and generality, so that new compilation techniques and new platforms are relatively easy to add.</p>
<p>This flexibility and generality has a cost, and given that compilation speed (or lack thereof) is one of the most important things to a programmer, reducing that cost can pay off in terms of user experience.</p>

CC BY-SA 4.0
2023-07-01T05:16:10.487Z
2023-07-01T05:16:10.487Z
Pseudonym
CC BY-SA 4.0
2023-07-01T06:53:24.417Z
I am really baffled by all the claims of compilation speed being important. People keep saying it, but I did not see any justification or even data to back this claim.. Do you have any links?
SK-logic
CC BY-SA 4.0
2023-07-01T08:34:58.707Z
Are you asking if people don't think LLVM is slow, or are you asking if people aren't using that as a reason to sidestep around LLVM? It's true that "slow" is relative, but it's also true that computers are several orders of magnitude than they were a couple of decades ago, but compilers even in "debug/no optimisation" mode aren't several orders of magnitude faster.
Pseudonym
CC BY-SA 4.0
2023-07-01T08:42:42.613Z
I'm curious about any research into how developers perceive compilation speed and how important it is to different sections of developers population. I see claims like "compilation speed is one of the most important things" a lot, but never seen data to show how exactly important it is.
SK-logic
CC BY-SA 4.0
2023-07-01T12:40:41.357Z
@SK-logic long compilation times means that when you make a change and  hit the compile and run button you end up waiting and very likely disengage mentally and switch to looking at something else (either some other bit of code or social media) then need to recontext switch back to what you changed when the compile is done.
ratchet freak
CC BY-SA 4.0
2023-07-01T12:43:15.200Z
@ratchetfreak that's all good in theory - I'm looking for actual solid data that shows the impact of long compilation. Coming from an industry where many hours compilation time is pretty typical, I may be a bit biased here, but everything needs evidence anyway, right?
SK-logic
CC BY-SA 4.0
2023-07-01T14:08:58.807Z
@SK-logic data point of one, but it matters so much to me that it's the second-biggest reason I don't use Rust. (First is complexity, and third is async.) I also don't think you need to have evidence on compilation times in particular; you could look up general research on feedback loop sizes, and that's clear: the smaller the feedback loop, the easier it is to make changes. Data point of one, but my quick compilation loop is one reason I refactor so much and don't have technical debt.
Gavin D. Howard
CC BY-SA 4.0
2023-07-01T14:32:47.243Z
@GavinD.Howard I see, fair enough. Probably my approach is just way too different as I don't see much value in a very fast feedback loop - but I imagine there might be people who need it for productivity.
SK-logic
CC BY-SA 4.0
2023-07-02T16:28:51.523Z
@SK-logic: Back in the 1990s, I observed that programmers with slow compilers would spend more on faster computers to minimize time spent waiting for their programs to compile, which would in turn make them less sensitive to how long their programmers would take to run on the kinds of equipment customers would be more likely to have,.
supercat
CC BY-SA 4.0
2023-07-02T16:32:29.670Z
@SK-logic: Besides, I'd say the continued use of tools like "make" is pretty strong evidence of the fact that faster compilation times are desirable.  If doing full builds wouldn't take an objectionably long time, simply using a script to process everything on every build would be simpler and easier than bothering with makefiles and dealing with issues that may result if e.g. one reverts a source file to an earlier version without having the time stamp get set later than build artifacts produced from it.
supercat
CC BY-SA 4.0
2023-07-02T16:34:50.017Z
@SK-logic: If there were an open-source compiler that was conceptually similar to tcc, but which targeted platforms for which I'd write C code (mostly ARM), and incorporated 1990s-style "optimizations", I'd switch to it in a heartbeat.
supercat
CC BY-SA 4.0
2023-07-02T17:44:26.750Z
@supercat in my trade, overnight compilation is a norm. It is ok. Just make sure you write correct code...
SK-logic
CC BY-SA 4.0
2023-07-02T17:52:39.723Z
@SK-logic:: It depends what one is doing.  If one is writing code to produce graphics, sounds, or other kinds of user experience, there's often no single "right" or "wrong" ways of doing things, but rather a continuum of better and worse ways whose quality can best be judged through experimentation.  If one were stuck with overnight compilers, then maybe one could use a pen, graph paper, and stop motion camera to figure out what a program's animation woudl look like without having to wait all night for the program to build, but having a faster compiler would seem more practical.
supercat
CC BY-SA 4.0
2023-07-02T19:08:57.453Z
@supercat indeed - I'm very interested in what Bret Victor was proposing, and I certainly see the value of very fast feedback loops. All I want to know is how many programmers really need it, how many problem domains depend on such feedback - since my own anecdotal experience shows there's quite a few domains where nobody really care. So the only useful answer here can be some statistics accumulated on a sizeable selection of developers. Only then it'll be useful for compiler developers to judge when speed is important and when it's not.
SK-logic
<p>There's not always a whole lot you can do if the backend has bugs. Consider <a href="https://github.com/ziglang/zig/issues/16270" rel="noreferrer">this recent issue</a> for Zig, which discusses using their own backend instead of LLVM. One of the advantages listed is, and I quote:</p>
<blockquote>
<ul>
<li>All our bugs are belong to us.</li>
</ul>
</blockquote>
<p>Further down the thread, a different user also brings up &quot;the existence of many bugs that are LLVM's fault&quot;.</p>

CC BY-SA 4.0
2023-07-01T03:55:11.943Z
2023-07-01T03:55:11.943Z
Bbrk24
CC BY-SA 4.0
2023-07-01T06:55:49.220Z
They also mention that LLVM is big, compile times are long and it doesn't support as many targets as you might hope.
Bruce Adams
CC BY-SA 4.0
2023-07-01T08:26:28.573Z
Not sure it's really such an issue. LLVM is open source and got a very permissive license. If you find bugs there - just fix bugs, easy.  Bring your own LLVM build with your project, it's always a bad idea to rely on some pre-packaged version from elsewhere. Getting your fixes back into upstream can be a somewhat more complicated story though, but, again, just maintaining your own fork is also not such a big deal.
SK-logic
CC BY-SA 4.0
2023-07-01T12:15:05.543Z
@SK-logic OTOH, fixing the bugs requires you to understand how LLVM works under the hood, which is not always going to be the case (especially if you chose to use LLVM so that you _didn’t_ need to worry about that stuff).
Austin Hemmelgarn
CC BY-SA 4.0
2023-07-01T12:44:44.023Z
@AustinHemmelgarn true, but I guess writing half of LLVM on your own and knowing that code base well enough to debug still requires a bit more effort than simply learning LLVM.
SK-logic
<p>It's hard to speak about all the IR frameworks/backends out there at once, but pretty much all of them are inflexible in some way and thus suitable only to certain types of languages and not others.</p>
<p>In particular, LLVM is kinda famous for being C/C++ centric, even Rust encountered a number of bugs/shortcomings/problems/inefficiencies that weren't an issue for C/C++ and thus were just hanging there for years unnoticed. All while Rust being low-level language pretty close to C/C++. The further you go the more trouble you encounter: it's well-known that adding a GC to LLVM is still hard and cumbersome. Implementing a <em>lazy</em> language is even harder and inefficient: LLVM backend for GHC Haskell do exist but it's slower than GCC through C--.</p>
<p>From the opposite side I've heard it's hard to add somewhat unconventional code generators to LLVM, like VLIW architectures. Again I've heard people more often use libFIRM for such projects (specialized microcontrollers, DSPs, etc.).</p>
<p>I guess you can find this or that shortcomings in any backend/framework. On the other hand, if you're implementing pretty conventional language, target common hardware and/or not aiming for ultimate performance and efficiency, any reasonable framework (LLVM, Cranelift, asmJIT, etc.) might serve you just fine and save enormous efforts.</p>

CC BY-SA 4.0
2023-07-03T10:11:02.673Z
2023-07-03T10:11:02.673Z
Alex Chichigin
CC BY-SA 4.0
2023-08-03T22:24:40.697Z
A lot of the behaviors that were objectionable for Rust weren't appropriate in C compilers intended for low-level programming either, and some are fundamentally broken even in C.
supercat
CC BY-SA 4.0
2023-08-04T10:10:18.450Z
@supercat that's true, but that's a bit different story. We're talking about bugs here, and nobody's surprised there are bugs in LLVM/Clang affecting C/C++. The fact that there are bugs that **don't** affect C/C++ but affect _other_ languages is kinda more surprising. But quite expected in hindsight: you can't test LLVM for a language that doesn't yet exist. That means if you're developing a new language, you're likely to uncover new bugs like Rust did. That's the point. And the bigger the framework, the more hidden bugs it's expected to have.
Alex Chichigin
CC BY-SA 4.0
2023-08-04T16:25:37.253Z
The issue isn't just bugs, but *deliberate assumptions* that were engineered in based on either a faulty belief that they're sound under the rules of C, or a belief that any situations where the C Standard would render them unsound represent defects in the Standard, ignoring the possibility that the Standard may have been intended not to allow such assumptions in the first place.
supercat
CC BY-SA 4.0
2023-08-04T16:31:39.357Z
For example, clang will assume that if two pointers P and Q compare equal, they may be used interchangeably, at the same time as it exploits assumptions that objects based on different objects won't alias, ignoring the possibility that a comparison between pointers based on different objects may report them equal.  This assumption might be legitimate if clang ensured that there was always at least one padding byte between objects identified by external symbols, and specified that any other tools generating code to be linked with clang must do likewise, but clang doesn't do that.
supercat
# What are the pitfalls of using an existing IR/compiler infrastructure like LLVM?
Posted by: username_0 on 2023-07-01
Using something like [LLVM](https://llvm.org/) when designing a compiler has a lot of advantages, since tons of work can be saved by using an existing optimizer and code generation for a variety of platforms. Even large, popular languages like Rust and Julia use LLVM, and LLVM implementations of languages like Go and Kotlin exist.

However, I'd assume some downsides exist to using an existing back-end. Compile time is one I've seen mentioned in the context of Rust, and I'd assume you lose some flexibility in how you compile and optimize your code when using a pre-existing compiler infrastructure.

What are some pitfalls/downsides of using an existing IR/optimizer/compiler infrastructure for a compiled language (as opposed to writing your own, rather than transpilation/bytecode)?
**Tags:** compilers optimization backend llvm
> **Comments:**
> **username_1**: It's worth noting that the Kotlin compiler isn't "just another third party compiler." It's the official backend for Kotlin/Native  
---
## 6 answers
### Answer by username_2 on 2023-07-01. Score: 22
# Very large and very complicated

The LLVM project has [over 2 million lines, or 1.3 GB, of code](https://news.ycombinator.com/item?id=34580907#34586552). It's one of the largest projects on Github. It's so large that [(at least at one point) you couldn't even push it to GitHub without workarounds](https://discourse.llvm.org/t/fyi-llvm-project-repo-has-exceeded-github-upload-size-limit/63293).

With this, LLVM has a lot of **unnecessary complexity**. There are a lot of features your compiler isn't going to use unless it's C++, and a hobbyist or prototype compiler is *definitely* not going to use.

LLVM was created and is maintained by lots of talented developers, but nonetheless, a repo that large and complex is going to have issues. *The following don't just apply to LLVM, but any large and complicated existing IR*:

* **Steep learning curve:** Because LLVM is so complex, it takes a lot of effort to understand how to use. See the [reference for llvm::Value](https://llvm.org/doxygen/classllvm_1_1Value.html): there are so many methods and subclasses it's hard to figure out which ones you want and which ones to ignore. There are also many subtle details which can trip up beginners (though off the top of my head I can't think of any examples, I remember this was the case).
* **Lack of freedom:** If you use LLVM as an IR you're practically required to adhere to LLVM conventions: e.g. `Module`/`Function`/`BB`/`Instruction`, using `...Builder`s like `IRBuilder` to construct values, using llvm `Type`s and `Value`s and `Metadata`. If you use your own IR, you can implement techniques and optimizations which are hard or straight-up impossible in LLVM.
* **Framework problem (AKA more lack of freedom):** It's not just in the IR. LLVM provides many generic types in the [ADT](https://llvm.org/doxygen/dir_32453792af2ba70c54e3ccae3a790d1b.html) module, including its own [string](https://llvm.org/doxygen/classllvm_1_1StringRef.html) and [bit-vector](https://llvm.org/doxygen/BitVector_8h.html); though you don't have to, it can be hard avoiding `StringRef` and `BitVector` in your own, non-IR code. More likely, you'll unintentionally write your AST and other earlier phases to be easier to translate into LLVM, which may make your language less unique more like C++. Like with most big frameworks, you could accidentally make your entire project revolve around using LLVM, especially if it's a small project and the majority of its code ends up being IR generation and LLVM integration.
* **Large dependency:** LLVM is 1.3 GB in source, but its install build is about *12 GB*. This can probably be stripped and minified for a language which only relies on IR and assembly generation, but still, LLVM is going to take up a lot of space in your app's distribution.
* **Bugs:** In over 2 million lines of code there are definitely a lot of bugs. The GitHub repo has [over 20,000 open issues](https://github.com/llvm/llvm-project/issues).
* **Hard to debug:** Because LLVM is so large, when there's an internal bug or even when there's not, it's hard to figure out where the bug originated and how to fix it, because you don't understand LLVM's inner workings.

As mentioned, these problems don't just apply to LLVM, but any other large general-purpose IR. If you write your own IR, **you have control**: you can make a small IR which only supports your language's features, and is written in your compiler's code style and design philosophy. This IR will be easier to understand, easier to integrate, easier to extend with features which would be challenging or impossible with LLVM, and easier to debug.

---

Of course this skips over the many benefits of LLVM and other popular IRs, and challenges using a custom IR, like:

* Writing your own IR is hard
* LLVM has a very good design philosophy and encourages good practices which may be better than the ones you would use
* LLVM has plenty of general-purpose features and optimizations which would be hard to implement yourself
* LLVM has a team of experts fixing bugs and constantly making improvements, you won't have to maintain the IR yourself if you use LLVM
* and so on

But there are good reasons why you may want to write your own IR. And even if you do end up using LLVM, they are good issues to prepare for and avoid.
> **Comments:**
> **username_3** (2023-07-02): OK, it's very large and very complicated: but what are the alternatives?  
> **username_2** (2023-07-02): Speaking from real experience: develop your own IR or multiple IRs, and *lower that* to LLVM. This is what Rust (https://rustc-dev-guide.rust-lang.org/overview.html#mir-lowering), Zig (https://github.com/ziglang/zig/blob/master/src/Air.zig), and I believe most other languages do.  
> **username_2** (2023-07-02): I just listed the downsides. In practice LLVM is usually much easier and better than generating your own assembly, hence why many production languages use it. You often just want to make sure not to be too dependent on LLVM, and simplify the IR generation so there's less room for bugs and it's easier to debug.  
> **username_3** (2023-07-02): Thanks for that. I find myself wondering whether there's scope for an "LLVM-lite" which uses basically the same code generation stuff but has a simplified API with a less brutal learning curve.  
> **username_4** (2023-07-03): @MarkMorganLloyd obvious alternatives to LLVM: [libFIRM](https://pp.ipd.kit.edu/firm/), [Cranelift](https://github.com/bytecodealliance/wasmtime/tree/main/cranelift), [asmJIT](https://asmjit.com/), [libJIT](https://www.gnu.org/software/libjit/). Also MLIR provides a nice middle-ground between building your own IR completely from scratch and using predefined one, but it's based on LLVM anyway.  
> **username_3** (2023-07-03): @AlexChichigin thanks, I always like being instructed in the obvious :-)  
> **username_4** (2023-07-03): @MarkMorganLloyd yeah, sorry for the "obvious"...  I meant these alternatives are very well-known in compilers community and easy to find, I'm not sharing any secrets here.   
> **username_3** (2023-07-03): @AlexChichigin please: I am in no way criticising you. They were obvious in that I should have done a bit more homework before asking about it... but I still feel it's a fair question in the current context.  
> **username_4** (2023-07-04): @MarkMorganLloyd no worries, I don't take it as offensive in any way or capacity.  Yeah, you'd probably find all the same links and some more simply searching for an "LLVM alternative", but this is a question answering site, so your question is 100% fair in my eyes, besides one can hope to get most meaningful links here, from people who already know the answers (not me ). But at the same time I should choose words with more care...  
---
### Answer by username_11 on 2023-07-01. Score: 7
There's not always a whole lot you can do if the backend has bugs. Consider [this recent issue](https://github.com/ziglang/zig/issues/16270) for Zig, which discusses using their own backend instead of LLVM. One of the advantages listed is, and I quote:

> * All our bugs are belong to us.

Further down the thread, a different user also brings up "the existence of many bugs that are LLVM's fault".
> **Comments:**
> **username_12** (2023-07-01): They also mention that LLVM is big, compile times are long and it doesn't support as many targets as you might hope.  
> **username_7** (2023-07-01): Not sure it's really such an issue. LLVM is open source and got a very permissive license. If you find bugs there - just fix bugs, easy.  Bring your own LLVM build with your project, it's always a bad idea to rely on some pre-packaged version from elsewhere. Getting your fixes back into upstream can be a somewhat more complicated story though, but, again, just maintaining your own fork is also not such a big deal.  
> **username_13** (2023-07-01): @SK-logic OTOH, fixing the bugs requires you to understand how LLVM works under the hood, which is not always going to be the case (especially if you chose to use LLVM so that you _didn’t_ need to worry about that stuff).  
> **username_7** (2023-07-01): @AustinHemmelgarn true, but I guess writing half of LLVM on your own and knowing that code base well enough to debug still requires a bit more effort than simply learning LLVM.  
---
### Answer by username_5 on 2023-07-02. Score: 5
Well, for [my AEC-to-WebAssembly compiler](https://aecforwebassembly.sourceforge.io), I decided not to use LLVM because I think WebAssembly is an even easier compilation target than LLVM is. To target LLVM, you need to understand what PHI is and what SSA is, whereas you don't need to understand those things if you are targetting WebAssembly.  
Had I targeted x86 and/or ARM, I would have used LLVM, since x86 and ARM are not designed to be easy compilation targets (x86 and ARM are designed to be easy to implement in hardware, without a lot of consideration for the ease of making a compiler targeting them), but WebAssembly is designed to be an easy compilation target.
---
### Answer by username_6 on 2023-07-01. Score: 4
Languages which use a back end like LLVM will be limited to the choice of optimization semantics offered thereby. In LLVM, for example, seems to analyze the possibility of pointer aliasing by assuming that if a X can be shown to equal some pointer Y, and Y is not based upon Z, then X isn't based upon Z. That's a silly useless definition of "based upon", but I a langauge that uses LLVM as a back end will be stuck with those broken semantics unless it foregoes whata should be useful pointer aliasing optimizations.
> **Comments:**
> **username_7** (2023-07-01): A lot of projects use LLVM as middle IR and provide their own back-ends instead. So you're not really that limited, you can cherry-pick what you want from LLVM and do the rest on your own.  
> **username_6** (2023-07-02): @SK-logic:  I thought the whole idea of using LLVM was to avoid the need for a machine-dependent back-end.  
> **username_7** (2023-07-02): why? The whole idea is to have a framework of common compiler components, middle-layer and back-end included, but since LLVM is quite opinionated on how back-ends should be organised, it is often more reasonable to have your own back-end outside of LLVM. You still get all of the optimisations and analysis passes LLVM can do, but write your own platform-specific back-end. Also, keep in mind that even LLVM IR from the very top is not platform-independent at all.  
> **username_6** (2023-07-02): @SK-logic: I thought compilers targeted LLVM so they could be used to generate code for any architecture which LLVM supports, without having to individually write a code generator for each such platform.  In any case, I've noticed that language implementations which target LLVM tend to have some common limitations on the kinds of useful optimizations they can perform without also performing broken and useless "optimizing" transforms.  If all of the optimizations performed by clang are really performed by LLVM, that would suggest that such limitations are probably inherent to LLVM...  
> **username_6** (2023-07-02): ...unless there would be some other way of generating metatada which would result in LLVM being able to process save and useful transformations while avoiding dangerous ones which are less likely to offer useful payoff.  
> **username_7** (2023-07-02): LLVM is a flexible framework. You can run whatever passes you want, and avoid running passes you don't need.  
---
### Answer by username_8 on 2023-07-01. Score: 4
Speed (and other resource usage) probably is the biggest factor in many cases. LLVM, specifically, is slow.

Unfortunately, "help speed up the slow bits" is not a realistic answer, because LLVM's whole infrastructure is slow for an extremely good reason: It was designed primarily as a research and development platform.

You see, LLVM is not a compiler backend. It is a toolkit of pieces that you can build your own compiler backend from. It is designed for flexibility and generality, so that new compilation techniques and new platforms are relatively easy to add.

This flexibility and generality has a cost, and given that compilation speed (or lack thereof) is one of the most important things to a programmer, reducing that cost can pay off in terms of user experience.
> **Comments:**
> **username_7** (2023-07-01): I am really baffled by all the claims of compilation speed being important. People keep saying it, but I did not see any justification or even data to back this claim.. Do you have any links?  
> **username_8** (2023-07-01): Are you asking if people don't think LLVM is slow, or are you asking if people aren't using that as a reason to sidestep around LLVM? It's true that "slow" is relative, but it's also true that computers are several orders of magnitude than they were a couple of decades ago, but compilers even in "debug/no optimisation" mode aren't several orders of magnitude faster.  
> **username_7** (2023-07-01): I'm curious about any research into how developers perceive compilation speed and how important it is to different sections of developers population. I see claims like "compilation speed is one of the most important things" a lot, but never seen data to show how exactly important it is.  
> **username_9** (2023-07-01): @SK-logic long compilation times means that when you make a change and  hit the compile and run button you end up waiting and very likely disengage mentally and switch to looking at something else (either some other bit of code or social media) then need to recontext switch back to what you changed when the compile is done.  
> **username_7** (2023-07-01): @ratchetfreak that's all good in theory - I'm looking for actual solid data that shows the impact of long compilation. Coming from an industry where many hours compilation time is pretty typical, I may be a bit biased here, but everything needs evidence anyway, right?  
> **username_10** (2023-07-01): @SK-logic data point of one, but it matters so much to me that it's the second-biggest reason I don't use Rust. (First is complexity, and third is async.) I also don't think you need to have evidence on compilation times in particular; you could look up general research on feedback loop sizes, and that's clear: the smaller the feedback loop, the easier it is to make changes. Data point of one, but my quick compilation loop is one reason I refactor so much and don't have technical debt.  
> **username_7** (2023-07-01): @GavinD.Howard I see, fair enough. Probably my approach is just way too different as I don't see much value in a very fast feedback loop - but I imagine there might be people who need it for productivity.  
> **username_6** (2023-07-02): @SK-logic: Back in the 1990s, I observed that programmers with slow compilers would spend more on faster computers to minimize time spent waiting for their programs to compile, which would in turn make them less sensitive to how long their programmers would take to run on the kinds of equipment customers would be more likely to have,.  
> **username_6** (2023-07-02): @SK-logic: Besides, I'd say the continued use of tools like "make" is pretty strong evidence of the fact that faster compilation times are desirable.  If doing full builds wouldn't take an objectionably long time, simply using a script to process everything on every build would be simpler and easier than bothering with makefiles and dealing with issues that may result if e.g. one reverts a source file to an earlier version without having the time stamp get set later than build artifacts produced from it.  
> **username_6** (2023-07-02): @SK-logic: If there were an open-source compiler that was conceptually similar to tcc, but which targeted platforms for which I'd write C code (mostly ARM), and incorporated 1990s-style "optimizations", I'd switch to it in a heartbeat.  
> **username_7** (2023-07-02): @supercat in my trade, overnight compilation is a norm. It is ok. Just make sure you write correct code...  
> **username_6** (2023-07-02): @SK-logic:: It depends what one is doing.  If one is writing code to produce graphics, sounds, or other kinds of user experience, there's often no single "right" or "wrong" ways of doing things, but rather a continuum of better and worse ways whose quality can best be judged through experimentation.  If one were stuck with overnight compilers, then maybe one could use a pen, graph paper, and stop motion camera to figure out what a program's animation woudl look like without having to wait all night for the program to build, but having a faster compiler would seem more practical.  
> **username_7** (2023-07-02): @supercat indeed - I'm very interested in what Bret Victor was proposing, and I certainly see the value of very fast feedback loops. All I want to know is how many programmers really need it, how many problem domains depend on such feedback - since my own anecdotal experience shows there's quite a few domains where nobody really care. So the only useful answer here can be some statistics accumulated on a sizeable selection of developers. Only then it'll be useful for compiler developers to judge when speed is important and when it's not.  
---
### Answer by username_4 on 2023-07-03. Score: 3
It's hard to speak about all the IR frameworks/backends out there at once, but pretty much all of them are inflexible in some way and thus suitable only to certain types of languages and not others.

In particular, LLVM is kinda famous for being C/C++ centric, even Rust encountered a number of bugs/shortcomings/problems/inefficiencies that weren't an issue for C/C++ and thus were just hanging there for years unnoticed. All while Rust being low-level language pretty close to C/C++. The further you go the more trouble you encounter: it's well-known that adding a GC to LLVM is still hard and cumbersome. Implementing a *lazy* language is even harder and inefficient: LLVM backend for GHC Haskell do exist but it's slower than GCC through C--.

From the opposite side I've heard it's hard to add somewhat unconventional code generators to LLVM, like VLIW architectures. Again I've heard people more often use libFIRM for such projects (specialized microcontrollers, DSPs, etc.).

I guess you can find this or that shortcomings in any backend/framework. On the other hand, if you're implementing pretty conventional language, target common hardware and/or not aiming for ultimate performance and efficiency, any reasonable framework (LLVM, Cranelift, asmJIT, etc.) might serve you just fine and save enormous efforts.
> **Comments:**
> **username_6** (2023-08-03): A lot of the behaviors that were objectionable for Rust weren't appropriate in C compilers intended for low-level programming either, and some are fundamentally broken even in C.  
> **username_4** (2023-08-04): @supercat that's true, but that's a bit different story. We're talking about bugs here, and nobody's surprised there are bugs in LLVM/Clang affecting C/C++. The fact that there are bugs that **don't** affect C/C++ but affect _other_ languages is kinda more surprising. But quite expected in hindsight: you can't test LLVM for a language that doesn't yet exist. That means if you're developing a new language, you're likely to uncover new bugs like Rust did. That's the point. And the bigger the framework, the more hidden bugs it's expected to have.  
> **username_6** (2023-08-04): The issue isn't just bugs, but *deliberate assumptions* that were engineered in based on either a faulty belief that they're sound under the rules of C, or a belief that any situations where the C Standard would render them unsound represent defects in the Standard, ignoring the possibility that the Standard may have been intended not to allow such assumptions in the first place.  
> **username_6** (2023-08-04): For example, clang will assume that if two pointers P and Q compare equal, they may be used interchangeably, at the same time as it exploits assumptions that objects based on different objects won't alias, ignoring the possibility that a comparison between pointers based on different objects may report them equal.  This assumption might be legitimate if clang ensured that there was always at least one padding byte between objects identified by external symbols, and specified that any other tools generating code to be linked with clang must do likewise, but clang doesn't do that.  
---
