All posts
Compiler6 min read

LLVM optimisation levels land in Cheeku

Cheeku now exposes O0 through O3, a generic CPU target and opt-in diagnostic artifacts. The runtime checks stay exactly where they were.

Cheeku now compiles through LLVM's new pass manager at four optimisation levels. O0 skips the optional IR pipeline, O1 simplifies scalar code, and O2 or O3 add loop and SLP vectorisation. O2 remains the default, so existing builds get a faster binary without changing a single command.

The target is configured before any pass runs. By default Cheeku uses a generic CPU for the detected host architecture, which keeps the executable portable across machines of the same architecture. Passing --cpu native opts into the host CPU's specific features; that binary may require those features elsewhere.

What each level does

  • O0: no optional IR passes. LLVM still lowers instructions into machine code.
  • O1: local promotion and scalar simplification.
  • O2: the standard pipeline, including loop and SLP vectorisation. This is the default.
  • O3: more aggressive standard transformations. Faster is not guaranteed.
terminalSH
cheeku examples/numerical.chuchu -O3 \
  --emit-ir numerical.ll \
  --emit-assembly numerical.s \
  -o numerical

The checks do not move

Checked signed arithmetic, division guards, array bounds and value-copy semantics are part of the production lowering at every level. No unsafe fast-math flags or unjustified nsw/nuw annotations were added. LLVM may still remove a check when it can prove the operation is safe, which is the point of an optimiser.

Every module is verified after generation, before and after passes, and again before object emission. If a pass or target step fails, compilation reports the error; it never quietly drops to a lower optimisation level.

O3 permits more aggressive standard transformations; it is not guaranteed to be faster or smaller than O2.

Measuring instead of guessing

--time-compilation prints stage durations as JSON on stderr. --emit-ir and --emit-assembly expose the optimised artifacts for inspection. --no-vectorize turns off the loop and SLP options for experiments, but it is not a promise of scalar machine code: other standard passes can still form vector operations.

The optimisation guide covers the pipeline, the target policy and the library API in detail. If you are comparing levels, build a fresh module for each run rather than reusing one.

Read it. Then run it.

Install Cheeku, compile the example and see the native binary for yourself.