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 {...@@ -959,6 +959,8 @@ pub const Node = struct {
959 };959 };
960960
961 /// The params are directly after the FnProto in memory.961 /// 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.
962 pub const FnProto = struct {964 pub const FnProto = struct {
963 base: Node = Node{ .id = .FnProto },965 base: Node = Node{ .id = .FnProto },
964 doc_comments: ?*DocComment,966 doc_comments: ?*DocComment,
src-self-hosted/Module.zig+145-41
...@@ -303,14 +303,14 @@ pub const Scope = struct {...@@ -303,14 +303,14 @@ pub const Scope = struct {
303 switch (self.tag) {303 switch (self.tag) {
304 .block => return self.cast(Block).?.arena,304 .block => return self.cast(Block).?.arena,
305 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,305 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
306 .gen_zir => return &self.cast(GenZIR).?.arena.allocator,306 .gen_zir => return self.cast(GenZIR).?.arena,
307 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,307 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
308 .file => unreachable,308 .file => unreachable,
309 }309 }
310 }310 }
311311
312 /// Asserts the scope has a parent which is a DeclAnalysis and312 /// If the scope has a parent which is a `DeclAnalysis`,
313 /// returns the Decl.313 /// returns the `Decl`, otherwise returns `null`.
314 pub fn decl(self: *Scope) ?*Decl {314 pub fn decl(self: *Scope) ?*Decl {
315 return switch (self.tag) {315 return switch (self.tag) {
316 .block => self.cast(Block).?.decl,316 .block => self.cast(Block).?.decl,
...@@ -653,7 +653,7 @@ pub const Scope = struct {...@@ -653,7 +653,7 @@ pub const Scope = struct {
653 label: ?Label = null,653 label: ?Label = null,
654654
655 pub const Label = struct {655 pub const Label = struct {
656 name: []const u8,656 zir_block: *zir.Inst.Block,
657 results: ArrayListUnmanaged(*Inst),657 results: ArrayListUnmanaged(*Inst),
658 block_inst: *Inst.Block,658 block_inst: *Inst.Block,
659 };659 };
...@@ -674,8 +674,8 @@ pub const Scope = struct {...@@ -674,8 +674,8 @@ pub const Scope = struct {
674 pub const base_tag: Tag = .gen_zir;674 pub const base_tag: Tag = .gen_zir;
675 base: Scope = Scope{ .tag = base_tag },675 base: Scope = Scope{ .tag = base_tag },
676 decl: *Decl,676 decl: *Decl,
677 arena: std.heap.ArenaAllocator,677 arena: *Allocator,
678 instructions: std.ArrayList(*zir.Inst),678 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
679 };679 };
680};680};
681681
...@@ -1115,19 +1115,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1115,19 +1115,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1115 // This arena allocator's memory is discarded at the end of this function. It is used1115 // This arena allocator's memory is discarded at the end of this function. It is used
1116 // to determine the type of the function, and hence the type of the decl, which is needed1116 // to determine the type of the function, and hence the type of the decl, which is needed
1117 // to complete the Decl analysis.1117 // to complete the Decl analysis.
1118 var fn_type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1119 defer fn_type_scope_arena.deinit();
1118 var fn_type_scope: Scope.GenZIR = .{1120 var fn_type_scope: Scope.GenZIR = .{
1119 .decl = decl,1121 .decl = decl,
1120 .arena = std.heap.ArenaAllocator.init(self.gpa),1122 .arena = &fn_type_scope_arena.allocator,
1121 .instructions = std.ArrayList(*zir.Inst).init(self.gpa),
1122 };1123 };
1123 defer fn_type_scope.arena.deinit();1124 defer fn_type_scope.instructions.deinit(self.gpa);
1124 defer fn_type_scope.instructions.deinit();
11251125
1126 const body_node = fn_proto.body_node orelse1126 const body_node = fn_proto.body_node orelse
1127 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});1127 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
11281128
1129 const param_decls = fn_proto.params();1129 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);
1131 for (param_decls) |param_decl, i| {1131 for (param_decls) |param_decl, i| {
1132 const param_type_node = switch (param_decl.param_type) {1132 const param_type_node = switch (param_decl.param_type) {
1133 .var_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),1133 .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 {...@@ -1190,24 +1190,24 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1190 const fn_zir = blk: {1190 const fn_zir = blk: {
1191 // This scope's arena memory is discarded after the ZIR generation1191 // This scope's arena memory is discarded after the ZIR generation
1192 // pass completes, and semantic analysis of it completes.1192 // 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();
1193 var gen_scope: Scope.GenZIR = .{1195 var gen_scope: Scope.GenZIR = .{
1194 .decl = decl,1196 .decl = decl,
1195 .arena = std.heap.ArenaAllocator.init(self.gpa),1197 .arena = &gen_scope_arena.allocator,
1196 .instructions = std.ArrayList(*zir.Inst).init(self.gpa),
1197 };1198 };
1198 errdefer gen_scope.arena.deinit();1199 defer gen_scope.instructions.deinit(self.gpa);
1199 defer gen_scope.instructions.deinit();
12001200
1201 const body_block = body_node.cast(ast.Node.Block).?;1201 const body_block = body_node.cast(ast.Node.Block).?;
12021202
1203 try self.astGenBlock(&gen_scope.base, body_block);1203 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);
1206 fn_zir.* = .{1206 fn_zir.* = .{
1207 .body = .{1207 .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),
1209 },1209 },
1210 .arena = gen_scope.arena.state,1210 .arena = gen_scope_arena.state,
1211 };1211 };
1212 break :blk fn_zir;1212 break :blk fn_zir;
1213 };1213 };
...@@ -1351,9 +1351,70 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir...@@ -1351,9 +1351,70 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir
1351 return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{});1351 return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{});
1352 }1352 }
1353 }1353 }
1354 const cond = try self.astGenExpr(scope, if_node.condition);1354 var block_scope: Scope.GenZIR = .{
1355 const body = try self.astGenExpr(scope, if_node.condition);1355 .decl = scope.decl().?,
1356 return self.failNode(scope, if_node.condition, "TODO implement astGenIf", .{});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;
1357}1418}
13581419
1359fn astGenControlFlowExpression(1420fn astGenControlFlowExpression(
...@@ -1379,12 +1440,12 @@ fn astGenControlFlowExpression(...@@ -1379,12 +1440,12 @@ fn astGenControlFlowExpression(
1379fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {1440fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
1380 const tree = scope.tree();1441 const tree = scope.tree();
1381 const ident_name = tree.tokenSlice(ident.token);1442 const ident_name = tree.tokenSlice(ident.token);
1443 const src = tree.token_locs[ident.token].start;
1382 if (mem.eql(u8, ident_name, "_")) {1444 if (mem.eql(u8, ident_name, "_")) {
1383 return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});1445 return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});
1384 }1446 }
13851447
1386 if (getSimplePrimitiveValue(ident_name)) |typed_value| {1448 if (getSimplePrimitiveValue(ident_name)) |typed_value| {
1387 const src = tree.token_locs[ident.token].start;
1388 return self.addZIRInstConst(scope, src, typed_value);1449 return self.addZIRInstConst(scope, src, typed_value);
1389 }1450 }
13901451
...@@ -1408,7 +1469,6 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE...@@ -1408,7 +1469,6 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
1408 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),1469 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
1409 else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),1470 else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),
1410 };1471 };
1411 const src = tree.token_locs[ident.token].start;
1412 return self.addZIRInstConst(scope, src, .{1472 return self.addZIRInstConst(scope, src, .{
1413 .ty = Type.initTag(.type),1473 .ty = Type.initTag(.type),
1414 .val = val,1474 .val = val,
...@@ -1417,10 +1477,21 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE...@@ -1417,10 +1477,21 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
1417 }1477 }
14181478
1419 if (self.lookupDeclName(scope, ident_name)) |decl| {1479 if (self.lookupDeclName(scope, ident_name)) |decl| {
1420 const src = tree.token_locs[ident.token].start;
1421 return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});1480 return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
1422 }1481 }
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
1424 return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});1495 return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});
1425}1496}
14261497
...@@ -1563,7 +1634,7 @@ fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zi...@@ -1563,7 +1634,7 @@ fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zi
1563 const lhs = try self.astGenExpr(scope, call.lhs);1634 const lhs = try self.astGenExpr(scope, call.lhs);
15641635
1565 const param_nodes = call.params();1636 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);
1567 for (param_nodes) |param_node, i| {1638 for (param_nodes) |param_node, i| {
1568 args[i] = try self.astGenExpr(scope, param_node);1639 args[i] = try self.astGenExpr(scope, param_node);
1569 }1640 }
...@@ -2239,7 +2310,7 @@ fn newZIRInst(...@@ -2239,7 +2310,7 @@ fn newZIRInst(
2239 comptime T: type,2310 comptime T: type,
2240 positionals: std.meta.fieldInfo(T, "positionals").field_type,2311 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2241 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,2312 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2242) !*zir.Inst {2313) !*T {
2243 const inst = try gpa.create(T);2314 const inst = try gpa.create(T);
2244 inst.* = .{2315 inst.* = .{
2245 .base = .{2316 .base = .{
...@@ -2249,30 +2320,48 @@ fn newZIRInst(...@@ -2249,30 +2320,48 @@ fn newZIRInst(
2249 .positionals = positionals,2320 .positionals = positionals,
2250 .kw_args = kw_args,2321 .kw_args = kw_args,
2251 };2322 };
2252 return &inst.base;2323 return inst;
2253}2324}
22542325
2255fn addZIRInst(2326fn addZIRInstSpecial(
2256 self: *Module,2327 self: *Module,
2257 scope: *Scope,2328 scope: *Scope,
2258 src: usize,2329 src: usize,
2259 comptime T: type,2330 comptime T: type,
2260 positionals: std.meta.fieldInfo(T, "positionals").field_type,2331 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2261 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,2332 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2262) !*zir.Inst {2333) !*T {
2263 const gen_zir = scope.cast(Scope.GenZIR).?;2334 const gen_zir = scope.cast(Scope.GenZIR).?;
2264 try gen_zir.instructions.ensureCapacity(gen_zir.instructions.items.len + 1);2335 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);
2265 const inst = try newZIRInst(&gen_zir.arena.allocator, src, T, positionals, kw_args);2336 const inst = try newZIRInst(gen_zir.arena, src, T, positionals, kw_args);
2266 gen_zir.instructions.appendAssumeCapacity(inst);2337 gen_zir.instructions.appendAssumeCapacity(&inst.base);
2267 return inst;2338 return inst;
2268}2339}
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
2270/// TODO The existence of this function is a workaround for a bug in stage1.2353/// TODO The existence of this function is a workaround for a bug in stage1.
2271fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {2354fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {
2272 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;2355 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;
2273 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});2356 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
2274}2357}
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
2276fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {2365fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {
2277 const inst = try block.arena.create(T);2366 const inst = try block.arena.create(T);
2278 inst.* = .{2367 inst.* = .{
...@@ -2403,6 +2492,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2403,6 +2492,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2403 switch (old_inst.tag) {2492 switch (old_inst.tag) {
2404 .arg => return self.analyzeInstArg(scope, old_inst.cast(zir.Inst.Arg).?),2493 .arg => return self.analyzeInstArg(scope, old_inst.cast(zir.Inst.Arg).?),
2405 .block => return self.analyzeInstBlock(scope, old_inst.cast(zir.Inst.Block).?),2494 .block => return self.analyzeInstBlock(scope, old_inst.cast(zir.Inst.Block).?),
2495 .@"break" => return self.analyzeInstBreak(scope, old_inst.cast(zir.Inst.Break).?),
2406 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),2496 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
2407 .breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.cast(zir.Inst.BreakVoid).?),2497 .breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.cast(zir.Inst.BreakVoid).?),
2408 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),2498 .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...@@ -2559,7 +2649,7 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr
2559 .arena = parent_block.arena,2649 .arena = parent_block.arena,
2560 // TODO @as here is working around a miscompilation compiler bug :(2650 // TODO @as here is working around a miscompilation compiler bug :(
2561 .label = @as(?Scope.Block.Label, Scope.Block.Label{2651 .label = @as(?Scope.Block.Label, Scope.Block.Label{
2562 .name = inst.positionals.label,2652 .zir_block = inst,
2563 .results = .{},2653 .results = .{},
2564 .block_inst = block_inst,2654 .block_inst = block_inst,
2565 }),2655 }),
...@@ -2588,25 +2678,39 @@ fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoin...@@ -2588,25 +2678,39 @@ fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoin
2588 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});2678 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
2589}2679}
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
2591fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst {2687fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst {
2592 const label_name = inst.positionals.label;2688 const block = inst.positionals.block;
2593 const void_inst = try self.constVoid(scope, inst.base.src);2689 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 {
2595 var opt_block = scope.cast(Scope.Block);2700 var opt_block = scope.cast(Scope.Block);
2596 while (opt_block) |block| {2701 while (opt_block) |block| {
2597 if (block.label) |*label| {2702 if (block.label) |*label| {
2598 if (mem.eql(u8, label.name, label_name)) {2703 if (label.zir_block == zir_block) {
2599 try label.results.append(self.gpa, void_inst);2704 try label.results.append(self.gpa, operand);
2600 const b = try self.requireRuntimeBlock(scope, inst.base.src);2705 const b = try self.requireRuntimeBlock(scope, src);
2601 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.BreakVoid, .{2706 return self.addNewInstArgs(b, src, Type.initTag(.noreturn), Inst.Br, .{
2602 .block = label.block_inst,2707 .block = label.block_inst,
2708 .operand = operand,
2603 });2709 });
2604 }2710 }
2605 }2711 }
2606 opt_block = block.parent;2712 opt_block = block.parent;
2607 } else {2713 } else unreachable;
2608 return self.fail(scope, inst.base.src, "use of undeclared label '{}'", .{label_name});
2609 }
2610}2714}
26112715
2612fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {2716fn 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 {...@@ -418,8 +418,9 @@ const Function = struct {
418 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?, arch),418 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?, arch),
419 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),419 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
420 .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch),420 .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch),
421 .br => return self.genBr(inst.cast(ir.Inst.Br).?, arch),
421 .breakpoint => return self.genBreakpoint(inst.src, arch),422 .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),
423 .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch),424 .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch),
424 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch),425 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch),
425 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch),426 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch),
...@@ -767,7 +768,13 @@ const Function = struct {...@@ -767,7 +768,13 @@ const Function = struct {
767 }768 }
768 }769 }
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 {
771 // Emit a jump with a relocation. It will be patched up after the block ends.778 // Emit a jump with a relocation. It will be patched up after the block ends.
772 try inst.args.block.codegen.relocs.ensureCapacity(self.gpa, inst.args.block.codegen.relocs.items.len + 1);779 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 {...@@ -780,7 +787,7 @@ const Function = struct {
780 // Leave the jump offset undefined787 // Leave the jump offset undefined
781 inst.args.block.codegen.relocs.appendAssumeCapacity(.{ .rel32 = self.code.items.len - 4 });788 inst.args.block.codegen.relocs.appendAssumeCapacity(.{ .rel32 = self.code.items.len - 4 });
782 },789 },
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}),
784 }791 }
785 return .none;792 return .none;
786 }793 }
src-self-hosted/ir.zig+15-4
...@@ -46,8 +46,9 @@ pub const Inst = struct {...@@ -46,8 +46,9 @@ pub const Inst = struct {
46 assembly,46 assembly,
47 bitcast,47 bitcast,
48 block,48 block,
49 br,
49 breakpoint,50 breakpoint,
50 breakvoid,51 brvoid,
51 call,52 call,
52 cmp,53 cmp,
53 condbr,54 condbr,
...@@ -80,7 +81,8 @@ pub const Inst = struct {...@@ -80,7 +81,8 @@ pub const Inst = struct {
80 .sub,81 .sub,
81 => false,82 => false,
8283
83 .breakvoid,84 .br,
85 .brvoid,
84 .condbr,86 .condbr,
85 .ret,87 .ret,
86 .retvoid,88 .retvoid,
...@@ -162,14 +164,23 @@ pub const Inst = struct {...@@ -162,14 +164,23 @@ pub const Inst = struct {
162 codegen: codegen.BlockData = .{},164 codegen: codegen.BlockData = .{},
163 };165 };
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
165 pub const Breakpoint = struct {176 pub const Breakpoint = struct {
166 pub const base_tag = Tag.breakpoint;177 pub const base_tag = Tag.breakpoint;
167 base: Inst,178 base: Inst,
168 args: void,179 args: void,
169 };180 };
170181
171 pub const BreakVoid = struct {182 pub const BrVoid = struct {
172 pub const base_tag = Tag.breakvoid;183 pub const base_tag = Tag.brvoid;
173 base: Inst,184 base: Inst,
174 args: struct {185 args: struct {
175 block: *Block,186 block: *Block,
src-self-hosted/zir.zig+145-80
...@@ -38,6 +38,8 @@ pub const Inst = struct {...@@ -38,6 +38,8 @@ pub const Inst = struct {
38 arg,38 arg,
39 /// A labeled block of code, which can return a value.39 /// A labeled block of code, which can return a value.
40 block,40 block,
41 /// Return a value from a `Block`.
42 @"break",
41 breakpoint,43 breakpoint,
42 /// Same as `break` but without an operand; the operand is assumed to be the void value.44 /// Same as `break` but without an operand; the operand is assumed to be the void value.
43 breakvoid,45 breakvoid,
...@@ -85,6 +87,7 @@ pub const Inst = struct {...@@ -85,6 +87,7 @@ pub const Inst = struct {
85 return switch (tag) {87 return switch (tag) {
86 .arg => Arg,88 .arg => Arg,
87 .block => Block,89 .block => Block,
90 .@"break" => Break,
88 .breakpoint => Breakpoint,91 .breakpoint => Breakpoint,
89 .breakvoid => BreakVoid,92 .breakvoid => BreakVoid,
90 .call => Call,93 .call => Call,
...@@ -143,12 +146,22 @@ pub const Inst = struct {...@@ -143,12 +146,22 @@ pub const Inst = struct {
143 base: Inst,146 base: Inst,
144147
145 positionals: struct {148 positionals: struct {
146 label: []const u8,
147 body: Module.Body,149 body: Module.Body,
148 },150 },
149 kw_args: struct {},151 kw_args: struct {},
150 };152 };
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
152 pub const Breakpoint = struct {165 pub const Breakpoint = struct {
153 pub const base_tag = Tag.breakpoint;166 pub const base_tag = Tag.breakpoint;
154 base: Inst,167 base: Inst,
...@@ -162,7 +175,7 @@ pub const Inst = struct {...@@ -162,7 +175,7 @@ pub const Inst = struct {
162 base: Inst,175 base: Inst,
163176
164 positionals: struct {177 positionals: struct {
165 label: []const u8,178 block: *Block,
166 },179 },
167 kw_args: struct {},180 kw_args: struct {},
168 };181 };
...@@ -610,8 +623,6 @@ pub const Module = struct {...@@ -610,8 +623,6 @@ pub const Module = struct {
610 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};623 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};
611 }624 }
612625
613 const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize, name: []const u8 });
614
615 const DeclAndIndex = struct {626 const DeclAndIndex = struct {
616 decl: *Decl,627 decl: *Decl,
617 index: usize,628 index: usize,
...@@ -645,84 +656,100 @@ pub const Module = struct {...@@ -645,84 +656,100 @@ pub const Module = struct {
645 /// The allocator is used for temporary storage, but this function always returns656 /// The allocator is used for temporary storage, but this function always returns
646 /// with no resources allocated.657 /// with no resources allocated.
647 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {658 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {
648 // First, build a map of *Inst to @ or % indexes659 var write = Writer{
649 var inst_table = InstPtrTable.init(allocator);660 .module = &self,
650 defer inst_table.deinit();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
654 for (self.decls) |decl, decl_i| {673 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
657 if (decl.inst.cast(Inst.Fn)) |fn_inst| {676 if (decl.inst.cast(Inst.Fn)) |fn_inst| {
658 for (fn_inst.positionals.body.instructions) |inst, inst_i| {677 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 });
660 }679 }
661 }680 }
662 }681 }
663682
664 for (self.decls) |decl, i| {683 for (self.decls) |decl, i| {
665 try stream.print("@{} ", .{decl.name});684 try stream.print("@{} ", .{decl.name});
666 try self.writeInstToStream(stream, decl.inst, &inst_table, 2);685 try write.writeInstToStream(stream, decl.inst);
667 try stream.writeByte('\n');686 try stream.writeByte('\n');
668 }687 }
669 }688 }
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
671 fn writeInstToStream(701 fn writeInstToStream(
672 self: Module,702 self: *Writer,
673 stream: var,703 stream: var,
674 inst: *Inst,704 inst: *Inst,
675 inst_table: *const InstPtrTable,705 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
676 indent: usize,
677 ) @TypeOf(stream).Error!void {
678 // TODO I tried implementing this with an inline for loop and hit a compiler bug706 // TODO I tried implementing this with an inline for loop and hit a compiler bug
679 switch (inst.tag) {707 switch (inst.tag) {
680 .arg => return self.writeInstToStreamGeneric(stream, .arg, inst, inst_table, indent),708 .arg => return self.writeInstToStreamGeneric(stream, .arg, inst),
681 .block => return self.writeInstToStreamGeneric(stream, .block, inst, inst_table, indent),709 .block => return self.writeInstToStreamGeneric(stream, .block, inst),
682 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table, indent),710 .@"break" => return self.writeInstToStreamGeneric(stream, .@"break", inst),
683 .breakvoid => return self.writeInstToStreamGeneric(stream, .breakvoid, inst, inst_table, indent),711 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst),
684 .call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table, indent),712 .breakvoid => return self.writeInstToStreamGeneric(stream, .breakvoid, inst),
685 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table, indent),713 .call => return self.writeInstToStreamGeneric(stream, .call, inst),
686 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table, indent),714 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst),
687 .declval => return self.writeInstToStreamGeneric(stream, .declval, inst, inst_table, indent),715 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst),
688 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst, inst_table, indent),716 .declval => return self.writeInstToStreamGeneric(stream, .declval, inst),
689 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst, inst_table, indent),717 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst),
690 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst, inst_table, indent),718 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst),
691 .str => return self.writeInstToStreamGeneric(stream, .str, inst, inst_table, indent),719 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst),
692 .int => return self.writeInstToStreamGeneric(stream, .int, inst, inst_table, indent),720 .str => return self.writeInstToStreamGeneric(stream, .str, inst),
693 .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst, inst_table, indent),721 .int => return self.writeInstToStreamGeneric(stream, .int, inst),
694 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst, inst_table, indent),722 .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst),
695 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst, inst_table, indent),723 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst),
696 .deref => return self.writeInstToStreamGeneric(stream, .deref, inst, inst_table, indent),724 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst),
697 .as => return self.writeInstToStreamGeneric(stream, .as, inst, inst_table, indent),725 .deref => return self.writeInstToStreamGeneric(stream, .deref, inst),
698 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst, inst_table, indent),726 .as => return self.writeInstToStreamGeneric(stream, .as, inst),
699 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst, inst_table, indent),727 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst),
700 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst, inst_table, indent),728 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst),
701 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst, inst_table, indent),729 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst),
702 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst, inst_table, indent),730 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst),
703 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst, inst_table, indent),731 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst),
704 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst, inst_table, indent),732 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst),
705 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst, inst_table, indent),733 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst),
706 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst, inst_table, indent),734 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst),
707 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst, inst_table, indent),735 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst),
708 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst, inst_table, indent),736 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst),
709 .add => return self.writeInstToStreamGeneric(stream, .add, inst, inst_table, indent),737 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst),
710 .sub => return self.writeInstToStreamGeneric(stream, .sub, inst, inst_table, indent),738 .add => return self.writeInstToStreamGeneric(stream, .add, inst),
711 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, inst, inst_table, indent),739 .sub => return self.writeInstToStreamGeneric(stream, .sub, inst),
712 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, inst, inst_table, indent),740 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, inst),
713 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, inst, inst_table, indent),741 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, inst),
714 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, inst, inst_table, indent),742 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, inst),
743 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, inst),
715 }744 }
716 }745 }
717746
718 fn writeInstToStreamGeneric(747 fn writeInstToStreamGeneric(
719 self: Module,748 self: *Writer,
720 stream: var,749 stream: var,
721 comptime inst_tag: Inst.Tag,750 comptime inst_tag: Inst.Tag,
722 base: *Inst,751 base: *Inst,
723 inst_table: *const InstPtrTable,752 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
724 indent: usize,
725 ) @TypeOf(stream).Error!void {
726 const SpecificInst = Inst.TagToType(inst_tag);753 const SpecificInst = Inst.TagToType(inst_tag);
727 const inst = @fieldParentPtr(SpecificInst, "base", base);754 const inst = @fieldParentPtr(SpecificInst, "base", base);
728 const Positionals = @TypeOf(inst.positionals);755 const Positionals = @TypeOf(inst.positionals);
...@@ -732,7 +759,7 @@ pub const Module = struct {...@@ -732,7 +759,7 @@ pub const Module = struct {
732 if (i != 0) {759 if (i != 0) {
733 try stream.writeAll(", ");760 try stream.writeAll(", ");
734 }761 }
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));
736 }763 }
737764
738 comptime var need_comma = pos_fields.len != 0;765 comptime var need_comma = pos_fields.len != 0;
...@@ -742,13 +769,13 @@ pub const Module = struct {...@@ -742,13 +769,13 @@ pub const Module = struct {
742 if (@field(inst.kw_args, arg_field.name)) |non_optional| {769 if (@field(inst.kw_args, arg_field.name)) |non_optional| {
743 if (need_comma) try stream.writeAll(", ");770 if (need_comma) try stream.writeAll(", ");
744 try stream.print("{}=", .{arg_field.name});771 try stream.print("{}=", .{arg_field.name});
745 try self.writeParamToStream(stream, non_optional, inst_table, indent);772 try self.writeParamToStream(stream, non_optional);
746 need_comma = true;773 need_comma = true;
747 }774 }
748 } else {775 } else {
749 if (need_comma) try stream.writeAll(", ");776 if (need_comma) try stream.writeAll(", ");
750 try stream.print("{}=", .{arg_field.name});777 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));
752 need_comma = true;779 need_comma = true;
753 }780 }
754 }781 }
...@@ -756,31 +783,37 @@ pub const Module = struct {...@@ -756,31 +783,37 @@ pub const Module = struct {
756 try stream.writeByte(')');783 try stream.writeByte(')');
757 }784 }
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 {
760 if (@typeInfo(@TypeOf(param)) == .Enum) {787 if (@typeInfo(@TypeOf(param)) == .Enum) {
761 return stream.writeAll(@tagName(param));788 return stream.writeAll(@tagName(param));
762 }789 }
763 switch (@TypeOf(param)) {790 switch (@TypeOf(param)) {
764 *Inst => return self.writeInstParamToStream(stream, param, inst_table),791 *Inst => return self.writeInstParamToStream(stream, param),
765 []*Inst => {792 []*Inst => {
766 try stream.writeByte('[');793 try stream.writeByte('[');
767 for (param) |inst, i| {794 for (param) |inst, i| {
768 if (i != 0) {795 if (i != 0) {
769 try stream.writeAll(", ");796 try stream.writeAll(", ");
770 }797 }
771 try self.writeInstParamToStream(stream, inst, inst_table);798 try self.writeInstParamToStream(stream, inst);
772 }799 }
773 try stream.writeByte(']');800 try stream.writeByte(']');
774 },801 },
775 Module.Body => {802 Module.Body => {
776 try stream.writeAll("{\n");803 try stream.writeAll("{\n");
777 for (param.instructions) |inst, i| {804 for (param.instructions) |inst, i| {
778 try stream.writeByteNTimes(' ', indent);805 try stream.writeByteNTimes(' ', self.indent);
779 try stream.print("%{} ", .{i});806 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;
781 try stream.writeByte('\n');814 try stream.writeByte('\n');
782 }815 }
783 try stream.writeByteNTimes(' ', indent - 2);816 try stream.writeByteNTimes(' ', self.indent - 2);
784 try stream.writeByte('}');817 try stream.writeByte('}');
785 },818 },
786 bool => return stream.writeByte("01"[@boolToInt(param)]),819 bool => return stream.writeByte("01"[@boolToInt(param)]),
...@@ -788,12 +821,16 @@ pub const Module = struct {...@@ -788,12 +821,16 @@ pub const Module = struct {
788 BigIntConst, usize => return stream.print("{}", .{param}),821 BigIntConst, usize => return stream.print("{}", .{param}),
789 TypedValue => unreachable, // this is a special case822 TypedValue => unreachable, // this is a special case
790 *IrModule.Decl => unreachable, // this is a special case823 *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 },
791 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),828 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
792 }829 }
793 }830 }
794831
795 fn writeInstParamToStream(self: Module, stream: var, inst: *Inst, inst_table: *const InstPtrTable) !void {832 fn writeInstParamToStream(self: *Writer, stream: var, inst: *Inst) !void {
796 if (inst_table.get(inst)) |info| {833 if (self.inst_table.get(inst)) |info| {
797 if (info.index) |i| {834 if (info.index) |i| {
798 try stream.print("%{}", .{info.index});835 try stream.print("%{}", .{info.index});
799 } else {836 } else {
...@@ -823,7 +860,9 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module...@@ -823,7 +860,9 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
823 .global_name_map = &global_name_map,860 .global_name_map = &global_name_map,
824 .decls = .{},861 .decls = .{},
825 .unnamed_index = 0,862 .unnamed_index = 0,
863 .block_table = std.StringHashMap(*Inst.Block).init(allocator),
826 };864 };
865 defer parser.block_table.deinit();
827 errdefer parser.arena.deinit();866 errdefer parser.arena.deinit();
828867
829 parser.parseRoot() catch |err| switch (err) {868 parser.parseRoot() catch |err| switch (err) {
...@@ -849,6 +888,7 @@ const Parser = struct {...@@ -849,6 +888,7 @@ const Parser = struct {
849 global_name_map: *std.StringHashMap(*Inst),888 global_name_map: *std.StringHashMap(*Inst),
850 error_msg: ?ErrorMsg = null,889 error_msg: ?ErrorMsg = null,
851 unnamed_index: usize,890 unnamed_index: usize,
891 block_table: std.StringHashMap(*Inst.Block),
852892
853 const Body = struct {893 const Body = struct {
854 instructions: std.ArrayList(*Inst),894 instructions: std.ArrayList(*Inst),
...@@ -1057,6 +1097,10 @@ const Parser = struct {...@@ -1057,6 +1097,10 @@ const Parser = struct {
1057 .tag = InstType.base_tag,1097 .tag = InstType.base_tag,
1058 };1098 };
10591099
1100 if (InstType == Inst.Block) {
1101 try self.block_table.put(inst_name, inst_specific);
1102 }
1103
1060 if (@hasField(InstType, "ty")) {1104 if (@hasField(InstType, "ty")) {
1061 inst_specific.ty = opt_type orelse {1105 inst_specific.ty = opt_type orelse {
1062 return self.fail("instruction '" ++ fn_name ++ "' requires type", .{});1106 return self.fail("instruction '" ++ fn_name ++ "' requires type", .{});
...@@ -1162,6 +1206,10 @@ const Parser = struct {...@@ -1162,6 +1206,10 @@ const Parser = struct {
1162 },1206 },
1163 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),1207 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
1164 *IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),1208 *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 },
1165 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),1213 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
1166 }1214 }
1167 return self.fail("TODO parse parameter {}", .{@typeName(T)});1215 return self.fail("TODO parse parameter {}", .{@typeName(T)});
...@@ -1226,7 +1274,9 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {...@@ -1226,7 +1274,9 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {
1226 .names = std.StringHashMap(void).init(allocator),1274 .names = std.StringHashMap(void).init(allocator),
1227 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),1275 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
1228 .indent = 0,1276 .indent = 0,
1277 .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
1229 };1278 };
1279 defer ctx.block_table.deinit();
1230 defer ctx.decls.deinit(allocator);1280 defer ctx.decls.deinit(allocator);
1231 defer ctx.names.deinit();1281 defer ctx.names.deinit();
1232 defer ctx.primitive_table.deinit();1282 defer ctx.primitive_table.deinit();
...@@ -1249,6 +1299,7 @@ const EmitZIR = struct {...@@ -1249,6 +1299,7 @@ const EmitZIR = struct {
1249 next_auto_name: usize,1299 next_auto_name: usize,
1250 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),1300 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),
1251 indent: usize,1301 indent: usize,
1302 block_table: std.AutoHashMap(*ir.Inst.Block, *Inst.Block),
12521303
1253 fn emit(self: *EmitZIR) !void {1304 fn emit(self: *EmitZIR) !void {
1254 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced1305 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced
...@@ -1611,33 +1662,47 @@ const EmitZIR = struct {...@@ -1611,33 +1662,47 @@ const EmitZIR = struct {
1611 const old_inst = inst.cast(ir.Inst.Block).?;1662 const old_inst = inst.cast(ir.Inst.Block).?;
1612 const new_inst = try self.arena.allocator.create(Inst.Block);1663 const new_inst = try self.arena.allocator.create(Inst.Block);
16131664
1614 // We do this now so that the break instructions within the block1665 try self.block_table.put(old_inst, new_inst);
1615 // can find it.1666
1616 try inst_table.put(&old_inst.base, &new_inst.base);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
1617 new_inst.* = .{1672 new_inst.* = .{
1618 .base = .{1673 .base = .{
1619 .src = inst.src,1674 .src = inst.src,
1620 .tag = Inst.Block.base_tag,1675 .tag = Inst.Block.base_tag,
1621 },1676 },
1622 .positionals = .{1677 .positionals = .{
1623 .label = try self.autoName(),1678 .body = .{ .instructions = block_body.toOwnedSlice() },
1624 .body = undefined,
1625 },1679 },
1626 .kw_args = .{},1680 .kw_args = .{},
1627 };1681 };
16281682
1629 var block_body = std.ArrayList(*Inst).init(self.allocator);1683 break :blk &new_inst.base;
1630 defer block_body.deinit();1684 },
16311685 .br => blk: {
1632 try self.emitBody(old_inst.args.body, inst_table, &block_body);1686 const old_inst = inst.cast(ir.Inst.Br).?;
1633 new_inst.positionals.body = .{ .instructions = block_body.toOwnedSlice() };1687 const new_block = self.block_table.get(old_inst.args.block).?;
16341688 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 };
1635 break :blk &new_inst.base;1700 break :blk &new_inst.base;
1636 },1701 },
1637 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),1702 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
1638 .breakvoid => blk: {1703 .brvoid => blk: {
1639 const old_inst = inst.cast(ir.Inst.BreakVoid).?;1704 const old_inst = inst.cast(ir.Inst.BrVoid).?;
1640 const new_block = inst_table.get(&old_inst.args.block.base).?;1705 const new_block = self.block_table.get(old_inst.args.block).?;
1641 const new_inst = try self.arena.allocator.create(Inst.BreakVoid);1706 const new_inst = try self.arena.allocator.create(Inst.BreakVoid);
1642 new_inst.* = .{1707 new_inst.* = .{
1643 .base = .{1708 .base = .{
...@@ -1645,7 +1710,7 @@ const EmitZIR = struct {...@@ -1645,7 +1710,7 @@ const EmitZIR = struct {
1645 .tag = Inst.BreakVoid.base_tag,1710 .tag = Inst.BreakVoid.base_tag,
1646 },1711 },
1647 .positionals = .{1712 .positionals = .{
1648 .label = new_block.cast(Inst.Block).?.positionals.label,1713 .block = new_block,
1649 },1714 },
1650 .kw_args = .{},1715 .kw_args = .{},
1651 };1716 };