authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-08 20:33:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-08 20:33:33-07:00
log8e425c0c8d78acc64a4223a35010df478d5b7e16
treeb08ffa0b517c132392e78e6dfb97c5424cac5697
parentbe0546d877e0df18201e73e803d8a966b57625c5

stage2: `if` AST=>ZIR


5 files changed, 317 insertions(+), 128 deletions(-)

lib/std/zig/ast.zig+2
......@@ -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+145-41
......@@ -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
13591420fn astGenControlFlowExpression(
......@@ -1379,12 +1440,12 @@ fn astGenControlFlowExpression(
13791440fn 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
2255fn addZIRInst(
2326fn 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
2341fn 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.
22712354fn 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.
2360fn 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
22762365fn 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
2681fn 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
25912687fn 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
2693fn 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
26122716fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
src-self-hosted/codegen.zig+10-3
......@@ -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 }
src-self-hosted/ir.zig+15-4
......@@ -46,8 +46,9 @@ pub const Inst = struct {
4646 assembly,
4747 bitcast,
4848 block,
49 br,
4950 breakpoint,
50 breakvoid,
51 brvoid,
5152 call,
5253 cmp,
5354 condbr,
......@@ -80,7 +81,8 @@ pub const Inst = struct {
8081 .sub,
8182 => false,
8283
83 .breakvoid,
84 .br,
85 .brvoid,
8486 .condbr,
8587 .ret,
8688 .retvoid,
......@@ -162,14 +164,23 @@ pub const Inst = struct {
162164 codegen: codegen.BlockData = .{},
163165 };
164166
167 pub const Br = struct {
168 pub const base_tag = Tag.br;
169 base: Inst,
170 args: struct {
171 block: *Block,
172 operand: *Inst,
173 },
174 };
175
165176 pub const Breakpoint = struct {
166177 pub const base_tag = Tag.breakpoint;
167178 base: Inst,
168179 args: void,
169180 };
170181
171 pub const BreakVoid = struct {
172 pub const base_tag = Tag.breakvoid;
182 pub const BrVoid = struct {
183 pub const base_tag = Tag.brvoid;
173184 base: Inst,
174185 args: struct {
175186 block: *Block,
src-self-hosted/zir.zig+145-80
......@@ -38,6 +38,8 @@ pub const Inst = struct {
3838 arg,
3939 /// A labeled block of code, which can return a value.
4040 block,
41 /// Return a value from a `Block`.
42 @"break",
4143 breakpoint,
4244 /// Same as `break` but without an operand; the operand is assumed to be the void value.
4345 breakvoid,
......@@ -85,6 +87,7 @@ pub const Inst = struct {
8587 return switch (tag) {
8688 .arg => Arg,
8789 .block => Block,
90 .@"break" => Break,
8891 .breakpoint => Breakpoint,
8992 .breakvoid => BreakVoid,
9093 .call => Call,
......@@ -143,12 +146,22 @@ pub const Inst = struct {
143146 base: Inst,
144147
145148 positionals: struct {
146 label: []const u8,
147149 body: Module.Body,
148150 },
149151 kw_args: struct {},
150152 };
151153
154 pub const Break = struct {
155 pub const base_tag = Tag.@"break";
156 base: Inst,
157
158 positionals: struct {
159 block: *Block,
160 operand: *Inst,
161 },
162 kw_args: struct {},
163 };
164
152165 pub const Breakpoint = struct {
153166 pub const base_tag = Tag.breakpoint;
154167 base: Inst,
......@@ -162,7 +175,7 @@ pub const Inst = struct {
162175 base: Inst,
163176
164177 positionals: struct {
165 label: []const u8,
178 block: *Block,
166179 },
167180 kw_args: struct {},
168181 };
......@@ -610,8 +623,6 @@ pub const Module = struct {
610623 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};
611624 }
612625
613 const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize, name: []const u8 });
614
615626 const DeclAndIndex = struct {
616627 decl: *Decl,
617628 index: usize,
......@@ -645,84 +656,100 @@ pub const Module = struct {
645656 /// The allocator is used for temporary storage, but this function always returns
646657 /// with no resources allocated.
647658 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {
648 // First, build a map of *Inst to @ or % indexes
649 var inst_table = InstPtrTable.init(allocator);
650 defer inst_table.deinit();
659 var write = Writer{
660 .module = &self,
661 .inst_table = InstPtrTable.init(allocator),
662 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator),
663 .arena = std.heap.ArenaAllocator.init(allocator),
664 .indent = 2,
665 };
666 defer write.arena.deinit();
667 defer write.inst_table.deinit();
668 defer write.block_table.deinit();
651669
652 try inst_table.ensureCapacity(self.decls.len);
670 // First, build a map of *Inst to @ or % indexes
671 try write.inst_table.ensureCapacity(self.decls.len);
653672
654673 for (self.decls) |decl, decl_i| {
655 try inst_table.putNoClobber(decl.inst, .{ .inst = decl.inst, .index = null, .name = decl.name });
674 try write.inst_table.putNoClobber(decl.inst, .{ .inst = decl.inst, .index = null, .name = decl.name });
656675
657676 if (decl.inst.cast(Inst.Fn)) |fn_inst| {
658677 for (fn_inst.positionals.body.instructions) |inst, inst_i| {
659 try inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i, .name = undefined });
678 try write.inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i, .name = undefined });
660679 }
661680 }
662681 }
663682
664683 for (self.decls) |decl, i| {
665684 try stream.print("@{} ", .{decl.name});
666 try self.writeInstToStream(stream, decl.inst, &inst_table, 2);
685 try write.writeInstToStream(stream, decl.inst);
667686 try stream.writeByte('\n');
668687 }
669688 }
670689
690};
691
692const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize, name: []const u8 });
693
694const Writer = struct {
695 module: *const Module,
696 inst_table: InstPtrTable,
697 block_table: std.AutoHashMap(*Inst.Block, []const u8),
698 arena: std.heap.ArenaAllocator,
699 indent: usize,
700
671701 fn writeInstToStream(
672 self: Module,
702 self: *Writer,
673703 stream: var,
674704 inst: *Inst,
675 inst_table: *const InstPtrTable,
676 indent: usize,
677 ) @TypeOf(stream).Error!void {
705 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
678706 // TODO I tried implementing this with an inline for loop and hit a compiler bug
679707 switch (inst.tag) {
680 .arg => return self.writeInstToStreamGeneric(stream, .arg, inst, inst_table, indent),
681 .block => return self.writeInstToStreamGeneric(stream, .block, inst, inst_table, indent),
682 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table, indent),
683 .breakvoid => return self.writeInstToStreamGeneric(stream, .breakvoid, inst, inst_table, indent),
684 .call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table, indent),
685 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table, indent),
686 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table, indent),
687 .declval => return self.writeInstToStreamGeneric(stream, .declval, inst, inst_table, indent),
688 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst, inst_table, indent),
689 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst, inst_table, indent),
690 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst, inst_table, indent),
691 .str => return self.writeInstToStreamGeneric(stream, .str, inst, inst_table, indent),
692 .int => return self.writeInstToStreamGeneric(stream, .int, inst, inst_table, indent),
693 .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst, inst_table, indent),
694 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst, inst_table, indent),
695 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst, inst_table, indent),
696 .deref => return self.writeInstToStreamGeneric(stream, .deref, inst, inst_table, indent),
697 .as => return self.writeInstToStreamGeneric(stream, .as, inst, inst_table, indent),
698 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst, inst_table, indent),
699 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst, inst_table, indent),
700 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst, inst_table, indent),
701 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst, inst_table, indent),
702 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst, inst_table, indent),
703 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst, inst_table, indent),
704 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst, inst_table, indent),
705 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst, inst_table, indent),
706 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst, inst_table, indent),
707 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst, inst_table, indent),
708 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst, inst_table, indent),
709 .add => return self.writeInstToStreamGeneric(stream, .add, inst, inst_table, indent),
710 .sub => return self.writeInstToStreamGeneric(stream, .sub, inst, inst_table, indent),
711 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, inst, inst_table, indent),
712 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, inst, inst_table, indent),
713 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, inst, inst_table, indent),
714 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, inst, inst_table, indent),
708 .arg => return self.writeInstToStreamGeneric(stream, .arg, inst),
709 .block => return self.writeInstToStreamGeneric(stream, .block, inst),
710 .@"break" => return self.writeInstToStreamGeneric(stream, .@"break", inst),
711 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst),
712 .breakvoid => return self.writeInstToStreamGeneric(stream, .breakvoid, inst),
713 .call => return self.writeInstToStreamGeneric(stream, .call, inst),
714 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst),
715 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst),
716 .declval => return self.writeInstToStreamGeneric(stream, .declval, inst),
717 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst),
718 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst),
719 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst),
720 .str => return self.writeInstToStreamGeneric(stream, .str, inst),
721 .int => return self.writeInstToStreamGeneric(stream, .int, inst),
722 .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst),
723 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst),
724 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst),
725 .deref => return self.writeInstToStreamGeneric(stream, .deref, inst),
726 .as => return self.writeInstToStreamGeneric(stream, .as, inst),
727 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst),
728 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst),
729 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst),
730 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst),
731 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst),
732 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst),
733 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst),
734 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst),
735 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst),
736 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst),
737 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst),
738 .add => return self.writeInstToStreamGeneric(stream, .add, inst),
739 .sub => return self.writeInstToStreamGeneric(stream, .sub, inst),
740 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, inst),
741 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, inst),
742 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, inst),
743 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, inst),
715744 }
716745 }
717746
718747 fn writeInstToStreamGeneric(
719 self: Module,
748 self: *Writer,
720749 stream: var,
721750 comptime inst_tag: Inst.Tag,
722751 base: *Inst,
723 inst_table: *const InstPtrTable,
724 indent: usize,
725 ) @TypeOf(stream).Error!void {
752 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
726753 const SpecificInst = Inst.TagToType(inst_tag);
727754 const inst = @fieldParentPtr(SpecificInst, "base", base);
728755 const Positionals = @TypeOf(inst.positionals);
......@@ -732,7 +759,7 @@ pub const Module = struct {
732759 if (i != 0) {
733760 try stream.writeAll(", ");
734761 }
735 try self.writeParamToStream(stream, @field(inst.positionals, arg_field.name), inst_table, indent);
762 try self.writeParamToStream(stream, @field(inst.positionals, arg_field.name));
736763 }
737764
738765 comptime var need_comma = pos_fields.len != 0;
......@@ -742,13 +769,13 @@ pub const Module = struct {
742769 if (@field(inst.kw_args, arg_field.name)) |non_optional| {
743770 if (need_comma) try stream.writeAll(", ");
744771 try stream.print("{}=", .{arg_field.name});
745 try self.writeParamToStream(stream, non_optional, inst_table, indent);
772 try self.writeParamToStream(stream, non_optional);
746773 need_comma = true;
747774 }
748775 } else {
749776 if (need_comma) try stream.writeAll(", ");
750777 try stream.print("{}=", .{arg_field.name});
751 try self.writeParamToStream(stream, @field(inst.kw_args, arg_field.name), inst_table, indent);
778 try self.writeParamToStream(stream, @field(inst.kw_args, arg_field.name));
752779 need_comma = true;
753780 }
754781 }
......@@ -756,31 +783,37 @@ pub const Module = struct {
756783 try stream.writeByte(')');
757784 }
758785
759 fn writeParamToStream(self: Module, stream: var, param: var, inst_table: *const InstPtrTable, indent: usize) !void {
786 fn writeParamToStream(self: *Writer, stream: var, param: var) !void {
760787 if (@typeInfo(@TypeOf(param)) == .Enum) {
761788 return stream.writeAll(@tagName(param));
762789 }
763790 switch (@TypeOf(param)) {
764 *Inst => return self.writeInstParamToStream(stream, param, inst_table),
791 *Inst => return self.writeInstParamToStream(stream, param),
765792 []*Inst => {
766793 try stream.writeByte('[');
767794 for (param) |inst, i| {
768795 if (i != 0) {
769796 try stream.writeAll(", ");
770797 }
771 try self.writeInstParamToStream(stream, inst, inst_table);
798 try self.writeInstParamToStream(stream, inst);
772799 }
773800 try stream.writeByte(']');
774801 },
775802 Module.Body => {
776803 try stream.writeAll("{\n");
777804 for (param.instructions) |inst, i| {
778 try stream.writeByteNTimes(' ', indent);
805 try stream.writeByteNTimes(' ', self.indent);
779806 try stream.print("%{} ", .{i});
780 try self.writeInstToStream(stream, inst, inst_table, indent + 2);
807 if (inst.cast(Inst.Block)) |block| {
808 const name = try std.fmt.allocPrint(&self.arena.allocator, "label_{}", .{i});
809 try self.block_table.put(block, name);
810 }
811 self.indent += 2;
812 try self.writeInstToStream(stream, inst);
813 self.indent -= 2;
781814 try stream.writeByte('\n');
782815 }
783 try stream.writeByteNTimes(' ', indent - 2);
816 try stream.writeByteNTimes(' ', self.indent - 2);
784817 try stream.writeByte('}');
785818 },
786819 bool => return stream.writeByte("01"[@boolToInt(param)]),
......@@ -788,12 +821,16 @@ pub const Module = struct {
788821 BigIntConst, usize => return stream.print("{}", .{param}),
789822 TypedValue => unreachable, // this is a special case
790823 *IrModule.Decl => unreachable, // this is a special case
824 *Inst.Block => {
825 const name = self.block_table.get(param).?;
826 return std.zig.renderStringLiteral(name, stream);
827 },
791828 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
792829 }
793830 }
794831
795 fn writeInstParamToStream(self: Module, stream: var, inst: *Inst, inst_table: *const InstPtrTable) !void {
796 if (inst_table.get(inst)) |info| {
832 fn writeInstParamToStream(self: *Writer, stream: var, inst: *Inst) !void {
833 if (self.inst_table.get(inst)) |info| {
797834 if (info.index) |i| {
798835 try stream.print("%{}", .{info.index});
799836 } else {
......@@ -823,7 +860,9 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
823860 .global_name_map = &global_name_map,
824861 .decls = .{},
825862 .unnamed_index = 0,
863 .block_table = std.StringHashMap(*Inst.Block).init(allocator),
826864 };
865 defer parser.block_table.deinit();
827866 errdefer parser.arena.deinit();
828867
829868 parser.parseRoot() catch |err| switch (err) {
......@@ -849,6 +888,7 @@ const Parser = struct {
849888 global_name_map: *std.StringHashMap(*Inst),
850889 error_msg: ?ErrorMsg = null,
851890 unnamed_index: usize,
891 block_table: std.StringHashMap(*Inst.Block),
852892
853893 const Body = struct {
854894 instructions: std.ArrayList(*Inst),
......@@ -1057,6 +1097,10 @@ const Parser = struct {
10571097 .tag = InstType.base_tag,
10581098 };
10591099
1100 if (InstType == Inst.Block) {
1101 try self.block_table.put(inst_name, inst_specific);
1102 }
1103
10601104 if (@hasField(InstType, "ty")) {
10611105 inst_specific.ty = opt_type orelse {
10621106 return self.fail("instruction '" ++ fn_name ++ "' requires type", .{});
......@@ -1162,6 +1206,10 @@ const Parser = struct {
11621206 },
11631207 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
11641208 *IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
1209 *Inst.Block => {
1210 const name = try self.parseStringLiteral();
1211 return self.block_table.get(name).?;
1212 },
11651213 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
11661214 }
11671215 return self.fail("TODO parse parameter {}", .{@typeName(T)});
......@@ -1226,7 +1274,9 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {
12261274 .names = std.StringHashMap(void).init(allocator),
12271275 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
12281276 .indent = 0,
1277 .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
12291278 };
1279 defer ctx.block_table.deinit();
12301280 defer ctx.decls.deinit(allocator);
12311281 defer ctx.names.deinit();
12321282 defer ctx.primitive_table.deinit();
......@@ -1249,6 +1299,7 @@ const EmitZIR = struct {
12491299 next_auto_name: usize,
12501300 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),
12511301 indent: usize,
1302 block_table: std.AutoHashMap(*ir.Inst.Block, *Inst.Block),
12521303
12531304 fn emit(self: *EmitZIR) !void {
12541305 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced
......@@ -1611,33 +1662,47 @@ const EmitZIR = struct {
16111662 const old_inst = inst.cast(ir.Inst.Block).?;
16121663 const new_inst = try self.arena.allocator.create(Inst.Block);
16131664
1614 // We do this now so that the break instructions within the block
1615 // can find it.
1616 try inst_table.put(&old_inst.base, &new_inst.base);
1665 try self.block_table.put(old_inst, new_inst);
1666
1667 var block_body = std.ArrayList(*Inst).init(self.allocator);
1668 defer block_body.deinit();
1669
1670 try self.emitBody(old_inst.args.body, inst_table, &block_body);
1671
16171672 new_inst.* = .{
16181673 .base = .{
16191674 .src = inst.src,
16201675 .tag = Inst.Block.base_tag,
16211676 },
16221677 .positionals = .{
1623 .label = try self.autoName(),
1624 .body = undefined,
1678 .body = .{ .instructions = block_body.toOwnedSlice() },
16251679 },
16261680 .kw_args = .{},
16271681 };
16281682
1629 var block_body = std.ArrayList(*Inst).init(self.allocator);
1630 defer block_body.deinit();
1631
1632 try self.emitBody(old_inst.args.body, inst_table, &block_body);
1633 new_inst.positionals.body = .{ .instructions = block_body.toOwnedSlice() };
1634
1683 break :blk &new_inst.base;
1684 },
1685 .br => blk: {
1686 const old_inst = inst.cast(ir.Inst.Br).?;
1687 const new_block = self.block_table.get(old_inst.args.block).?;
1688 const new_inst = try self.arena.allocator.create(Inst.Break);
1689 new_inst.* = .{
1690 .base = .{
1691 .src = inst.src,
1692 .tag = Inst.Break.base_tag,
1693 },
1694 .positionals = .{
1695 .block = new_block,
1696 .operand = try self.resolveInst(new_body, old_inst.args.operand),
1697 },
1698 .kw_args = .{},
1699 };
16351700 break :blk &new_inst.base;
16361701 },
16371702 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
1638 .breakvoid => blk: {
1639 const old_inst = inst.cast(ir.Inst.BreakVoid).?;
1640 const new_block = inst_table.get(&old_inst.args.block.base).?;
1703 .brvoid => blk: {
1704 const old_inst = inst.cast(ir.Inst.BrVoid).?;
1705 const new_block = self.block_table.get(old_inst.args.block).?;
16411706 const new_inst = try self.arena.allocator.create(Inst.BreakVoid);
16421707 new_inst.* = .{
16431708 .base = .{
......@@ -1645,7 +1710,7 @@ const EmitZIR = struct {
16451710 .tag = Inst.BreakVoid.base_tag,
16461711 },
16471712 .positionals = .{
1648 .label = new_block.cast(Inst.Block).?.positionals.label,
1713 .block = new_block,
16491714 },
16501715 .kw_args = .{},
16511716 };