Skip to content

Commit 8e425c0

Browse files
committed
stage2: if AST=>ZIR
1 parent be0546d commit 8e425c0

5 files changed

Lines changed: 317 additions & 128 deletions

File tree

lib/std/zig/ast.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,8 @@ pub const Node = struct {
959959
};
960960

961961
/// The params are directly after the FnProto in memory.
962+
/// TODO have a flags field for the optional nodes, and have them appended
963+
/// before or after the parameters in memory.
962964
pub const FnProto = struct {
963965
base: Node = Node{ .id = .FnProto },
964966
doc_comments: ?*DocComment,

src-self-hosted/Module.zig

Lines changed: 145 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,14 @@ pub const Scope = struct {
303303
switch (self.tag) {
304304
.block => return self.cast(Block).?.arena,
305305
.decl => return &self.cast(DeclAnalysis).?.arena.allocator,
306-
.gen_zir => return &self.cast(GenZIR).?.arena.allocator,
306+
.gen_zir => return self.cast(GenZIR).?.arena,
307307
.zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
308308
.file => unreachable,
309309
}
310310
}
311311

312-
/// Asserts the scope has a parent which is a DeclAnalysis and
313-
/// returns the Decl.
312+
/// If the scope has a parent which is a `DeclAnalysis`,
313+
/// returns the `Decl`, otherwise returns `null`.
314314
pub fn decl(self: *Scope) ?*Decl {
315315
return switch (self.tag) {
316316
.block => self.cast(Block).?.decl,
@@ -653,7 +653,7 @@ pub const Scope = struct {
653653
label: ?Label = null,
654654

655655
pub const Label = struct {
656-
name: []const u8,
656+
zir_block: *zir.Inst.Block,
657657
results: ArrayListUnmanaged(*Inst),
658658
block_inst: *Inst.Block,
659659
};
@@ -674,8 +674,8 @@ pub const Scope = struct {
674674
pub const base_tag: Tag = .gen_zir;
675675
base: Scope = Scope{ .tag = base_tag },
676676
decl: *Decl,
677-
arena: std.heap.ArenaAllocator,
678-
instructions: std.ArrayList(*zir.Inst),
677+
arena: *Allocator,
678+
instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
679679
};
680680
};
681681

@@ -1115,19 +1115,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11151115
// This arena allocator's memory is discarded at the end of this function. It is used
11161116
// to determine the type of the function, and hence the type of the decl, which is needed
11171117
// to complete the Decl analysis.
1118+
var fn_type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1119+
defer fn_type_scope_arena.deinit();
11181120
var fn_type_scope: Scope.GenZIR = .{
11191121
.decl = decl,
1120-
.arena = std.heap.ArenaAllocator.init(self.gpa),
1121-
.instructions = std.ArrayList(*zir.Inst).init(self.gpa),
1122+
.arena = &fn_type_scope_arena.allocator,
11221123
};
1123-
defer fn_type_scope.arena.deinit();
1124-
defer fn_type_scope.instructions.deinit();
1124+
defer fn_type_scope.instructions.deinit(self.gpa);
11251125

11261126
const body_node = fn_proto.body_node orelse
11271127
return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
11281128

11291129
const param_decls = fn_proto.params();
1130-
const param_types = try fn_type_scope.arena.allocator.alloc(*zir.Inst, param_decls.len);
1130+
const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);
11311131
for (param_decls) |param_decl, i| {
11321132
const param_type_node = switch (param_decl.param_type) {
11331133
.var_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
@@ -1190,24 +1190,24 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11901190
const fn_zir = blk: {
11911191
// This scope's arena memory is discarded after the ZIR generation
11921192
// pass completes, and semantic analysis of it completes.
1193+
var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1194+
errdefer gen_scope_arena.deinit();
11931195
var gen_scope: Scope.GenZIR = .{
11941196
.decl = decl,
1195-
.arena = std.heap.ArenaAllocator.init(self.gpa),
1196-
.instructions = std.ArrayList(*zir.Inst).init(self.gpa),
1197+
.arena = &gen_scope_arena.allocator,
11971198
};
1198-
errdefer gen_scope.arena.deinit();
1199-
defer gen_scope.instructions.deinit();
1199+
defer gen_scope.instructions.deinit(self.gpa);
12001200

12011201
const body_block = body_node.cast(ast.Node.Block).?;
12021202

12031203
try self.astGenBlock(&gen_scope.base, body_block);
12041204

1205-
const fn_zir = try gen_scope.arena.allocator.create(Fn.ZIR);
1205+
const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR);
12061206
fn_zir.* = .{
12071207
.body = .{
1208-
.instructions = try gen_scope.arena.allocator.dupe(*zir.Inst, gen_scope.instructions.items),
1208+
.instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
12091209
},
1210-
.arena = gen_scope.arena.state,
1210+
.arena = gen_scope_arena.state,
12111211
};
12121212
break :blk fn_zir;
12131213
};
@@ -1351,9 +1351,70 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir
13511351
return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{});
13521352
}
13531353
}
1354-
const cond = try self.astGenExpr(scope, if_node.condition);
1355-
const body = try self.astGenExpr(scope, if_node.condition);
1356-
return self.failNode(scope, if_node.condition, "TODO implement astGenIf", .{});
1354+
var block_scope: Scope.GenZIR = .{
1355+
.decl = scope.decl().?,
1356+
.arena = scope.arena(),
1357+
.instructions = .{},
1358+
};
1359+
defer block_scope.instructions.deinit(self.gpa);
1360+
1361+
const cond = try self.astGenExpr(&block_scope.base, if_node.condition);
1362+
1363+
const tree = scope.tree();
1364+
const if_src = tree.token_locs[if_node.if_token].start;
1365+
const condbr = try self.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{
1366+
.condition = cond,
1367+
.true_body = undefined, // populated below
1368+
.false_body = undefined, // populated below
1369+
}, .{});
1370+
1371+
const block = try self.addZIRInstBlock(scope, if_src, .{
1372+
.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1373+
});
1374+
var then_scope: Scope.GenZIR = .{
1375+
.decl = block_scope.decl,
1376+
.arena = block_scope.arena,
1377+
.instructions = .{},
1378+
};
1379+
defer then_scope.instructions.deinit(self.gpa);
1380+
1381+
const then_result = try self.astGenExpr(&then_scope.base, if_node.body);
1382+
const then_src = tree.token_locs[if_node.body.lastToken()].start;
1383+
_ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{
1384+
.block = block,
1385+
.operand = then_result,
1386+
}, .{});
1387+
condbr.positionals.true_body = .{
1388+
.instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items),
1389+
};
1390+
1391+
var else_scope: Scope.GenZIR = .{
1392+
.decl = block_scope.decl,
1393+
.arena = block_scope.arena,
1394+
.instructions = .{},
1395+
};
1396+
defer else_scope.instructions.deinit(self.gpa);
1397+
1398+
if (if_node.@"else") |else_node| {
1399+
const else_result = try self.astGenExpr(&else_scope.base, else_node.body);
1400+
const else_src = tree.token_locs[else_node.body.lastToken()].start;
1401+
_ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{
1402+
.block = block,
1403+
.operand = else_result,
1404+
}, .{});
1405+
} else {
1406+
// TODO Optimization opportunity: we can avoid an allocation and a memcpy here
1407+
// by directly allocating the body for this one instruction.
1408+
const else_src = tree.token_locs[if_node.lastToken()].start;
1409+
_ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.BreakVoid, .{
1410+
.block = block,
1411+
}, .{});
1412+
}
1413+
condbr.positionals.false_body = .{
1414+
.instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
1415+
};
1416+
1417+
return &block.base;
13571418
}
13581419

