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:
entryblock with onealloca i64per named local/param.- Spill each parameter into its alloca.
- Pre-create every TAC basic block as a
BasicBlock*. - Branch from
entryto the first TAC block. - Walk each TAC instruction, dispatch on opcode, emit one or more LLVM instructions.
Mapping opcodes
| TAC | IRBuilder |
|---|---|
Add/Sub/Mul/Div/Mod | CreateAdd/Sub/Mul/SDiv/SRem |
And/Or | CreateAnd/Or |
Eq/Ne/Lt/... | CreateICmpEQ/NE/SLT/... then CreateZExt to i64 |
Neg | CreateNeg |
Not | ICmpEQ x, 0 then ZExt |
Move t,_ | alias in temps map |
Move name,_ | CreateStore to alloca |
LoadGlobal/StoreGlobal | CreateLoad/Store on GlobalVariable |
Print | CreateCall(printf, {fmt, v}) |
Call f(args) | CreateCall(callee, args) |
Jump | CreateBr |
CondJump | ICmpNE x,0 then CreateCondBr |
Return | CreateRet |
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.