Step 07 · Targets and llc

Our mlcc emits target-independent LLVM IR. To produce a binary:

./build/mlcc -O program.ml > program.ll
/opt/homebrew/opt/llvm/bin/llc -O3 -filetype=obj program.ll -o program.o
clang program.o -o program
./program

llc walks:

LLVM IR
  → SelectionDAG / GlobalISel    (instruction selection)
  → MachineInstr                 (target-specific MI)
  → Register allocation
  → Instruction scheduling
  → Machine code emission         (.o)

Going programmatic

Inside C++, you'd:

  1. InitializeNativeTarget, InitializeNativeTargetAsmPrinter.
  2. TargetRegistry::lookupTarget(sys::getDefaultTargetTriple(), err).
  3. target->createTargetMachine(...).
  4. Set the module's DataLayout and TargetTriple.
  5. Use a legacy PassManager + addPassesToEmitFile(...) to write a .o.

We stop short of that in cp-11 to keep the lab focused; cp-12 (ORC JIT) will internalise target initialisation in order to execute IR without lli.

When to add a custom target

Building a real backend is a full course. For research languages, ride the existing X86/AArch64/RISC-V backends. Only write a target when you ship custom silicon.