13591420
fn astGenControlFlowExpression(
@@ -1379,12 +1440,12 @@ fn astGenControlFlowExpression(
13791440
fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
13801441
const tree = scope.tree();
13811442
const ident_name = tree.tokenSlice(ident.token);
1443+
const src = tree.token_locs[ident.token].start;
13821444
if (mem.eql(u8, ident_name, "_")) {
13831445
return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});
13841446
}
13851447

13861448
if (getSimplePrimitiveValue(ident_name)) |typed_value| {
1387-
const src = tree.token_locs[ident.token].start;
13881449
return self.addZIRInstConst(scope, src, typed_value);
13891450
}
13901451

@@ -1408,7 +1469,6 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
14081469
64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
14091470
else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),
14101471
};
1411-
const src = tree.token_locs[ident.token].start;
14121472
return self.addZIRInstConst(scope, src, .{
14131473
.ty = Type.initTag(.type),
14141474
.val = val,
@@ -1417,10 +1477,21 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
14171477
}
14181478

14191479
if (self.lookupDeclName(scope, ident_name)) |decl| {
1420-
const src = tree.token_locs[ident.token].start;
14211480
return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
14221481
}
14231482

1483+
// Function parameter
1484+
if (scope.decl()) |decl| {
1485+
if (tree.root_node.decls()[decl.src_index].cast(ast.Node.FnProto)) |fn_proto| {
1486+
for (fn_proto.params()) |param, i| {
1487+
const param_name = tree.tokenSlice(param.name_token.?);
1488+
if (mem.eql(u8, param_name, ident_name)) {
1489+
return try self.addZIRInst(scope, src, zir.Inst.Arg, .{ .index = i }, .{});
1490+
}
1491+
}
1492+
}
1493+
}
1494+
14241495
return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});
14251496
}
14261497

