[HN Gopher] LLVM: The bad parts
___________________________________________________________________
LLVM: The bad parts
Author : vitaut
Score : 256 points
Date : 2026-01-12 14:18 UTC (8 hours ago)
(HTM) web link (www.npopov.com)
(TXT) w3m dump (www.npopov.com)
| neuroelectron wrote:
| It's amazing to me that this is trusted to build so much of
| software. It's basically impossible to audit yet Rust is supposed
| to be safe. It's a pipe dream that it will ever be complete or
| Rust will deprecate it. I think infinite churn is the point.
| hu3 wrote:
| Go is sometimes criticised for not using LLVM but I think they
| made the right choice.
|
| For starters the tooling would be much slower if it required
| LLVM.
| phplovesong wrote:
| Also OCaml. Having a own compiler is THE way for language
| development. IMHO.
| anonymous908213 wrote:
| Personally I think a happy medium is to compile to C99.
| Then, after your own compiler's high-level syntax
| transformation pass, you can pass it through the Tiny C
| Compiler which is somewhere on the order of ~10x faster
| than Clang -O0. When you need performance optimizations at
| the cost of build speed, or to support a compilation target
| that TCC does not, you can freely switch to compiling with
| Clang, getting much of the value of LLVM without ever
| specifically targeting it. This is what I do for my own
| language, and it makes my life significantly easier and is
| perfectly sufficient for my use, since as with most
| languages my language will never be used by millions of
| people (or perhaps only ever one person, as I have not
| deigned to publish it).
|
| I think writing a compiler targeting machine code from
| scratch only really makes sense if you have Google's
| resources, as Go did. That includes both the money and the
| talent pool of employees that can be assigned to work on
| the task full-time; not everyone has Ken Thompson lying
| around on payroll. To do better than LLVM is a herculean
| feat, and most languages will never be mainstream enough to
| justify the undertaking; indeed I think an undertaking of
| that scale would prevent a language from ever getting far
| enough along to attract users/contributors if it doesn't
| already have powerful backing from day 0.
| simonask wrote:
| That might be convenient if your language has semantics
| that map well-ish to C99 semantics. But C is a really
| messy language with lots of little quirks. For example,
| Rust code would compile to something slower if it had to
| use C as an intermediate representation.
|
| Also, compiled languages want accurate and rich debug
| info. All of that information would be lost.
| tubs wrote:
| You can track debug symbol through c. It's just one of
| many layers debug info gets tracked through.
| pornel wrote:
| Rust does its own testing, and regularly helps fix issues in
| LLVM (which usually also benefits clang users and other LLVM
| languages).
|
| Optimizing compilers are basically impossible to audit, but
| there are tools like alive2 for checking them.
| bigstrat2003 wrote:
| > I think infinite churn is the point.
|
| That would require the LLVM devs to be stupid and/or evil. As
| that is not the case, your supposition is not true either. They
| might be willing to accept churn in the service of other goals,
| but they don't have churn as a goal unto itself.
| pizlonator wrote:
| This is a good write up and I agree with pretty much all of it.
|
| Two comments:
|
| - LLVM IR is actually remarkably stable these days. I was able to
| rebase Fil-C from llvm 17 to 20 in a single day of work. In other
| projects I've maintained a LLVM pass that worked across multiple
| llvm versions and it was straightforward to do.
|
| - LICM register pressure is a big issue especially when the
| source isn't C or C++. I don't think the problem here is
| necessarily licm. It might be that regalloc needs to be taught to
| rematerialize
| theresistor wrote:
| > It might be that regalloc needs to be taught to rematerialize
|
| It knows how to rematerialize, and has for a long time, but the
| backend is generally more local/has less visibility than the
| optimizer. This causes it to struggle to consistently undo bad
| decisions LICM may have made.
| pizlonator wrote:
| > It knows how to rematerialize
|
| That's very cool, I didn't realize that.
|
| > but the backend is generally more local/has less visibility
| than the optimizer
|
| I don't really buy that. It's operating on SSA, so it has
| exactly the same view as LICM in practice (to my knowledge
| LICM doesn't cross function boundary).
|
| LICM can't possibly know the cost of hoisting. Regalloc does
| have decent visibility into cost. Hence why this feels like a
| regalloc remat problem to me
| CalChris wrote:
| > to my knowledge LICM doesn't cross function boundary
|
| LICM is called with runOnLoop() but is called _after_
| function inlining. Inlining enlarges functions, possibly
| revealing more invariants.
| pizlonator wrote:
| Sure. Any pass that is scoped to functions (or even
| loops, or basic blocks) will have increased scope if run
| after inlining, and most passes run after inlining.
|
| In the context of this thread, your observation is not
| meaningful. The point is: LICM doesn't cross function
| boundary and neither does regalloc, so LICM has no
| greater scope than regalloc.
| fooker wrote:
| There is a rematerialize pass, there is no real reason to
| couple it with register allocation. LLVM regalloc is already
| somewhat subpar.
|
| What would be neat is to expose all right knobs and levers so
| that frontend writers can benchmark a number of possibilities
| and choose the right values.
|
| I can understand this is easier said than done of course.
| pizlonator wrote:
| > There is a rematerialize pass, there is no real reason to
| couple it with register allocation
|
| The reason to couple it to regalloc is that you only want to
| remat if it saves you a spill
| fooker wrote:
| Remat can produce a performance boost even when everything
| has a register.
|
| Admittedly, this comes up more often in non-CPU backends.
| pizlonator wrote:
| > Remat can produce a performance boost even when
| everything has a register.
|
| Can you give an example?
| fooker wrote:
| Rematerializing 'safe' computation from across a barrier
| or thread sync/wait works wonders.
|
| Also loads and stores and function calls, but that's a
| bit finicky to tune. We usually tell people to update
| their programs when this is needed.
| pizlonator wrote:
| > Rematerializing 'safe' computation from across a
| barrier or thread sync/wait works wonders.
|
| While this is literally "rematerialization", it's such a
| different case of remat from what I'm talking about that
| it should be a different phase. It's optimizing for a
| different goal.
|
| Also feels very GPU specific. So I'd imagine this being a
| pass you only add to the pipeline if you know you're
| targeting a GPU.
|
| > Also loads and stores and function calls, but that's a
| bit finicky to tune. We usually tell people to update
| their programs when this is needed.
|
| This also feels like it's gotta be GPU specific.
|
| No chance that doing this on a CPU would be a speed-up
| unless it saved you reg pressure.
| weinzierl wrote:
| _" LLVM IR is actually remarkably stable these days."_
|
| I'm by no means an LLVM expert but my take away from when I
| played with it a couple of years ago was that it is more like
| the union of different languages. Every tool and component in
| the LLVM universe had its own set of rules and requirements for
| the LLVM IR that it understands. The IR is more like a common
| vocabulary than a common language.
|
| My bewilderment about LLVM IR not being stable between versions
| had given way to understanding that this freedom was necessary.
|
| Do you think I misunderstood?
| enos_feedler wrote:
| This take makes sense in the context of MLIR creation which
| introduces dialects which are namespaces within the IR. Given
| it was created by Chris Lattner I would guess he saw these
| problems with LLVM as well.
| pizlonator wrote:
| > like the union of different languages
|
| No. Here are two good ways to think about it:
|
| 1. It's the C programming language represented as SSA form
| and with some of the UB in the C spec given a strict
| definition.
|
| 2. It's a low level representation. It's suitable for
| lowering other languages to. Theoretically, you could lower
| anything to it since it's Turing-complete. Practically, it's
| only suitable for lowering sufficiently statically-typed
| languages to it.
|
| > Every tool and component in the LLVM universe had its own
| set of rules and requirements for the LLVM IR that it
| understands.
|
| Definitely not. All of those tools have a shared
| understanding of what happens when LLVM executes on a
| particular target and data layout.
|
| The only flexibility is that you're allowed to alter _some_
| of the semantics on a per-target and per-datalayout basis.
| Targets have limited power to change semantics (for example,
| they cannot change what "add" means). Data layout is its own
| IR, and that IR has its own semantics - and everything that
| deals with LLVM IR has to deal with the data layout "IR" and
| has to understand it the same way.
|
| > My bewilderment about LLVM IR not being stable between
| versions had given way to understanding that this freedom was
| necessary.
|
| Not parsing this statement very well, but bottom line: LLVM
| IR is remarkably stable because of Hyrum's law within the
| LLVM project's repository. There's a TON of code in LLVM that
| deals with LLVM IR. So, it's super hard to change even the
| smallest things about how LLVM IR works or what it means,
| because any such change would surely break at least one of
| the many things in the LLVM project's repo.
| jcranmer wrote:
| > 1. It's the C programming language represented as SSA
| form and with some of the UB in the C spec given a strict
| definition.
|
| This is becoming steadily less true over time, as LLVM IR
| is growing somewhat more divorced from C/C++, but that's
| probably a good way to start thinking about it if you're
| comfortable with C's corner case semantics.
|
| (In terms of frontends, I've seen "Rust needs/wants this"
| as much as Clang these days, and Flang and Julia are also
| pretty relevant for some things.)
|
| There's currently a working group in LLVM on building
| better, LLVM-based semantics, and the current topic du jour
| of that WG is a byte type proposal.
| pizlonator wrote:
| > This is becoming steadily less true over time, as LLVM
| IR is growing somewhat more divorced from C/C++, but
| that's probably a good way to start thinking about it if
| you're comfortable with C's corner case semantics.
|
| First of all, you're right. I'm going to reply with
| amusing pedantry but I'm not really disagreeing
|
| I feel like in some ways LLVM is becoming more like C-in-
| SSA...
|
| > and the current topic du jour of that WG is a byte type
| proposal.
|
| That's a case of becoming more like C! C has pointer
| provenance and the idea that byte copies can copy "more"
| than just the 8 bits, somehow.
|
| (The C provenance proposal may be in a state where it's
| not officially part of the spec - I'm not sure exactly -
| but it's _effectively_ part of the language in the sense
| that a lot of us already consider it to be part of the
| language.)
| jcranmer wrote:
| The C pointer provenance is still in TS form and is
| largely constructed by trying to retroactively justify
| the semantics of existing compilers (which all follow
| some form of pointer provenance, just not necessarily
| coherently). This is still an area where we have a decent
| idea of what we want the semantics to be but it's
| challenging to come up with a working formalization.
|
| I'd have to double-check, but my recollection is that the
| current TS doesn't actually require that you be able to
| implement user-written memcpy, rather it's just something
| that the authors threw their hands up and said "we hope
| compilers support this, but we can't specify how." In
| that sense, byte type is going beyond what C does.
| pizlonator wrote:
| > The C pointer provenance is still in TS form and is
| largely constructed by trying to retroactively justify
| the semantics of existing compilers
|
| That's my understanding too
|
| > I'd have to double-check, but my recollection is that
| the current TS doesn't actually require that you be able
| to implement user-written memcpy, rather it's just
| something that the authors threw their hands up and said
| "we hope compilers support this, but we can't specify
| how."
|
| That's also my understanding
|
| > In that sense, byte type is going beyond what C does.
|
| I disagree, but only because I probably define "C"
| differently than you.
|
| "C", to me, isn't what the spec describes. If you define
| "C" as what the spec describes, then almost zero C
| programs are "C". (Source: in the process of making
| Fil-C, I experimented with various points on the spectrum
| here and have high confidence that to compile any real C
| program you need to go far beyond what the spec
| promises.)
|
| To me, when we say "C", we are really talking about:
|
| - What real C programs expect to happen.
|
| - What real C compilers (like LLVM) make happen.
|
| In that sense, the byte type is a case of LLVM hardening
| the guarantee that it already makes to real C programs.
|
| So, LLVM having a byte type is a necessary component of
| LLVM supporting C-as-everyone-practically-it.
|
| Also, I would guess that we wouldn't be talking about the
| byte type if it wasn't for C. Type safe languages with
| well-defined semantics have no need for allowing the user
| to write a byte-copy loop that does the right thing if it
| copies data of arbitrary type
|
| (Please correct me if I'm wrong, this is fun)
| uecker wrote:
| The C standard has a conformance model that distinguishes
| between "strictly conforming" and "conforming" C
| programs. Almost zero C programs are strictly conforming,
| but many are conforming.
| uecker wrote:
| bytewise copy just works with the TS. What it does not
| support is tracking provenance across the copy and doing
| optimization based on this. What we hope is that
| compilers drop these optimizations, because they are
| unsound.
| weinzierl wrote:
| Thanks for your detailed answer. You encouraged me to give
| it another try and have closer look this time.
| jcranmer wrote:
| Given some of the discussions I've been stuck in over the past
| couple of weeks, one of the things I especially want to see built
| out for LLVM is a comprehensive executable test suite that starts
| not from C but from LLVM IR. If you've ever tried working on your
| own backend, one of the things you notice is there's not a lot of
| documentation about all of the SelectionDAG stuff (or
| GlobalISel), and there is also a lot of semi-generic "support X
| operation on top of Y operation if X isn't supported." And the
| precise semantics of X or Y aren't clearly documented, so it's
| quite easy to build the wrong thing.
| Fiveplus wrote:
| [dead]
| muizelaar wrote:
| What section is that?
| Fiveplus wrote:
| Sorry, wrong post.
| phplovesong wrote:
| Comptimes aee an issue, not only for LLVM itself, but also for
| users, as a prime example: Rust. Rust has horrible comptimes for
| anything larger, what makes its a real PITA to use.
| ksec wrote:
| >Compilation time
|
| I remember part of the selling point of LLVM during its early
| stage was compilation time being so much faster than GCC.
|
| LLVM started about 15 years after GCC. Considering LLVM is 23
| years old already. I wonder if something new again will pop up.
| circuit10 wrote:
| A few months ago someone wrote a much faster -O0 backend for
| LLVM, though it seems it didn't get much attention upstream:
| https://discourse.llvm.org/t/tpde-llvm-10-20x-faster-llvm-o0...
|
| Discussion: https://news.ycombinator.com/item?id=45072481
|
| There are also codegen projects that don't use LLVM IR that are
| faster like Cranelift:
| https://github.com/bytecodealliance/wasmtime/tree/main/crane...
| ggggffggggg wrote:
| > This is somewhat unsurprising, as code review ... may not
| provide immediate value to the person reviewing (or their
| employer).
|
| If you get "credit" for contributing when you review, maybe
| people (and even employers, though that is perhaps less likely)
| would find _doing_ reviews to be more valuable.
|
| Not sure what that looks like; maybe whatever shows up in GitHub
| is already enough.
| loeg wrote:
| Honestly, the same phenomenon is a problem inside companies as
| well. My employer credits review quality and quantity
| relatively well (i.e., in annual performance review), but it
| still isn't a strong enough motivator to really get the rate up
| to a satisfactory level.
| anarazel wrote:
| FWIW, the article says "Frontends are somewhat insulated from
| this because they can use the largely stable C API." but that's
| not been my/our experience. There are parts of the API that are
| somewhat stable, but other parts (e.g. Orc) that change wildly.
| nikic wrote:
| Yes, the Orc C API follows different rules from the rest of the
| C API (https://github.com/llvm/llvm-
| project/blob/501416a755d1b85ca1...).
| anarazel wrote:
| I know, but even if it's not breaking promises, the constant
| stream of changes still makes it still rather painful to
| utilize LLVM. Not helped by the fact that unless you embed
| LLVM you have to deal with a lot of different LLVM versions
| out there...
| lhames wrote:
| FWIW eventual stability is a goal, but there's going to be
| more churn as we work towards full arbitrary program
| execution (https://www.youtube.com/watch?v=qgtA-bWC_vM
| covers some recent progress).
|
| If you're looking for stability in practice: the ORC LLJIT
| API is your best bet at the moment (or sticking to MCJIT
| until it's removed).
| hu3 wrote:
| Hey Nikita, if you're reading this, Thank You! for your
| contributions to PHP!
|
| We miss you!
| pja wrote:
| Six years ago I was building LLVM pretty regularly on an 8GB Dell
| 9360 laptop whilst on a compiler related contract. (Still have it
| actually - that thing is weirdly indestructible for a cheap
| ultrabook.)
|
| Build time wasn't great, but it was tolerable, so long as you
| reduced link parallelism to squeeze inside the memory
| constraints.
|
| Is it still possible to compile LLVM on such a machine, or is 8Gb
| no longer workable at all?
| apitman wrote:
| My main concern with LLVM is that it adds 30+ million lines of
| code dependency to any language that relies on it.
|
| Part of the reason I'm not ready to go all in on Rust is that I'm
| not willing to externalize that much complexity in the programs I
| make.
| MeetingsBrowser wrote:
| What language do you typically use?
| pklausler wrote:
| > There are thousands of contributors and the distribution is
| relatively flat (that is, it's not the case that a small handful
| of people is responsible for the majority of contributions.)
|
| This certainly varies across different parts of llvm-project. In
| flang, there's very much a "long tail". 80% of its 654K lines are
| attributed to the 17 contributors responsible for 1% or more of
| them, according to "git blame", out of 355 total.
| nikic wrote:
| That was ambiguously phrased. The point I was trying to make
| here is that we don't have the situation that is very common
| for open-source projects, where a project might nominally have
| a 100 contributors, but in reality it's one person doing 95% of
| the changes.
|
| LLVM of course has plenty of contributors that only ever landed
| one change, but the thing that matters for project health is
| that that the group of "top contributors" is fairly large.
|
| (And yes, this does differ by subproject, e.g. lld is an
| example of a subproject where one contributor is more active
| than everyone else combined.)
| pklausler wrote:
| There may be a difference of degree here, but not a
| difference of kind.
| hoyhoy wrote:
| I asked the guy working on compiler-rt to change one boolean so
| the LLVM 18 build would work on macOS, and he locked the whole
| issue down as "heated" and it's still not fixed four years later.
|
| I love LLVM though. clang-tidy, ASAN, UBSAN, LSAN, MSAN, and TSAN
| are AMAZING. If you are coding C and C++ and NOT using clang-
| tidy, you are doing it wrong.
|
| My biggest problem with LLVM rn is that -fbounds-safety is only
| available on Xcode/AppleClang and not LLVM Clang. MSAN and LSAN
| are only available on LLVM and not Xcode/AppleClang. Also Xcode
| doesn't ship clang-tidy, clang-format, or llvm-symbolizer. It's
| kind of a mess on macOS rn. I basically rolled my own darwin LLVM
| for LSAN and clang-tidy support.
|
| The situation on Linux is even weirder. RHEL doesn't ship libcxx,
| but Fedora does ship it. No distro has libcxx instrumented for
| MSAN at the moment which means rolling your own.
|
| What would be amazing is if some distro would just ship native
| LLVM with all the things working out of the box. Fedora is really
| close right now, but I still have to build compiler-rt manually
| for MSAN support..
___________________________________________________________________
(page generated 2026-01-12 23:00 UTC)