feature. See also
. The project being documented here (as the example) is the Zig library itself.
Ir.Builder
pub const Builder = struct
File
Code
pub const Builder = struct {
gpa: Allocator,
arena: std.heap.ArenaAllocator,
interner: *Interner,
decls: std.array_hash_map.String(Decl) = .empty,
instructions: std.MultiArrayList(Ir.Inst) = .empty,
body: std.ArrayList(Ref) = .empty,
alloc_count: u32 = 0,
arg_count: u32 = 0,
current_label: Ref = undefined,
pub fn deinit(b: *Builder) void {
for (b.decls.values()) |*decl| {
decl.deinit(b.gpa);
}
b.decls.deinit(b.gpa);
b.arena.deinit();
b.instructions.deinit(b.gpa);
b.body.deinit(b.gpa);
b.* = undefined;
}
pub fn finish(b: *Builder) Ir {
return .{
.interner = b.interner,
.decls = b.decls.move(),
};
}
pub fn startFn(b: *Builder) Allocator.Error!void {
const entry = try b.makeLabel("entry");
try b.body.append(b.gpa, entry);
b.current_label = entry;
}
pub fn finishFn(b: *Builder, name: []const u8) !void {
var duped_instructions = try b.instructions.clone(b.gpa);
errdefer duped_instructions.deinit(b.gpa);
var duped_body = try b.body.clone(b.gpa);
errdefer duped_body.deinit(b.gpa);
try b.decls.put(b.gpa, name, .{
.instructions = duped_instructions,
.body = duped_body,
.arena = b.arena.state,
});
b.instructions.shrinkRetainingCapacity(0);
b.body.shrinkRetainingCapacity(0);
b.arena = std.heap.ArenaAllocator.init(b.gpa);
b.alloc_count = 0;
b.arg_count = 0;
}
pub fn startBlock(b: *Builder, label: Ref) !void {
try b.body.append(b.gpa, label);
b.current_label = label;
}
pub fn addArg(b: *Builder, ty: Interner.Ref) Allocator.Error!Ref {
const ref: Ref = @fromBackingInt(@intCast(b.instructions.len));
try b.instructions.append(b.gpa, .{ .tag = .arg, .data = .{ .none = {} }, .ty = ty });
try b.body.insert(b.gpa, b.arg_count, ref);
b.arg_count += 1;
return ref;
}
pub fn addAlloc(b: *Builder, size: u32, @"align": u32) Allocator.Error!Ref {
const ref: Ref = @fromBackingInt(@intCast(b.instructions.len));
try b.instructions.append(b.gpa, .{
.tag = .alloc,
.data = .{ .alloc = .{ .size = size, .@"align" = @"align" } },
.ty = .ptr,
});
try b.body.insert(b.gpa, b.alloc_count + b.arg_count + 1, ref);
b.alloc_count += 1;
return ref;
}
pub fn addInst(b: *Builder, tag: Ir.Inst.Tag, data: Ir.Inst.Data, ty: Interner.Ref) Allocator.Error!Ref {
const ref: Ref = @fromBackingInt(@intCast(b.instructions.len));
try b.instructions.append(b.gpa, .{ .tag = tag, .data = data, .ty = ty });
try b.body.append(b.gpa, ref);
return ref;
}
pub fn makeLabel(b: *Builder, name: [*:0]const u8) Allocator.Error!Ref {
const ref: Ref = @fromBackingInt(@intCast(b.instructions.len));
try b.instructions.append(b.gpa, .{ .tag = .label, .data = .{ .label = name }, .ty = .void });
return ref;
}
pub fn addJump(b: *Builder, label: Ref) Allocator.Error!void {
_ = try b.addInst(.jmp, .{ .un = label }, .noreturn);
}
pub fn addBranch(b: *Builder, cond: Ref, true_label: Ref, false_label: Ref) Allocator.Error!void {
const branch = try b.arena.allocator().create(Ir.Inst.Branch);
branch.* = .{
.cond = cond,
.then = true_label,
.@"else" = false_label,
};
_ = try b.addInst(.branch, .{ .branch = branch }, .noreturn);
}
pub fn addSwitch(b: *Builder, target: Ref, values: []Interner.Ref, labels: []Ref, default: Ref) Allocator.Error!void {
assert(values.len == labels.len);
const a = b.arena.allocator();
const @"switch" = try a.create(Ir.Inst.Switch);
@"switch".* = .{
.target = target,
.cases_len = @intCast(values.len),
.case_vals = (try a.dupe(Interner.Ref, values)).ptr,
.case_labels = (try a.dupe(Ref, labels)).ptr,
.default = default,
};
_ = try b.addInst(.@"switch", .{ .@"switch" = @"switch" }, .noreturn);
}
pub fn addStore(b: *Builder, ptr: Ref, val: Ref) Allocator.Error!void {
_ = try b.addInst(.store, .{ .bin = .{ .lhs = ptr, .rhs = val } }, .void);
}
pub fn addConstant(b: *Builder, val: Interner.Ref, ty: Interner.Ref) Allocator.Error!Ref {
const ref: Ref = @fromBackingInt(@intCast(b.instructions.len));
try b.instructions.append(b.gpa, .{
.tag = .constant,
.data = .{ .constant = val },
.ty = ty,
});
return ref;
}
pub fn addPhi(b: *Builder, inputs: []const Inst.Phi.Input, ty: Interner.Ref) Allocator.Error!Ref {
const a = b.arena.allocator();
const input_refs = try a.alloc(Ref, inputs.len * 2 + 1);
input_refs[0] = @fromBackingInt(@intCast(inputs.len));
@memcpy(input_refs[1..], std.mem.bytesAsSlice(Ref, std.mem.sliceAsBytes(inputs)));
return b.addInst(.phi, .{ .phi = .{ .ptr = input_refs.ptr } }, ty);
}
pub fn addSelect(b: *Builder, cond: Ref, then: Ref, @"else": Ref, ty: Interner.Ref) Allocator.Error!Ref {
const branch = try b.arena.allocator().create(Ir.Inst.Branch);
branch.* = .{
.cond = cond,
.then = then,
.@"else" = @"else",
};
return b.addInst(.select, .{ .branch = branch }, ty);
}
}