@@ -1563,7 +1634,7 @@ fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zi
15631634
const lhs = try self.astGenExpr(scope, call.lhs);
15641635

15651636
const param_nodes = call.params();
1566-
const args = try scope.cast(Scope.GenZIR).?.arena.allocator.alloc(*zir.Inst, param_nodes.len);
1637+
const args = try scope.cast(Scope.GenZIR).?.arena.alloc(*zir.Inst, param_nodes.len);
15671638
for (param_nodes) |param_node, i| {
15681639
args[i] = try self.astGenExpr(scope, param_node);
15691640
}
@@ -2239,7 +2310,7 @@ fn newZIRInst(
22392310
comptime T: type,
22402311
positionals: std.meta.fieldInfo(T, "positionals").field_type,
22412312
kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2242-
) !*zir.Inst {
2313+
) !*T {
22432314
const inst = try gpa.create(T);
22442315
inst.* = .{
22452316
.base = .{
@@ -2249,30 +2320,48 @@ fn newZIRInst(
22492320
.positionals = positionals,
22502321
.kw_args = kw_args,
22512322
};
2252-
return &inst.base;
2323+
return inst;
22532324
}
22542325

2255-
fn addZIRInst(
2326+
fn addZIRInstSpecial(
22562327
self: *Module,
22572328
scope: *Scope,
22582329
src: usize,
22592330
comptime T: type,
22602331
positionals: std.meta.fieldInfo(T, "positionals").field_type,
22612332
kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2262-
) !*zir.Inst {
2333+
) !*T {
22632334
const gen_zir = scope.cast(Scope.GenZIR).?;
2264-
try gen_zir.instructions.ensureCapacity(gen_zir.instructions.items.len + 1);
2265-
const inst = try newZIRInst(&gen_zir.arena.allocator, src, T, positionals, kw_args);
2266-
gen_zir.instructions.appendAssumeCapacity(inst);
2335+
try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);
2336+
const inst = try newZIRInst(gen_zir.arena, src, T, positionals, kw_args);
2337+
gen_zir.instructions.appendAssumeCapacity(&inst.base);
22672338
return inst;
22682339
}
22692340

2341+
fn addZIRInst(
2342+
self: *Module,
2343+
scope: *Scope,
2344+
src: usize,
2345+
comptime T: type,
2346+
positionals: std.meta.fieldInfo(T, "positionals").field_type,
2347+
kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2348+
) !*zir.Inst {
2349+
const inst_special = try self.addZIRInstSpecial(scope, src, T, positionals, kw_args);
2350+
return &inst_special.base;
2351+
}
2352+
22702353
/// TODO The existence of this function is a workaround for a bug in stage1.
22712354
fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {
22722355
const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;
22732356
return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
22742357
}
22752358

2359+
/// TODO The existence of this function is a workaround for a bug in stage1.
2360+
fn addZIRInstBlock(self: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block {
2361+
const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type;
2362+
return self.addZIRInstSpecial(scope, src, zir.Inst.Block, P{ .body = body }, .{});
2363+
}
2364+
22762365
fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {
22772366
const inst = try block.arena.create(T);
22782367
inst.* = .{
@@ -2403,6 +2492,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
24032492
switch (old_inst.tag) {
24042493
.arg => return self.analyzeInstArg(scope, old_inst.cast(zir.Inst.Arg).?),
24052494
.block => return self.analyzeInstBlock(scope, old_inst.cast(zir.Inst.Block).?),
2495+
.@"break" => return self.analyzeInstBreak(scope, old_inst.cast(zir.Inst.Break).?),
24062496
.breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
24072497
.breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.cast(zir.Inst.BreakVoid).?),
24082498
.call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
@@ -2559,7 +2649,7 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr
25592649
.arena = parent_block.arena,
25602650
// TODO @as here is working around a miscompilation compiler bug :(
25612651
.label = @as(?Scope.Block.Label, Scope.Block.Label{
2562-
.name = inst.positionals.label,
2652+
.zir_block = inst,
25632653
.results = .{},
25642654
.block_inst = block_inst,
25652655
}),
@@ -2588,25 +2678,39 @@ fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoin
25882678
return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
25892679
}
25902680

2681+
fn analyzeInstBreak(self: *Module, scope: *Scope, inst: *zir.Inst.Break) InnerError!*Inst {
2682+
const operand = try self.resolveInst(scope, inst.positionals.operand);
2683+
const block = inst.positionals.block;
2684+
return self.analyzeBreak(scope, inst.base.src, block, operand);
2685+
}
2686+
25912687
fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst {
2592-
const label_name = inst.positionals.label;
2688+
const block = inst.positionals.block;
25932689
const void_inst = try self.constVoid(scope, inst.base.src);
2690+
return self.analyzeBreak(scope, inst.base.src, block, void_inst);
2691+
}
25942692

2693+
fn analyzeBreak(
2694+
self: *Module,
2695+
scope: *Scope,
2696+
src: usize,
2697+
zir_block: *zir.Inst.Block,
2698+
operand: *Inst,
2699+
) InnerError!*Inst {
25952700
var opt_block = scope.cast(Scope.Block);
25962701
while (opt_block) |block| {
25972702
if (block.label) |*label| {
2598-
if (mem.eql(u8, label.name, label_name)) {
2599-
try label.results.append(self.gpa, void_inst);
2600-
const b = try self.requireRuntimeBlock(scope, inst.base.src);
2601-
return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.BreakVoid, .{
2703+
if (label.zir_block == zir_block) {
2704+
try label.results.append(self.gpa, operand);
2705+
const b = try self.requireRuntimeBlock(scope, src);
2706+
return self.addNewInstArgs(b, src, Type.initTag(.noreturn), Inst.Br, .{
26022707
.block = label.block_inst,
2708+
.operand = operand,
26032709
});
26042710
}
26052711
}
26062712
opt_block = block.parent;
2607-
} else {
2608-
return self.fail(scope, inst.base.src, "use of undeclared label '{}'", .{label_name});
2609-
}
2713+
} else unreachable;
26102714
}
26112715

26122716
fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {

src-self-hosted/codegen.zig

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,9 @@ const Function = struct {
418418
.assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?, arch),
419419
.bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
420420
.block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch),
421+
.br => return self.genBr(inst.cast(ir.Inst.Br).?, arch),
421422
.breakpoint => return self.genBreakpoint(inst.src, arch),
422-
.breakvoid => return self.genBreakVoid(inst.cast(ir.Inst.BreakVoid).?, arch),
423+
.brvoid => return self.genBrVoid(inst.cast(ir.Inst.BrVoid).?, arch),
423424
.call => return self.genCall(inst.cast(ir.Inst.Call).?, arch),
424425
.cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch),
425426
.condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch),
@@ -767,7 +768,13 @@ const Function = struct {
767768
}
768769
}
769770

770-
fn genBreakVoid(self: *Function, inst: *ir.Inst.BreakVoid, comptime arch: std.Target.Cpu.Arch) !MCValue {
771+
fn genBr(self: *Function, inst: *ir.Inst.Br, comptime arch: std.Target.Cpu.Arch) !MCValue {
772+
switch (arch) {
773+
else => return self.fail(inst.base.src, "TODO implement br for {}", .{self.target.cpu.arch}),
774+
}
775+
}
776+
777+
fn genBrVoid(self: *Function, inst: *ir.Inst.BrVoid, comptime arch: std.Target.Cpu.Arch) !MCValue {
771778
// Emit a jump with a relocation. It will be patched up after the block ends.
772779
try inst.args.block.codegen.relocs.ensureCapacity(self.gpa, inst.args.block.codegen.relocs.items.len + 1);
773780

@@ -780,7 +787,7 @@ const Function = struct {
780787
// Leave the jump offset undefined
781788
inst.args.block.codegen.relocs.appendAssumeCapacity(.{ .rel32 = self.code.items.len - 4 });
782789
},
783-
else => return self.fail(inst.base.src, "TODO implement breakvoid for {}", .{self.target.cpu.arch}),
790+
else => return self.fail(inst.base.src, "TODO implement brvoid for {}", .{self.target.cpu.arch}),
784791
}
785792
return .none;
786793
}

0 commit comments

Comments
 (0)