Step 02 · IRBuilder

IRBuilder<> is a cursor: you SetInsertPoint(BB) and then every Create* call appends one instruction at the cursor.

llvm::IRBuilder<> b(ctx);
auto* bb = llvm::BasicBlock::Create(ctx, "entry", fn);
b.SetInsertPoint(bb);
auto* sum = b.CreateAdd(lhs, rhs, "sum");
b.CreateRet(sum);

What we build

Per function:

  1. entry block with one alloca i64 per named local/param.
  2. Spill each parameter into its alloca.
  3. Pre-create every TAC basic block as a BasicBlock*.
  4. Branch from entry to the first TAC block.
  5. Walk each TAC instruction, dispatch on opcode, emit one or more LLVM instructions.

Mapping opcodes

TACIRBuilder
Add/Sub/Mul/Div/ModCreateAdd/Sub/Mul/SDiv/SRem
And/OrCreateAnd/Or
Eq/Ne/Lt/...CreateICmpEQ/NE/SLT/... then CreateZExt to i64
NegCreateNeg
NotICmpEQ x, 0 then ZExt
Move t,_alias in temps map
Move name,_CreateStore to alloca
LoadGlobal/StoreGlobalCreateLoad/Store on GlobalVariable
PrintCreateCall(printf, {fmt, v})
Call f(args)CreateCall(callee, args)
JumpCreateBr
CondJumpICmpNE x,0 then CreateCondBr
ReturnCreateRet

Naming

Anonymous SSA values get %0, %1, … from the printer. Passing a name string to Create* ("sum") is purely cosmetic — it survives to the printed IR and is invaluable when reading optimised output.