The pipeline of Zig code looks something like this:
- Source code
- AST (Abstract Syntax Tree)
- ZIR (Zig Intermediate Representation)
- AIR (Analyzed Intermediate Representation)
- Backend-specific logic (LLVM backend, x86-64 self-hosted backend, etc.)
Comptime evaluation happens in the transition from ZIR to AIR, using a process called Sema. So, it sounds like AIR is what you’re looking for.
It is possible to look at a textual representation of ZIR and AIR using the following two commands, but these commands only work on a debug build of the compiler, so you will need to build one from source to run them:
- ZIR:
zig ast-check -t file.zig
- AIR:
zig build-obj --verbose-air file.zig
For comparison, here’s a simple main function:
pub fn main() !void {
std.debug.print("Hello, world!", .{});
}
And here are the ZIR and AIR for the function, as of Zig 0.12.0-dev.1836+dd189a354:
ZIR
[60] pub main line(2) hash(b34a5dd1dd5f828d0d25f54718b526c5): %4 = block_inline({
%23 = func_inferred(ret_ty=@void_type, inferror, body={
%5 = block({
%6 = dbg_block_begin()
%7 = dbg_stmt(2, 5)
%8 = decl_ref("std") token_offset:4:5 to :4:8
%9 = dbg_stmt(2, 8)
%10 = field_ptr(%8, "debug") node_offset:4:5 to :4:14
%11 = dbg_stmt(2, 14)
%12 = dbg_stmt(2, 20)
%13 = field_call(nodiscard .auto, %10, "print", [
{
%14 = str("Hello, world!")
%15 = break_inline(%13, %14)
},
{
%16 = struct_init_empty_result(%13) node_offset:4:38 to :4:41
%17 = break_inline(%13, %16)
},
]) node_offset:4:5 to :4:42
%18 = dbg_block_end()
%19 = restore_err_ret_index(%5.none)
%20 = break(%5, @void_value)
}) node_offset:3:21 to :3:21
%21 = restore_err_ret_index(.none.none)
%22 = ret_implicit(@void_value) token_offset:5:1 to :5:1
}) (lbrace=1:21,rbrace=3:1) node_offset:3:1 to :3:7
%24 = break_inline(%4, %23)
}) node_offset:3:1 to :3:20
AIR
%0!= save_err_return_trace_index()
%2!= dbg_block_begin()
%3!= dbg_stmt(2:20)
%4!= call(<fn (@TypeOf(.{})) void, (function 'print__anon_2997')>, [@Air.Inst.Ref.empty_struct])
%5!= dbg_block_end()
%7!= ret(<@typeInfo(@typeInfo(@TypeOf(test.main)).Fn.return_type.?).ErrorUnion.error_set!void, {}>)
In particular, in this example, you can see how the generic call to std.debug.print
has been monomorphized down to a call to print__anon_2997
.