Step 06 · Globals and the print runtime
MiniLang's top-level let bindings become module globals. We
scan every function for LoadGlobal/StoreGlobal to discover the
names, then create one GlobalVariable each:
new llvm::GlobalVariable(
mod, i64, /*isConstant=*/false,
llvm::GlobalValue::ExternalLinkage,
llvm::ConstantInt::get(i64, 0), name);
External linkage keeps the symbol visible in the .o we'd emit with
llc — necessary for any future linker-level integration.
printf shim
auto* ft = llvm::FunctionType::get(i32, {i8p}, /*isVarArg=*/true);
printfFn = llvm::Function::Create(ft, ExternalLinkage, "printf", mod);
fmtStr = b.CreateGlobalString("%lld\n", ".fmt", 0, &mod);
CreateGlobalString returns a pointer (i8*/ptr under opaque
pointers) directly usable as the first argument to printf. Under
LLVM 20 the textual form is ptr @.fmt.
Why printf and not a hand-rolled write(2) loop? Three reasons:
- the C runtime is always available on a JIT or system linker;
%lldis portable and exactly matches ouri64;- it lets
lliexecute the program with no extra plumbing.
cp-14 will replace this with a proper ml_print(Value) runtime that
understands strings, booleans and closures.