Step 04 · LLVM-dialect mapping

Our emitter speaks one dialect: llvm. The mapping is mechanical:

TACMLIR llvm
Numeric constantllvm.mlir.constant(N : i64) : i64
Named local xllvm.alloca in entry block, llvm.load/llvm.store thereafter
Add a,bllvm.add %a, %b : i64
Sub/Mul/Div/Modllvm.sub/mul/sdiv/srem
And/Orllvm.and/or
Eq/Ne/Lt/...llvm.icmp "eq"/"ne"/"slt"/... then llvm.zext _ : i1 to i64
Negllvm.sub %zero, %a
Notllvm.icmp "eq" %a, %zero then zext
LoadGlobal xllvm.mlir.addressof @x then llvm.load
StoreGlobal x, vllvm.mlir.addressof @x then llvm.store
Print vllvm.call @printf(@fmt, v) vararg(...) : (!llvm.ptr, i64) -> i32
Call f(args)llvm.call @f(args) : (...) -> i64
Jump bbllvm.br ^bbN
CondJump v, T, Fllvm.icmp "ne" v, 0 then llvm.cond_br ... ^bbT, ^bbF
Return vllvm.return %v : i64 (i32 0 for main)

Globals

llvm.mlir.global internal @x(0 : i64) : i64

internal linkage; initial value 0. Stores at main-time install the user's initialiser. llvm.mlir.addressof @x reifies the global as a !llvm.ptr value.

printf

llvm.mlir.global internal constant @fmt("%lld\0A\00") {addr_space = 0 : i32}
llvm.func @printf(!llvm.ptr, ...) -> i32

Variadic call sites must spell their vararg signature:

%r = llvm.call @printf(%f, %v) vararg(!llvm.func<i32 (ptr, ...)>)
     : (!llvm.ptr, i64) -> i32

That's MLIR's way of preserving variadic information that LLVM's function type would otherwise carry as (...).