Why `-fno-emit-bin` is so much faster to get to the first compilation error?

Currently, the bottleneck of the compiler is Semantic Analysis, which is what produces those compile errors.

How it works today is ping ponging between Sema and Codegen. For example, when analyzing bar in this code:

fn foo() void {}
fn bar() void { foo(); }

Here is what will happen:

  1. Sema foo
  2. Codegen foo
  3. Sema bar
  4. Codegen bar
  5. LLVM Emit Object…

In this case, Codegen means using the LLVM IR builder API to construct an LLVM Module. The LLVM IR builder, written in C++, does slow C++ things. You know, calling nested inherited constructors, dutifully running unnecessary destructors, being blissfully ignorant about batch operations, celebrating move semantics while heap allocating out the wazoo. Classic stuff.

Anyway, with -fno-emit-bin, here is what happens instead:

  1. Sema foo
  2. Sema bar

So not only did LLVM Emit Object disappear but also the Codegen phases.

In other words, even constructing the LLVM IR Module is slow.

Related: directly output LLVM bitcode rather than using LLVM’s IRBuilder API


I meant to add: as you might have guessed, a future planned enhancement is moving Codegen to a different thread than Sema.

15 Likes