| author | |
| committer | |
| log | 31023de6c4b3957ef356be01b5454426844955a9 |
| tree | 7951b8c7265ace392bde49165b505762f1cc33e8 |
| parent | 12d18a36e5eed4b0898e93df2fd13b56061049b3 |
Introduce "inline" variants of ZIR tags:
* block => block_inline
* repeat => repeat_inline
* break => break_inline
* condbr => condbr_inline
The inline variants perform control flow at compile-time, and they
utilize the return value of `Sema.analyzeBody`.
`analyzeBody` now returns an Index, not a Ref, which is the ZIR index of
a break instruction. This effectively communicates both the intended
break target block as well as the operand, allowing parent blocks to
find out whether they, in turn, should return the break instruction up the
call stack, or accept the operand as the block's result and continue
analyzing instructions in the block.
Additionally:
* removed the deprecated ZIR tag `block_comptime`.
* removed `break_void_node` so that all break instructions use the same Data.
* zir.Code: remove the `root_start` and `root_len` fields. There is now
implied to be a block at index 0 for the root body. This is so that
`break_inline` has something to point at and we no longer need the
special instruction `break_flat`.
* implement source location byteOffset() for .node_offset_if_cond
.node_offset_for_cond is probably redundant and can be deleted.
We don't have `comptime var` supported yet, so this commit adds a test
that at least makes sure the condition is required to be comptime known
for `inline while`.6 files changed, 227 insertions(+), 176 deletions(-)
lib/std/zig/parse.zig+1-4| ... | @@ -59,10 +59,7 @@ pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!Tree { | ... | @@ -59,10 +59,7 @@ pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!Tree { |
| 59 | parser.nodes.appendAssumeCapacity(.{ | 59 | parser.nodes.appendAssumeCapacity(.{ |
| 60 | .tag = .root, | 60 | .tag = .root, |
| 61 | .main_token = 0, | 61 | .main_token = 0, |
| 62 | .data = .{ | 62 | .data = undefined, |
| 63 | .lhs = undefined, | ||
| 64 | .rhs = undefined, | ||
| 65 | }, | ||
| 66 | }); | 63 | }); |
| 67 | const root_members = try parser.parseContainerMembers(); | 64 | const root_members = try parser.parseContainerMembers(); |
| 68 | const root_decls = try root_members.toSpan(&parser); | 65 | const root_decls = try root_members.toSpan(&parser); |
src/Module.zig+58-58| ... | @@ -952,15 +952,11 @@ pub const Scope = struct { | ... | @@ -952,15 +952,11 @@ pub const Scope = struct { |
| 952 | /// initialized, but empty, state. | 952 | /// initialized, but empty, state. |
| 953 | pub fn finish(gz: *GenZir) !zir.Code { | 953 | pub fn finish(gz: *GenZir) !zir.Code { |
| 954 | const gpa = gz.zir_code.gpa; | 954 | const gpa = gz.zir_code.gpa; |
| 955 | const root_start = @intCast(u32, gz.zir_code.extra.items.len); | 955 | try gz.setBlockBody(0); |
| 956 | const root_len = @intCast(u32, gz.instructions.items.len); | ||
| 957 | try gz.zir_code.extra.appendSlice(gpa, gz.instructions.items); | ||
| 958 | return zir.Code{ | 956 | return zir.Code{ |
| 959 | .instructions = gz.zir_code.instructions.toOwnedSlice(), | 957 | .instructions = gz.zir_code.instructions.toOwnedSlice(), |
| 960 | .string_bytes = gz.zir_code.string_bytes.toOwnedSlice(gpa), | 958 | .string_bytes = gz.zir_code.string_bytes.toOwnedSlice(gpa), |
| 961 | .extra = gz.zir_code.extra.toOwnedSlice(gpa), | 959 | .extra = gz.zir_code.extra.toOwnedSlice(gpa), |
| 962 | .root_start = root_start, | ||
| 963 | .root_len = root_len, | ||
| 964 | }; | 960 | }; |
| 965 | } | 961 | } |
| 966 | 962 | ||
| ... | @@ -1224,11 +1220,12 @@ pub const Scope = struct { | ... | @@ -1224,11 +1220,12 @@ pub const Scope = struct { |
| 1224 | 1220 | ||
| 1225 | pub fn addBreak( | 1221 | pub fn addBreak( |
| 1226 | gz: *GenZir, | 1222 | gz: *GenZir, |
| 1223 | tag: zir.Inst.Tag, | ||
| 1227 | break_block: zir.Inst.Index, | 1224 | break_block: zir.Inst.Index, |
| 1228 | operand: zir.Inst.Ref, | 1225 | operand: zir.Inst.Ref, |
| 1229 | ) !zir.Inst.Index { | 1226 | ) !zir.Inst.Index { |
| 1230 | return gz.addAsIndex(.{ | 1227 | return gz.addAsIndex(.{ |
| 1231 | .tag = .@"break", | 1228 | .tag = tag, |
| 1232 | .data = .{ .@"break" = .{ | 1229 | .data = .{ .@"break" = .{ |
| 1233 | .block_inst = break_block, | 1230 | .block_inst = break_block, |
| 1234 | .operand = operand, | 1231 | .operand = operand, |
| ... | @@ -1236,20 +1233,6 @@ pub const Scope = struct { | ... | @@ -1236,20 +1233,6 @@ pub const Scope = struct { |
| 1236 | }); | 1233 | }); |
| 1237 | } | 1234 | } |
| 1238 | 1235 | ||
| 1239 | pub fn addBreakVoid( | ||
| 1240 | gz: *GenZir, | ||
| 1241 | break_block: zir.Inst.Index, | ||
| 1242 | node_index: ast.Node.Index, | ||
| 1243 | ) !zir.Inst.Index { | ||
| 1244 | return gz.addAsIndex(.{ | ||
| 1245 | .tag = .break_void_node, | ||
| 1246 | .data = .{ .break_void_node = .{ | ||
| 1247 | .src_node = gz.zir_code.decl.nodeIndexToRelative(node_index), | ||
| 1248 | .block_inst = break_block, | ||
| 1249 | } }, | ||
| 1250 | }); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | pub fn addBin( | 1236 | pub fn addBin( |
| 1254 | gz: *GenZir, | 1237 | gz: *GenZir, |
| 1255 | tag: zir.Inst.Tag, | 1238 | tag: zir.Inst.Tag, |
| ... | @@ -1323,11 +1306,11 @@ pub const Scope = struct { | ... | @@ -1323,11 +1306,11 @@ pub const Scope = struct { |
| 1323 | 1306 | ||
| 1324 | /// Note that this returns a `zir.Inst.Index` not a ref. | 1307 | /// Note that this returns a `zir.Inst.Index` not a ref. |
| 1325 | /// Leaves the `payload_index` field undefined. | 1308 | /// Leaves the `payload_index` field undefined. |
| 1326 | pub fn addCondBr(gz: *GenZir, node: ast.Node.Index) !zir.Inst.Index { | 1309 | pub fn addCondBr(gz: *GenZir, tag: zir.Inst.Tag, node: ast.Node.Index) !zir.Inst.Index { |
| 1327 | try gz.instructions.ensureCapacity(gz.zir_code.gpa, gz.instructions.items.len + 1); | 1310 | try gz.instructions.ensureCapacity(gz.zir_code.gpa, gz.instructions.items.len + 1); |
| 1328 | const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); | 1311 | const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); |
| 1329 | try gz.zir_code.instructions.append(gz.zir_code.gpa, .{ | 1312 | try gz.zir_code.instructions.append(gz.zir_code.gpa, .{ |
| 1330 | .tag = .condbr, | 1313 | .tag = tag, |
| 1331 | .data = .{ .pl_node = .{ | 1314 | .data = .{ .pl_node = .{ |
| 1332 | .src_node = gz.zir_code.decl.nodeIndexToRelative(node), | 1315 | .src_node = gz.zir_code.decl.nodeIndexToRelative(node), |
| 1333 | .payload_index = undefined, | 1316 | .payload_index = undefined, |
| ... | @@ -1462,6 +1445,24 @@ pub const WipZirCode = struct { | ... | @@ -1462,6 +1445,24 @@ pub const WipZirCode = struct { |
| 1462 | } | 1445 | } |
| 1463 | }; | 1446 | }; |
| 1464 | 1447 | ||
| 1448 | /// Call `deinit` on the result. | ||
| 1449 | fn initAstGen(mod: *Module, decl: *Decl, arena: *Allocator) !WipZirCode { | ||
| 1450 | var wzc: WipZirCode = .{ | ||
| 1451 | .decl = decl, | ||
| 1452 | .arena = arena, | ||
| 1453 | .gpa = mod.gpa, | ||
| 1454 | }; | ||
| 1455 | // Must be a block instruction at index 0 with the root body. | ||
| 1456 | try wzc.instructions.append(mod.gpa, .{ | ||
| 1457 | .tag = .block, | ||
| 1458 | .data = .{ .pl_node = .{ | ||
| 1459 | .src_node = 0, | ||
| 1460 | .payload_index = undefined, | ||
| 1461 | } }, | ||
| 1462 | }); | ||
| 1463 | return wzc; | ||
| 1464 | } | ||
| 1465 | |||
| 1465 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. | 1466 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. |
| 1466 | /// Its memory is managed with the general purpose allocator so that they | 1467 | /// Its memory is managed with the general purpose allocator so that they |
| 1467 | /// can be created and destroyed in response to incremental updates. | 1468 | /// can be created and destroyed in response to incremental updates. |
| ... | @@ -1572,10 +1573,10 @@ pub const SrcLoc = struct { | ... | @@ -1572,10 +1573,10 @@ pub const SrcLoc = struct { |
| 1572 | const token_starts = tree.tokens.items(.start); | 1573 | const token_starts = tree.tokens.items(.start); |
| 1573 | return token_starts[tok_index]; | 1574 | return token_starts[tok_index]; |
| 1574 | }, | 1575 | }, |
| 1575 | .node_abs => |node_index| { | 1576 | .node_abs => |node| { |
| 1576 | const tree = src_loc.container.file_scope.base.tree(); | 1577 | const tree = src_loc.container.file_scope.base.tree(); |
| 1577 | const token_starts = tree.tokens.items(.start); | 1578 | const token_starts = tree.tokens.items(.start); |
| 1578 | const tok_index = tree.firstToken(node_index); | 1579 | const tok_index = tree.firstToken(node); |
| 1579 | return token_starts[tok_index]; | 1580 | return token_starts[tok_index]; |
| 1580 | }, | 1581 | }, |
| 1581 | .byte_offset => |byte_off| { | 1582 | .byte_offset => |byte_off| { |
| ... | @@ -1591,15 +1592,14 @@ pub const SrcLoc = struct { | ... | @@ -1591,15 +1592,14 @@ pub const SrcLoc = struct { |
| 1591 | }, | 1592 | }, |
| 1592 | .node_offset => |node_off| { | 1593 | .node_offset => |node_off| { |
| 1593 | const decl = src_loc.container.decl; | 1594 | const decl = src_loc.container.decl; |
| 1594 | const node_index = decl.relativeToNodeIndex(node_off); | 1595 | const node = decl.relativeToNodeIndex(node_off); |
| 1595 | const tree = decl.container.file_scope.base.tree(); | 1596 | const tree = decl.container.file_scope.base.tree(); |
| 1596 | const main_tokens = tree.nodes.items(.main_token); | 1597 | const main_tokens = tree.nodes.items(.main_token); |
| 1597 | const tok_index = main_tokens[node_index]; | 1598 | const tok_index = main_tokens[node]; |
| 1598 | const token_starts = tree.tokens.items(.start); | 1599 | const token_starts = tree.tokens.items(.start); |
| 1599 | return token_starts[tok_index]; | 1600 | return token_starts[tok_index]; |
| 1600 | }, | 1601 | }, |
| 1601 | .node_offset_var_decl_ty => @panic("TODO"), | 1602 | .node_offset_var_decl_ty => @panic("TODO"), |
| 1602 | .node_offset_for_cond => @panic("TODO"), | ||
| 1603 | .node_offset_builtin_call_arg0 => @panic("TODO"), | 1603 | .node_offset_builtin_call_arg0 => @panic("TODO"), |
| 1604 | .node_offset_builtin_call_arg1 => @panic("TODO"), | 1604 | .node_offset_builtin_call_arg1 => @panic("TODO"), |
| 1605 | .node_offset_builtin_call_argn => unreachable, // Handled specially in `Sema`. | 1605 | .node_offset_builtin_call_argn => unreachable, // Handled specially in `Sema`. |
| ... | @@ -1610,7 +1610,27 @@ pub const SrcLoc = struct { | ... | @@ -1610,7 +1610,27 @@ pub const SrcLoc = struct { |
| 1610 | .node_offset_deref_ptr => @panic("TODO"), | 1610 | .node_offset_deref_ptr => @panic("TODO"), |
| 1611 | .node_offset_asm_source => @panic("TODO"), | 1611 | .node_offset_asm_source => @panic("TODO"), |
| 1612 | .node_offset_asm_ret_ty => @panic("TODO"), | 1612 | .node_offset_asm_ret_ty => @panic("TODO"), |
| 1613 | .node_offset_if_cond => @panic("TODO"), | 1613 | |
| 1614 | .node_offset_for_cond, .node_offset_if_cond => |node_off| { | ||
| 1615 | const decl = src_loc.container.decl; | ||
| 1616 | const node = decl.relativeToNodeIndex(node_off); | ||
| 1617 | const tree = decl.container.file_scope.base.tree(); | ||
| 1618 | const node_tags = tree.nodes.items(.tag); | ||
| 1619 | const cond_expr = switch (node_tags[node]) { | ||
| 1620 | .if_simple => tree.ifSimple(node).ast.cond_expr, | ||
| 1621 | .@"if" => tree.ifFull(node).ast.cond_expr, | ||
| 1622 | .while_simple => tree.whileSimple(node).ast.cond_expr, | ||
| 1623 | .while_cont => tree.whileCont(node).ast.cond_expr, | ||
| 1624 | .@"while" => tree.whileFull(node).ast.cond_expr, | ||
| 1625 | .for_simple => tree.forSimple(node).ast.cond_expr, | ||
| 1626 | .@"for" => tree.forFull(node).ast.cond_expr, | ||
| 1627 | else => unreachable, | ||
| 1628 | }; | ||
| 1629 | const main_tokens = tree.nodes.items(.main_token); | ||
| 1630 | const tok_index = main_tokens[cond_expr]; | ||
| 1631 | const token_starts = tree.tokens.items(.start); | ||
| 1632 | return token_starts[tok_index]; | ||
| 1633 | }, | ||
| 1614 | .node_offset_bin_op => @panic("TODO"), | 1634 | .node_offset_bin_op => @panic("TODO"), |
| 1615 | .node_offset_bin_lhs => @panic("TODO"), | 1635 | .node_offset_bin_lhs => @panic("TODO"), |
| 1616 | .node_offset_bin_rhs => @panic("TODO"), | 1636 | .node_offset_bin_rhs => @panic("TODO"), |
| ... | @@ -2034,11 +2054,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2034,11 +2054,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { |
| 2034 | defer analysis_arena.deinit(); | 2054 | defer analysis_arena.deinit(); |
| 2035 | 2055 | ||
| 2036 | var code: zir.Code = blk: { | 2056 | var code: zir.Code = blk: { |
| 2037 | var wip_zir_code: WipZirCode = .{ | 2057 | var wip_zir_code = try mod.initAstGen(decl, &analysis_arena.allocator); |
| 2038 | .decl = decl, | ||
| 2039 | .arena = &analysis_arena.allocator, | ||
| 2040 | .gpa = mod.gpa, | ||
| 2041 | }; | ||
| 2042 | defer wip_zir_code.deinit(); | 2058 | defer wip_zir_code.deinit(); |
| 2043 | 2059 | ||
| 2044 | var gen_scope: Scope.GenZir = .{ | 2060 | var gen_scope: Scope.GenZir = .{ |
| ... | @@ -2111,11 +2127,7 @@ fn astgenAndSemaFn( | ... | @@ -2111,11 +2127,7 @@ fn astgenAndSemaFn( |
| 2111 | var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); | 2127 | var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| 2112 | defer fn_type_scope_arena.deinit(); | 2128 | defer fn_type_scope_arena.deinit(); |
| 2113 | 2129 | ||
| 2114 | var fn_type_wip_zir_code: WipZirCode = .{ | 2130 | var fn_type_wip_zir_code = try mod.initAstGen(decl, &fn_type_scope_arena.allocator); |
| 2115 | .decl = decl, | ||
| 2116 | .arena = &fn_type_scope_arena.allocator, | ||
| 2117 | .gpa = mod.gpa, | ||
| 2118 | }; | ||
| 2119 | defer fn_type_wip_zir_code.deinit(); | 2131 | defer fn_type_wip_zir_code.deinit(); |
| 2120 | 2132 | ||
| 2121 | var fn_type_scope: Scope.GenZir = .{ | 2133 | var fn_type_scope: Scope.GenZir = .{ |
| ... | @@ -2270,7 +2282,7 @@ fn astgenAndSemaFn( | ... | @@ -2270,7 +2282,7 @@ fn astgenAndSemaFn( |
| 2270 | const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type; | 2282 | const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type; |
| 2271 | break :fn_type try fn_type_scope.addFnType(tag, return_type_inst, param_types); | 2283 | break :fn_type try fn_type_scope.addFnType(tag, return_type_inst, param_types); |
| 2272 | }; | 2284 | }; |
| 2273 | _ = try fn_type_scope.addUnNode(.break_flat, fn_type_inst, 0); | 2285 | _ = try fn_type_scope.addBreak(.break_inline, 0, fn_type_inst); |
| 2274 | 2286 | ||
| 2275 | // We need the memory for the Type to go into the arena for the Decl | 2287 | // We need the memory for the Type to go into the arena for the Decl |
| 2276 | var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); | 2288 | var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| ... | @@ -2348,12 +2360,8 @@ fn astgenAndSemaFn( | ... | @@ -2348,12 +2360,8 @@ fn astgenAndSemaFn( |
| 2348 | 2360 | ||
| 2349 | const fn_zir: zir.Code = blk: { | 2361 | const fn_zir: zir.Code = blk: { |
| 2350 | // We put the ZIR inside the Decl arena. | 2362 | // We put the ZIR inside the Decl arena. |
| 2351 | var wip_zir_code: WipZirCode = .{ | 2363 | var wip_zir_code = try mod.initAstGen(decl, &decl_arena.allocator); |
| 2352 | .decl = decl, | 2364 | wip_zir_code.ref_start_index = @intCast(u32, zir.Inst.Ref.typed_value_map.len + param_count); |
| 2353 | .arena = &decl_arena.allocator, | ||
| 2354 | .gpa = mod.gpa, | ||
| 2355 | .ref_start_index = @intCast(u32, zir.Inst.Ref.typed_value_map.len + param_count), | ||
| 2356 | }; | ||
| 2357 | defer wip_zir_code.deinit(); | 2365 | defer wip_zir_code.deinit(); |
| 2358 | 2366 | ||
| 2359 | var gen_scope: Scope.GenZir = .{ | 2367 | var gen_scope: Scope.GenZir = .{ |
| ... | @@ -2559,11 +2567,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2559,11 +2567,7 @@ fn astgenAndSemaVarDecl( |
| 2559 | var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); | 2567 | var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| 2560 | defer gen_scope_arena.deinit(); | 2568 | defer gen_scope_arena.deinit(); |
| 2561 | 2569 | ||
| 2562 | var wip_zir_code: WipZirCode = .{ | 2570 | var wip_zir_code = try mod.initAstGen(decl, &gen_scope_arena.allocator); |
| 2563 | .decl = decl, | ||
| 2564 | .arena = &gen_scope_arena.allocator, | ||
| 2565 | .gpa = mod.gpa, | ||
| 2566 | }; | ||
| 2567 | defer wip_zir_code.deinit(); | 2571 | defer wip_zir_code.deinit(); |
| 2568 | 2572 | ||
| 2569 | var gen_scope: Scope.GenZir = .{ | 2573 | var gen_scope: Scope.GenZir = .{ |
| ... | @@ -2583,7 +2587,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2583,7 +2587,7 @@ fn astgenAndSemaVarDecl( |
| 2583 | init_result_loc, | 2587 | init_result_loc, |
| 2584 | var_decl.ast.init_node, | 2588 | var_decl.ast.init_node, |
| 2585 | ); | 2589 | ); |
| 2586 | _ = try gen_scope.addUnNode(.break_flat, init_inst, var_decl.ast.init_node); | 2590 | _ = try gen_scope.addBreak(.break_inline, 0, init_inst); |
| 2587 | var code = try gen_scope.finish(); | 2591 | var code = try gen_scope.finish(); |
| 2588 | defer code.deinit(mod.gpa); | 2592 | defer code.deinit(mod.gpa); |
| 2589 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { | 2593 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { |
| ... | @@ -2611,7 +2615,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2611,7 +2615,7 @@ fn astgenAndSemaVarDecl( |
| 2611 | }; | 2615 | }; |
| 2612 | defer block_scope.instructions.deinit(mod.gpa); | 2616 | defer block_scope.instructions.deinit(mod.gpa); |
| 2613 | 2617 | ||
| 2614 | const init_inst_zir_ref = try sema.root(&block_scope); | 2618 | const init_inst_zir_ref = try sema.rootAsRef(&block_scope); |
| 2615 | // The result location guarantees the type coercion. | 2619 | // The result location guarantees the type coercion. |
| 2616 | const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref); | 2620 | const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref); |
| 2617 | // The is_comptime in the Scope.Block guarantees the result is comptime-known. | 2621 | // The is_comptime in the Scope.Block guarantees the result is comptime-known. |
| ... | @@ -2632,11 +2636,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2632,11 +2636,7 @@ fn astgenAndSemaVarDecl( |
| 2632 | var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); | 2636 | var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| 2633 | defer type_scope_arena.deinit(); | 2637 | defer type_scope_arena.deinit(); |
| 2634 | 2638 | ||
| 2635 | var wip_zir_code: WipZirCode = .{ | 2639 | var wip_zir_code = try mod.initAstGen(decl, &type_scope_arena.allocator); |
| 2636 | .decl = decl, | ||
| 2637 | .arena = &type_scope_arena.allocator, | ||
| 2638 | .gpa = mod.gpa, | ||
| 2639 | }; | ||
| 2640 | defer wip_zir_code.deinit(); | 2640 | defer wip_zir_code.deinit(); |
| 2641 | 2641 | ||
| 2642 | var type_scope: Scope.GenZir = .{ | 2642 | var type_scope: Scope.GenZir = .{ |
| ... | @@ -2647,7 +2647,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2647,7 +2647,7 @@ fn astgenAndSemaVarDecl( |
| 2647 | defer type_scope.instructions.deinit(mod.gpa); | 2647 | defer type_scope.instructions.deinit(mod.gpa); |
| 2648 | 2648 | ||
| 2649 | const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node); | 2649 | const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node); |
| 2650 | _ = try type_scope.addUnNode(.break_flat, var_type, 0); | 2650 | _ = try type_scope.addBreak(.break_inline, 0, var_type); |
| 2651 | 2651 | ||
| 2652 | var code = try type_scope.finish(); | 2652 | var code = try type_scope.finish(); |
| 2653 | defer code.deinit(mod.gpa); | 2653 | defer code.deinit(mod.gpa); |
src/Sema.zig+72-45| ... | @@ -60,14 +60,21 @@ const InnerError = Module.InnerError; | ... | @@ -60,14 +60,21 @@ const InnerError = Module.InnerError; |
| 60 | const Decl = Module.Decl; | 60 | const Decl = Module.Decl; |
| 61 | const LazySrcLoc = Module.LazySrcLoc; | 61 | const LazySrcLoc = Module.LazySrcLoc; |
| 62 | 62 | ||
| 63 | pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref { | 63 | pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Index { |
| 64 | const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len]; | 64 | const inst_data = sema.code.instructions.items(.data)[0].pl_node; |
| 65 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | ||
| 66 | const root_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 65 | return sema.analyzeBody(root_block, root_body); | 67 | return sema.analyzeBody(root_block, root_body); |
| 66 | } | 68 | } |
| 67 | 69 | ||
| 68 | /// Assumes that `root_block` ends with `break_flat`. | 70 | pub fn rootAsRef(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref { |
| 71 | const break_inst = try sema.root(root_block); | ||
| 72 | return sema.code.instructions.items(.data)[break_inst].@"break".operand; | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Assumes that `root_block` ends with `break_inline`. | ||
| 69 | pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type { | 76 | pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type { |
| 70 | const zir_inst_ref = try sema.root(root_block); | 77 | const zir_inst_ref = try sema.rootAsRef(root_block); |
| 71 | // Source location is unneeded because resolveConstValue must have already | 78 | // Source location is unneeded because resolveConstValue must have already |
| 72 | // been successfully called when coercing the value to a type, from the | 79 | // been successfully called when coercing the value to a type, from the |
| 73 | // result location. | 80 | // result location. |
| ... | @@ -78,17 +85,22 @@ pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type { | ... | @@ -78,17 +85,22 @@ pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type { |
| 78 | /// return type of `analyzeBody` so that we can tail call them. | 85 | /// return type of `analyzeBody` so that we can tail call them. |
| 79 | /// Only appropriate to return when the instruction is known to be NoReturn | 86 | /// Only appropriate to return when the instruction is known to be NoReturn |
| 80 | /// solely based on the ZIR tag. | 87 | /// solely based on the ZIR tag. |
| 81 | const always_noreturn: InnerError!zir.Inst.Ref = .none; | 88 | const always_noreturn: InnerError!zir.Inst.Index = @as(zir.Inst.Index, undefined); |
| 82 | 89 | ||
| 83 | /// This function is the main loop of `Sema` and it can be used in two different ways: | 90 | /// This function is the main loop of `Sema` and it can be used in two different ways: |
| 84 | /// * The traditional way where there are N breaks out of the block and peer type | 91 | /// * The traditional way where there are N breaks out of the block and peer type |
| 85 | /// resolution is done on the break operands. In this case, the `zir.Inst.Index` | 92 | /// resolution is done on the break operands. In this case, the `zir.Inst.Index` |
| 86 | /// part of the return value will be `undefined`, and callsites should ignore it, | 93 | /// part of the return value will be `undefined`, and callsites should ignore it, |
| 87 | /// finding the block result value via the block scope. | 94 | /// finding the block result value via the block scope. |
| 88 | /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_flat` | 95 | /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline` |
| 89 | /// instruction. In this case, the `zir.Inst.Index` part of the return value will be | 96 | /// instruction. In this case, the `zir.Inst.Index` part of the return value will be |
| 90 | /// the block result value. No block scope needs to be created for this strategy. | 97 | /// the break instruction. This communicates both which block the break applies to, as |
| 91 | pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !zir.Inst.Ref { | 98 | /// well as the operand. No block scope needs to be created for this strategy. |
| 99 | pub fn analyzeBody( | ||
| 100 | sema: *Sema, | ||
| 101 | block: *Scope.Block, | ||
| 102 | body: []const zir.Inst.Index, | ||
| 103 | ) InnerError!zir.Inst.Index { | ||
| 92 | // No tracy calls here, to avoid interfering with the tail call mechanism. | 104 | // No tracy calls here, to avoid interfering with the tail call mechanism. |
| 93 | 105 | ||
| 94 | const map = block.sema.inst_map; | 106 | const map = block.sema.inst_map; |
| ... | @@ -127,8 +139,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -127,8 +139,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 127 | .bitcast => try sema.zirBitcast(block, inst), | 139 | .bitcast => try sema.zirBitcast(block, inst), |
| 128 | .bitcast_ref => try sema.zirBitcastRef(block, inst), | 140 | .bitcast_ref => try sema.zirBitcastRef(block, inst), |
| 129 | .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), | 141 | .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), |
| 130 | .block => try sema.zirBlock(block, inst, false), | 142 | .block => try sema.zirBlock(block, inst), |
| 131 | .block_comptime => try sema.zirBlock(block, inst, true), | ||
| 132 | .bool_not => try sema.zirBoolNot(block, inst), | 143 | .bool_not => try sema.zirBoolNot(block, inst), |
| 133 | .bool_and => try sema.zirBoolOp(block, inst, false), | 144 | .bool_and => try sema.zirBoolOp(block, inst, false), |
| 134 | .bool_or => try sema.zirBoolOp(block, inst, true), | 145 | .bool_or => try sema.zirBoolOp(block, inst, true), |
| ... | @@ -227,8 +238,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -227,8 +238,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 227 | // tail call them here. | 238 | // tail call them here. |
| 228 | .condbr => return sema.zirCondbr(block, inst), | 239 | .condbr => return sema.zirCondbr(block, inst), |
| 229 | .@"break" => return sema.zirBreak(block, inst), | 240 | .@"break" => return sema.zirBreak(block, inst), |
| 230 | .break_void_node => return sema.zirBreakVoidNode(block, inst), | 241 | .break_inline => return inst, |
| 231 | .break_flat => return sema.code.instructions.items(.data)[inst].un_node.operand, | ||
| 232 | .compile_error => return sema.zirCompileError(block, inst), | 242 | .compile_error => return sema.zirCompileError(block, inst), |
| 233 | .ret_coerce => return sema.zirRetTok(block, inst, true), | 243 | .ret_coerce => return sema.zirRetTok(block, inst, true), |
| 234 | .ret_node => return sema.zirRetNode(block, inst), | 244 | .ret_node => return sema.zirRetNode(block, inst), |
| ... | @@ -286,13 +296,43 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -286,13 +296,43 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 286 | continue; | 296 | continue; |
| 287 | }, | 297 | }, |
| 288 | 298 | ||
| 289 | // Special case: send comptime control flow back to the beginning of this block. | 299 | // Special case instructions to handle comptime control flow. |
| 290 | .repeat_inline => { | 300 | .repeat_inline => { |
| 301 | // Send comptime control flow back to the beginning of this block. | ||
| 291 | const src: LazySrcLoc = .{ .node_offset = datas[inst].node }; | 302 | const src: LazySrcLoc = .{ .node_offset = datas[inst].node }; |
| 292 | try sema.emitBackwardBranch(block, src); | 303 | try sema.emitBackwardBranch(block, src); |
| 293 | i = 0; | 304 | i = 0; |
| 294 | continue; | 305 | continue; |
| 295 | }, | 306 | }, |
| 307 | .block_inline => blk: { | ||
| 308 | // Directly analyze the block body without introducing a new block. | ||
| 309 | const inst_data = datas[inst].pl_node; | ||
| 310 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | ||
| 311 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 312 | const break_inst = try sema.analyzeBody(block, inline_body); | ||
| 313 | const break_data = datas[break_inst].@"break"; | ||
| 314 | if (inst == break_data.block_inst) { | ||
| 315 | break :blk try sema.resolveInst(break_data.operand); | ||
| 316 | } else { | ||
| 317 | return break_inst; | ||
| 318 | } | ||
| 319 | }, | ||
| 320 | .condbr_inline => blk: { | ||
| 321 | const inst_data = datas[inst].pl_node; | ||
| 322 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; | ||
| 323 | const extra = sema.code.extraData(zir.Inst.CondBr, inst_data.payload_index); | ||
| 324 | const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; | ||
| 325 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | ||
| 326 | const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); | ||
| 327 | const inline_body = if (cond.val.toBool()) then_body else else_body; | ||
| 328 | const break_inst = try sema.analyzeBody(block, inline_body); | ||
| 329 | const break_data = datas[break_inst].@"break"; | ||
| 330 | if (inst == break_data.block_inst) { | ||
| 331 | break :blk try sema.resolveInst(break_data.operand); | ||
| 332 | } else { | ||
| 333 | return break_inst; | ||
| 334 | } | ||
| 335 | }, | ||
| 296 | }; | 336 | }; |
| 297 | if (map[inst].ty.isNoReturn()) | 337 | if (map[inst].ty.isNoReturn()) |
| 298 | return always_noreturn; | 338 | return always_noreturn; |
| ... | @@ -745,7 +785,7 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In | ... | @@ -745,7 +785,7 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In |
| 745 | return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int); | 785 | return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int); |
| 746 | } | 786 | } |
| 747 | 787 | ||
| 748 | fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | 788 | fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { |
| 749 | const tracy = trace(@src()); | 789 | const tracy = trace(@src()); |
| 750 | defer tracy.end(); | 790 | defer tracy.end(); |
| 751 | 791 | ||
| ... | @@ -783,7 +823,7 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -783,7 +823,7 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 783 | } | 823 | } |
| 784 | } | 824 | } |
| 785 | 825 | ||
| 786 | fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | 826 | fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { |
| 787 | const tracy = trace(@src()); | 827 | const tracy = trace(@src()); |
| 788 | defer tracy.end(); | 828 | defer tracy.end(); |
| 789 | 829 | ||
| ... | @@ -854,12 +894,7 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -854,12 +894,7 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 854 | return sema.analyzeBlockBody(parent_block, &child_block, merges); | 894 | return sema.analyzeBlockBody(parent_block, &child_block, merges); |
| 855 | } | 895 | } |
| 856 | 896 | ||
| 857 | fn zirBlock( | 897 | fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { |
| 858 | sema: *Sema, | ||
| 859 | parent_block: *Scope.Block, | ||
| 860 | inst: zir.Inst.Index, | ||
| 861 | is_comptime: bool, | ||
| 862 | ) InnerError!*Inst { | ||
| 863 | const tracy = trace(@src()); | 898 | const tracy = trace(@src()); |
| 864 | defer tracy.end(); | 899 | defer tracy.end(); |
| 865 | 900 | ||
| ... | @@ -896,7 +931,7 @@ fn zirBlock( | ... | @@ -896,7 +931,7 @@ fn zirBlock( |
| 896 | }, | 931 | }, |
| 897 | }), | 932 | }), |
| 898 | .inlining = parent_block.inlining, | 933 | .inlining = parent_block.inlining, |
| 899 | .is_comptime = is_comptime or parent_block.is_comptime, | 934 | .is_comptime = parent_block.is_comptime, |
| 900 | }; | 935 | }; |
| 901 | const merges = &child_block.label.?.merges; | 936 | const merges = &child_block.label.?.merges; |
| 902 | 937 | ||
| ... | @@ -1000,7 +1035,7 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1000,7 +1035,7 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1000 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); | 1035 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); |
| 1001 | } | 1036 | } |
| 1002 | 1037 | ||
| 1003 | fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | 1038 | fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { |
| 1004 | const tracy = trace(@src()); | 1039 | const tracy = trace(@src()); |
| 1005 | defer tracy.end(); | 1040 | defer tracy.end(); |
| 1006 | 1041 | ||
| ... | @@ -1009,22 +1044,13 @@ fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!z | ... | @@ -1009,22 +1044,13 @@ fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!z |
| 1009 | return sema.analyzeBreak(block, sema.src, inst_data.block_inst, operand); | 1044 | return sema.analyzeBreak(block, sema.src, inst_data.block_inst, operand); |
| 1010 | } | 1045 | } |
| 1011 | 1046 | ||
| 1012 | fn zirBreakVoidNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | ||
| 1013 | const tracy = trace(@src()); | ||
| 1014 | defer tracy.end(); | ||
| 1015 | |||
| 1016 | const inst_data = sema.code.instructions.items(.data)[inst].break_void_node; | ||
| 1017 | const void_inst = try sema.mod.constVoid(sema.arena, .unneeded); | ||
| 1018 | return sema.analyzeBreak(block, inst_data.src(), inst_data.block_inst, void_inst); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | fn analyzeBreak( | 1047 | fn analyzeBreak( |
| 1022 | sema: *Sema, | 1048 | sema: *Sema, |
| 1023 | start_block: *Scope.Block, | 1049 | start_block: *Scope.Block, |
| 1024 | src: LazySrcLoc, | 1050 | src: LazySrcLoc, |
| 1025 | zir_block: zir.Inst.Index, | 1051 | zir_block: zir.Inst.Index, |
| 1026 | operand: *Inst, | 1052 | operand: *Inst, |
| 1027 | ) InnerError!zir.Inst.Ref { | 1053 | ) InnerError!zir.Inst.Index { |
| 1028 | var block = start_block; | 1054 | var block = start_block; |
| 1029 | while (true) { | 1055 | while (true) { |
| 1030 | if (block.label) |*label| { | 1056 | if (block.label) |*label| { |
| ... | @@ -2844,7 +2870,8 @@ fn zirBoolBr( | ... | @@ -2844,7 +2870,8 @@ fn zirBoolBr( |
| 2844 | const tracy = trace(@src()); | 2870 | const tracy = trace(@src()); |
| 2845 | defer tracy.end(); | 2871 | defer tracy.end(); |
| 2846 | 2872 | ||
| 2847 | const inst_data = sema.code.instructions.items(.data)[inst].bool_br; | 2873 | const datas = sema.code.instructions.items(.data); |
| 2874 | const inst_data = datas[inst].bool_br; | ||
| 2848 | const src: LazySrcLoc = .unneeded; | 2875 | const src: LazySrcLoc = .unneeded; |
| 2849 | const lhs = try sema.resolveInst(inst_data.lhs); | 2876 | const lhs = try sema.resolveInst(inst_data.lhs); |
| 2850 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 2877 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); |
| ... | @@ -2856,9 +2883,9 @@ fn zirBoolBr( | ... | @@ -2856,9 +2883,9 @@ fn zirBoolBr( |
| 2856 | } | 2883 | } |
| 2857 | // comptime-known left-hand side. No need for a block here; the result | 2884 | // comptime-known left-hand side. No need for a block here; the result |
| 2858 | // is simply the rhs expression. Here we rely on there only being 1 | 2885 | // is simply the rhs expression. Here we rely on there only being 1 |
| 2859 | // break instruction (`break_flat`). | 2886 | // break instruction (`break_inline`). |
| 2860 | const zir_inst_ref = try sema.analyzeBody(parent_block, body); | 2887 | const break_inst = try sema.analyzeBody(parent_block, body); |
| 2861 | return sema.resolveInst(zir_inst_ref); | 2888 | return sema.resolveInst(datas[break_inst].@"break".operand); |
| 2862 | } | 2889 | } |
| 2863 | 2890 | ||
| 2864 | const block_inst = try sema.arena.create(Inst.Block); | 2891 | const block_inst = try sema.arena.create(Inst.Block); |
| ... | @@ -2889,8 +2916,8 @@ fn zirBoolBr( | ... | @@ -2889,8 +2916,8 @@ fn zirBoolBr( |
| 2889 | }); | 2916 | }); |
| 2890 | _ = try lhs_block.addBr(src, block_inst, lhs_result); | 2917 | _ = try lhs_block.addBr(src, block_inst, lhs_result); |
| 2891 | 2918 | ||
| 2892 | const rhs_result_zir_ref = try sema.analyzeBody(rhs_block, body); | 2919 | const rhs_break_inst = try sema.analyzeBody(rhs_block, body); |
| 2893 | const rhs_result = try sema.resolveInst(rhs_result_zir_ref); | 2920 | const rhs_result = try sema.resolveInst(datas[rhs_break_inst].@"break".operand); |
| 2894 | _ = try rhs_block.addBr(src, block_inst, rhs_result); | 2921 | _ = try rhs_block.addBr(src, block_inst, rhs_result); |
| 2895 | 2922 | ||
| 2896 | const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) }; | 2923 | const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) }; |
| ... | @@ -2959,7 +2986,7 @@ fn zirCondbr( | ... | @@ -2959,7 +2986,7 @@ fn zirCondbr( |
| 2959 | sema: *Sema, | 2986 | sema: *Sema, |
| 2960 | parent_block: *Scope.Block, | 2987 | parent_block: *Scope.Block, |
| 2961 | inst: zir.Inst.Index, | 2988 | inst: zir.Inst.Index, |
| 2962 | ) InnerError!zir.Inst.Ref { | 2989 | ) InnerError!zir.Inst.Index { |
| 2963 | const tracy = trace(@src()); | 2990 | const tracy = trace(@src()); |
| 2964 | defer tracy.end(); | 2991 | defer tracy.end(); |
| 2965 | 2992 | ||
| ... | @@ -3008,7 +3035,7 @@ fn zirCondbr( | ... | @@ -3008,7 +3035,7 @@ fn zirCondbr( |
| 3008 | return always_noreturn; | 3035 | return always_noreturn; |
| 3009 | } | 3036 | } |
| 3010 | 3037 | ||
| 3011 | fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | 3038 | fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { |
| 3012 | const tracy = trace(@src()); | 3039 | const tracy = trace(@src()); |
| 3013 | defer tracy.end(); | 3040 | defer tracy.end(); |
| 3014 | 3041 | ||
| ... | @@ -3030,7 +3057,7 @@ fn zirRetTok( | ... | @@ -3030,7 +3057,7 @@ fn zirRetTok( |
| 3030 | block: *Scope.Block, | 3057 | block: *Scope.Block, |
| 3031 | inst: zir.Inst.Index, | 3058 | inst: zir.Inst.Index, |
| 3032 | need_coercion: bool, | 3059 | need_coercion: bool, |
| 3033 | ) InnerError!zir.Inst.Ref { | 3060 | ) InnerError!zir.Inst.Index { |
| 3034 | const tracy = trace(@src()); | 3061 | const tracy = trace(@src()); |
| 3035 | defer tracy.end(); | 3062 | defer tracy.end(); |
| 3036 | 3063 | ||
| ... | @@ -3041,7 +3068,7 @@ fn zirRetTok( | ... | @@ -3041,7 +3068,7 @@ fn zirRetTok( |
| 3041 | return sema.analyzeRet(block, operand, src, need_coercion); | 3068 | return sema.analyzeRet(block, operand, src, need_coercion); |
| 3042 | } | 3069 | } |
| 3043 | 3070 | ||
| 3044 | fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | 3071 | fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { |
| 3045 | const tracy = trace(@src()); | 3072 | const tracy = trace(@src()); |
| 3046 | defer tracy.end(); | 3073 | defer tracy.end(); |
| 3047 | 3074 | ||
| ... | @@ -3058,7 +3085,7 @@ fn analyzeRet( | ... | @@ -3058,7 +3085,7 @@ fn analyzeRet( |
| 3058 | operand: *Inst, | 3085 | operand: *Inst, |
| 3059 | src: LazySrcLoc, | 3086 | src: LazySrcLoc, |
| 3060 | need_coercion: bool, | 3087 | need_coercion: bool, |
| 3061 | ) InnerError!zir.Inst.Ref { | 3088 | ) InnerError!zir.Inst.Index { |
| 3062 | if (block.inlining) |inlining| { | 3089 | if (block.inlining) |inlining| { |
| 3063 | // We are inlining a function call; rewrite the `ret` as a `break`. | 3090 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 3064 | try inlining.merges.results.append(sema.gpa, operand); | 3091 | try inlining.merges.results.append(sema.gpa, operand); |
| ... | @@ -3244,7 +3271,7 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: | ... | @@ -3244,7 +3271,7 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: |
| 3244 | try parent_block.instructions.append(sema.gpa, &block_inst.base); | 3271 | try parent_block.instructions.append(sema.gpa, &block_inst.base); |
| 3245 | } | 3272 | } |
| 3246 | 3273 | ||
| 3247 | fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !zir.Inst.Ref { | 3274 | fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !zir.Inst.Index { |
| 3248 | // TODO Once we have a panic function to call, call it here instead of breakpoint. | 3275 | // TODO Once we have a panic function to call, call it here instead of breakpoint. |
| 3249 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); | 3276 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); |
| 3250 | _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach); | 3277 | _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach); |
src/astgen.zig+27-20| ... | @@ -699,7 +699,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro | ... | @@ -699,7 +699,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro |
| 699 | }; | 699 | }; |
| 700 | 700 | ||
| 701 | if (rhs == 0) { | 701 | if (rhs == 0) { |
| 702 | _ = try parent_gz.addBreakVoid(block_inst, node); | 702 | _ = try parent_gz.addBreak(.@"break", block_inst, .void_value); |
| 703 | return zir.Inst.Ref.unreachable_value; | 703 | return zir.Inst.Ref.unreachable_value; |
| 704 | } | 704 | } |
| 705 | block_gz.break_count += 1; | 705 | block_gz.break_count += 1; |
| ... | @@ -707,7 +707,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro | ... | @@ -707,7 +707,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro |
| 707 | const operand = try expr(mod, parent_scope, block_gz.break_result_loc, rhs); | 707 | const operand = try expr(mod, parent_scope, block_gz.break_result_loc, rhs); |
| 708 | const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count; | 708 | const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count; |
| 709 | 709 | ||
| 710 | const br = try parent_gz.addBreak(block_inst, operand); | 710 | const br = try parent_gz.addBreak(.@"break", block_inst, operand); |
| 711 | 711 | ||
| 712 | if (block_gz.break_result_loc == .block_ptr) { | 712 | if (block_gz.break_result_loc == .block_ptr) { |
| 713 | try block_gz.labeled_breaks.append(mod.gpa, br); | 713 | try block_gz.labeled_breaks.append(mod.gpa, br); |
| ... | @@ -860,7 +860,7 @@ fn labeledBlockExpr( | ... | @@ -860,7 +860,7 @@ fn labeledBlockExpr( |
| 860 | const tracy = trace(@src()); | 860 | const tracy = trace(@src()); |
| 861 | defer tracy.end(); | 861 | defer tracy.end(); |
| 862 | 862 | ||
| 863 | assert(zir_tag == .block or zir_tag == .block_comptime); | 863 | assert(zir_tag == .block); |
| 864 | 864 | ||
| 865 | const tree = parent_scope.tree(); | 865 | const tree = parent_scope.tree(); |
| 866 | const main_tokens = tree.nodes.items(.main_token); | 866 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -911,8 +911,6 @@ fn labeledBlockExpr( | ... | @@ -911,8 +911,6 @@ fn labeledBlockExpr( |
| 911 | for (block_scope.labeled_breaks.items) |br| { | 911 | for (block_scope.labeled_breaks.items) |br| { |
| 912 | zir_datas[br].@"break".operand = .void_value; | 912 | zir_datas[br].@"break".operand = .void_value; |
| 913 | } | 913 | } |
| 914 | // TODO technically not needed since we changed the tag to break_void but | ||
| 915 | // would be better still to elide the ones that are in this list. | ||
| 916 | try block_scope.setBlockBody(block_inst); | 914 | try block_scope.setBlockBody(block_inst); |
| 917 | 915 | ||
| 918 | return gz.zir_code.indexToRef(block_inst); | 916 | return gz.zir_code.indexToRef(block_inst); |
| ... | @@ -1027,7 +1025,7 @@ fn blockExprStmts( | ... | @@ -1027,7 +1025,7 @@ fn blockExprStmts( |
| 1027 | .bitcast_result_ptr, | 1025 | .bitcast_result_ptr, |
| 1028 | .bit_or, | 1026 | .bit_or, |
| 1029 | .block, | 1027 | .block, |
| 1030 | .block_comptime, | 1028 | .block_inline, |
| 1031 | .loop, | 1029 | .loop, |
| 1032 | .bool_br_and, | 1030 | .bool_br_and, |
| 1033 | .bool_br_or, | 1031 | .bool_br_or, |
| ... | @@ -1122,9 +1120,9 @@ fn blockExprStmts( | ... | @@ -1122,9 +1120,9 @@ fn blockExprStmts( |
| 1122 | .compile_log, | 1120 | .compile_log, |
| 1123 | .ensure_err_payload_void, | 1121 | .ensure_err_payload_void, |
| 1124 | .@"break", | 1122 | .@"break", |
| 1125 | .break_void_node, | 1123 | .break_inline, |
| 1126 | .break_flat, | ||
| 1127 | .condbr, | 1124 | .condbr, |
| 1125 | .condbr_inline, | ||
| 1128 | .compile_error, | 1126 | .compile_error, |
| 1129 | .ret_node, | 1127 | .ret_node, |
| 1130 | .ret_tok, | 1128 | .ret_tok, |
| ... | @@ -1663,7 +1661,7 @@ fn orelseCatchExpr( | ... | @@ -1663,7 +1661,7 @@ fn orelseCatchExpr( |
| 1663 | }; | 1661 | }; |
| 1664 | const operand = try expr(mod, &block_scope.base, operand_rl, lhs); | 1662 | const operand = try expr(mod, &block_scope.base, operand_rl, lhs); |
| 1665 | const cond = try block_scope.addUnNode(cond_op, operand, node); | 1663 | const cond = try block_scope.addUnNode(cond_op, operand, node); |
| 1666 | const condbr = try block_scope.addCondBr(node); | 1664 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 1667 | 1665 | ||
| 1668 | const block = try parent_gz.addBlock(.block, node); | 1666 | const block = try parent_gz.addBlock(.block, node); |
| 1669 | try parent_gz.instructions.append(mod.gpa, block); | 1667 | try parent_gz.instructions.append(mod.gpa, block); |
| ... | @@ -1731,6 +1729,7 @@ fn orelseCatchExpr( | ... | @@ -1731,6 +1729,7 @@ fn orelseCatchExpr( |
| 1731 | else_result, | 1729 | else_result, |
| 1732 | block, | 1730 | block, |
| 1733 | block, | 1731 | block, |
| 1732 | .@"break", | ||
| 1734 | ); | 1733 | ); |
| 1735 | } | 1734 | } |
| 1736 | 1735 | ||
| ... | @@ -1750,6 +1749,7 @@ fn finishThenElseBlock( | ... | @@ -1750,6 +1749,7 @@ fn finishThenElseBlock( |
| 1750 | else_result: zir.Inst.Ref, | 1749 | else_result: zir.Inst.Ref, |
| 1751 | main_block: zir.Inst.Index, | 1750 | main_block: zir.Inst.Index, |
| 1752 | then_break_block: zir.Inst.Index, | 1751 | then_break_block: zir.Inst.Index, |
| 1752 | break_tag: zir.Inst.Tag, | ||
| 1753 | ) InnerError!zir.Inst.Ref { | 1753 | ) InnerError!zir.Inst.Ref { |
| 1754 | // We now have enough information to decide whether the result instruction should | 1754 | // We now have enough information to decide whether the result instruction should |
| 1755 | // be communicated via result location pointer or break instructions. | 1755 | // be communicated via result location pointer or break instructions. |
| ... | @@ -1758,11 +1758,11 @@ fn finishThenElseBlock( | ... | @@ -1758,11 +1758,11 @@ fn finishThenElseBlock( |
| 1758 | switch (strat.tag) { | 1758 | switch (strat.tag) { |
| 1759 | .break_void => { | 1759 | .break_void => { |
| 1760 | if (!wzc.refIsNoReturn(then_result)) { | 1760 | if (!wzc.refIsNoReturn(then_result)) { |
| 1761 | _ = try then_scope.addBreakVoid(then_break_block, then_src); | 1761 | _ = try then_scope.addBreak(break_tag, then_break_block, .void_value); |
| 1762 | } | 1762 | } |
| 1763 | const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false; | 1763 | const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false; |
| 1764 | if (!elide_else) { | 1764 | if (!elide_else) { |
| 1765 | _ = try else_scope.addBreakVoid(main_block, else_src); | 1765 | _ = try else_scope.addBreak(break_tag, main_block, .void_value); |
| 1766 | } | 1766 | } |
| 1767 | assert(!strat.elide_store_to_block_ptr_instructions); | 1767 | assert(!strat.elide_store_to_block_ptr_instructions); |
| 1768 | try setCondBrPayload(condbr, cond, then_scope, else_scope); | 1768 | try setCondBrPayload(condbr, cond, then_scope, else_scope); |
| ... | @@ -1770,14 +1770,14 @@ fn finishThenElseBlock( | ... | @@ -1770,14 +1770,14 @@ fn finishThenElseBlock( |
| 1770 | }, | 1770 | }, |
| 1771 | .break_operand => { | 1771 | .break_operand => { |
| 1772 | if (!wzc.refIsNoReturn(then_result)) { | 1772 | if (!wzc.refIsNoReturn(then_result)) { |
| 1773 | _ = try then_scope.addBreak(then_break_block, then_result); | 1773 | _ = try then_scope.addBreak(break_tag, then_break_block, then_result); |
| 1774 | } | 1774 | } |
| 1775 | if (else_result != .none) { | 1775 | if (else_result != .none) { |
| 1776 | if (!wzc.refIsNoReturn(else_result)) { | 1776 | if (!wzc.refIsNoReturn(else_result)) { |
| 1777 | _ = try else_scope.addBreak(main_block, else_result); | 1777 | _ = try else_scope.addBreak(break_tag, main_block, else_result); |
| 1778 | } | 1778 | } |
| 1779 | } else { | 1779 | } else { |
| 1780 | _ = try else_scope.addBreakVoid(main_block, else_src); | 1780 | _ = try else_scope.addBreak(break_tag, main_block, .void_value); |
| 1781 | } | 1781 | } |
| 1782 | if (strat.elide_store_to_block_ptr_instructions) { | 1782 | if (strat.elide_store_to_block_ptr_instructions) { |
| 1783 | try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope); | 1783 | try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope); |
| ... | @@ -1944,7 +1944,7 @@ fn boolBinOp( | ... | @@ -1944,7 +1944,7 @@ fn boolBinOp( |
| 1944 | }; | 1944 | }; |
| 1945 | defer rhs_scope.instructions.deinit(mod.gpa); | 1945 | defer rhs_scope.instructions.deinit(mod.gpa); |
| 1946 | const rhs = try expr(mod, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs); | 1946 | const rhs = try expr(mod, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs); |
| 1947 | _ = try rhs_scope.addUnNode(.break_flat, rhs, node); | 1947 | _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); |
| 1948 | try rhs_scope.setBoolBrBody(bool_br); | 1948 | try rhs_scope.setBoolBrBody(bool_br); |
| 1949 | 1949 | ||
| 1950 | const block_ref = gz.zir_code.indexToRef(bool_br); | 1950 | const block_ref = gz.zir_code.indexToRef(bool_br); |
| ... | @@ -1979,7 +1979,7 @@ fn ifExpr( | ... | @@ -1979,7 +1979,7 @@ fn ifExpr( |
| 1979 | } | 1979 | } |
| 1980 | }; | 1980 | }; |
| 1981 | 1981 | ||
| 1982 | const condbr = try block_scope.addCondBr(node); | 1982 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 1983 | 1983 | ||
| 1984 | const block = try parent_gz.addBlock(.block, node); | 1984 | const block = try parent_gz.addBlock(.block, node); |
| 1985 | try parent_gz.instructions.append(mod.gpa, block); | 1985 | try parent_gz.instructions.append(mod.gpa, block); |
| ... | @@ -2042,6 +2042,7 @@ fn ifExpr( | ... | @@ -2042,6 +2042,7 @@ fn ifExpr( |
| 2042 | else_info.result, | 2042 | else_info.result, |
| 2043 | block, | 2043 | block, |
| 2044 | block, | 2044 | block, |
| 2045 | .@"break", | ||
| 2045 | ); | 2046 | ); |
| 2046 | } | 2047 | } |
| 2047 | 2048 | ||
| ... | @@ -2108,7 +2109,9 @@ fn whileExpr( | ... | @@ -2108,7 +2109,9 @@ fn whileExpr( |
| 2108 | try checkLabelRedefinition(mod, scope, label_token); | 2109 | try checkLabelRedefinition(mod, scope, label_token); |
| 2109 | } | 2110 | } |
| 2110 | const parent_gz = scope.getGenZir(); | 2111 | const parent_gz = scope.getGenZir(); |
| 2111 | const loop_block = try parent_gz.addBlock(.loop, node); | 2112 | const is_inline = while_full.inline_token != null; |
| 2113 | const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop; | ||
| 2114 | const loop_block = try parent_gz.addBlock(loop_tag, node); | ||
| 2112 | try parent_gz.instructions.append(mod.gpa, loop_block); | 2115 | try parent_gz.instructions.append(mod.gpa, loop_block); |
| 2113 | 2116 | ||
| 2114 | var loop_scope: Scope.GenZir = .{ | 2117 | var loop_scope: Scope.GenZir = .{ |
| ... | @@ -2140,8 +2143,10 @@ fn whileExpr( | ... | @@ -2140,8 +2143,10 @@ fn whileExpr( |
| 2140 | } | 2143 | } |
| 2141 | }; | 2144 | }; |
| 2142 | 2145 | ||
| 2143 | const condbr = try continue_scope.addCondBr(node); | 2146 | const condbr_tag: zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; |
| 2144 | const cond_block = try loop_scope.addBlock(.block, node); | 2147 | const condbr = try continue_scope.addCondBr(condbr_tag, node); |
| 2148 | const block_tag: zir.Inst.Tag = if (is_inline) .block_inline else .block; | ||
| 2149 | const cond_block = try loop_scope.addBlock(block_tag, node); | ||
| 2145 | try loop_scope.instructions.append(mod.gpa, cond_block); | 2150 | try loop_scope.instructions.append(mod.gpa, cond_block); |
| 2146 | try continue_scope.setBlockBody(cond_block); | 2151 | try continue_scope.setBlockBody(cond_block); |
| 2147 | 2152 | ||
| ... | @@ -2152,7 +2157,6 @@ fn whileExpr( | ... | @@ -2152,7 +2157,6 @@ fn whileExpr( |
| 2152 | if (while_full.ast.cont_expr != 0) { | 2157 | if (while_full.ast.cont_expr != 0) { |
| 2153 | _ = try expr(mod, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr); | 2158 | _ = try expr(mod, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr); |
| 2154 | } | 2159 | } |
| 2155 | const is_inline = while_full.inline_token != null; | ||
| 2156 | const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | 2160 | const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; |
| 2157 | _ = try loop_scope.addNode(repeat_tag, node); | 2161 | _ = try loop_scope.addNode(repeat_tag, node); |
| 2158 | 2162 | ||
| ... | @@ -2208,6 +2212,7 @@ fn whileExpr( | ... | @@ -2208,6 +2212,7 @@ fn whileExpr( |
| 2208 | return mod.failTok(scope, some.token, "unused while loop label", .{}); | 2212 | return mod.failTok(scope, some.token, "unused while loop label", .{}); |
| 2209 | } | 2213 | } |
| 2210 | } | 2214 | } |
| 2215 | const break_tag: zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | ||
| 2211 | return finishThenElseBlock( | 2216 | return finishThenElseBlock( |
| 2212 | mod, | 2217 | mod, |
| 2213 | scope, | 2218 | scope, |
| ... | @@ -2224,6 +2229,7 @@ fn whileExpr( | ... | @@ -2224,6 +2229,7 @@ fn whileExpr( |
| 2224 | else_info.result, | 2229 | else_info.result, |
| 2225 | loop_block, | 2230 | loop_block, |
| 2226 | cond_block, | 2231 | cond_block, |
| 2232 | break_tag, | ||
| 2227 | ); | 2233 | ); |
| 2228 | } | 2234 | } |
| 2229 | 2235 | ||
| ... | @@ -2424,6 +2430,7 @@ fn forExpr( | ... | @@ -2424,6 +2430,7 @@ fn forExpr( |
| 2424 | else_info.result, | 2430 | else_info.result, |
| 2425 | for_block, | 2431 | for_block, |
| 2426 | cond_block, | 2432 | cond_block, |
| 2433 | .@"break", | ||
| 2427 | ); | 2434 | ); |
| 2428 | } | 2435 | } |
| 2429 | 2436 |
src/zir.zig+32-49| ... | @@ -26,6 +26,8 @@ const LazySrcLoc = Module.LazySrcLoc; | ... | @@ -26,6 +26,8 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 26 | /// handled by the codegen backend, and errors reported there. However for now, | 26 | /// handled by the codegen backend, and errors reported there. However for now, |
| 27 | /// inline assembly is not an exception. | 27 | /// inline assembly is not an exception. |
| 28 | pub const Code = struct { | 28 | pub const Code = struct { |
| 29 | /// There is always implicitly a `block` instruction at index 0. | ||
| 30 | /// This is so that `break_inline` can break from the root block. | ||
| 29 | instructions: std.MultiArrayList(Inst).Slice, | 31 | instructions: std.MultiArrayList(Inst).Slice, |
| 30 | /// In order to store references to strings in fewer bytes, we copy all | 32 | /// In order to store references to strings in fewer bytes, we copy all |
| 31 | /// string bytes into here. String bytes can be null. It is up to whomever | 33 | /// string bytes into here. String bytes can be null. It is up to whomever |
| ... | @@ -35,11 +37,6 @@ pub const Code = struct { | ... | @@ -35,11 +37,6 @@ pub const Code = struct { |
| 35 | string_bytes: []u8, | 37 | string_bytes: []u8, |
| 36 | /// The meaning of this data is determined by `Inst.Tag` value. | 38 | /// The meaning of this data is determined by `Inst.Tag` value. |
| 37 | extra: []u32, | 39 | extra: []u32, |
| 38 | /// First ZIR instruction in this `Code`. | ||
| 39 | /// `extra` at this index contains a `Ref` for every root member. | ||
| 40 | root_start: u32, | ||
| 41 | /// Number of ZIR instructions in the implicit root block of the `Code`. | ||
| 42 | root_len: u32, | ||
| 43 | 40 | ||
| 44 | /// Returns the requested data, as well as the new index which is at the start of the | 41 | /// Returns the requested data, as well as the new index which is at the start of the |
| 45 | /// trailers for the object. | 42 | /// trailers for the object. |
| ... | @@ -98,17 +95,14 @@ pub const Code = struct { | ... | @@ -98,17 +95,14 @@ pub const Code = struct { |
| 98 | .arena = &arena.allocator, | 95 | .arena = &arena.allocator, |
| 99 | .scope = scope, | 96 | .scope = scope, |
| 100 | .code = code, | 97 | .code = code, |
| 101 | .indent = 2, | 98 | .indent = 0, |
| 102 | .param_count = param_count, | 99 | .param_count = param_count, |
| 103 | }; | 100 | }; |
| 104 | 101 | ||
| 105 | const decl_name = scope.srcDecl().?.name; | 102 | const decl_name = scope.srcDecl().?.name; |
| 106 | const stderr = std.io.getStdErr().writer(); | 103 | const stderr = std.io.getStdErr().writer(); |
| 107 | try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name }); | 104 | try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name }); |
| 108 | 105 | try writer.writeInstToStream(stderr, 0); | |
| 109 | const root_body = code.extra[code.root_start..][0..code.root_len]; | ||
| 110 | try writer.writeBody(stderr, root_body); | ||
| 111 | |||
| 112 | try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name }); | 106 | try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name }); |
| 113 | } | 107 | } |
| 114 | }; | 108 | }; |
| ... | @@ -189,8 +183,11 @@ pub const Inst = struct { | ... | @@ -189,8 +183,11 @@ pub const Inst = struct { |
| 189 | /// A labeled block of code, which can return a value. | 183 | /// A labeled block of code, which can return a value. |
| 190 | /// Uses the `pl_node` union field. Payload is `Block`. | 184 | /// Uses the `pl_node` union field. Payload is `Block`. |
| 191 | block, | 185 | block, |
| 192 | /// Same as `block` but additionally makes the inner instructions execute at comptime. | 186 | /// A list of instructions which are analyzed in the parent context, without |
| 193 | block_comptime, | 187 | /// generating a runtime block. Must terminate with an "inline" variant of |
| 188 | /// a noreturn instruction. | ||
| 189 | /// Uses the `pl_node` union field. Payload is `Block`. | ||
| 190 | block_inline, | ||
| 194 | /// Boolean AND. See also `bit_and`. | 191 | /// Boolean AND. See also `bit_and`. |
| 195 | /// Uses the `pl_node` union field. Payload is `Bin`. | 192 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 196 | bool_and, | 193 | bool_and, |
| ... | @@ -212,16 +209,12 @@ pub const Inst = struct { | ... | @@ -212,16 +209,12 @@ pub const Inst = struct { |
| 212 | /// Uses the `break` union field. | 209 | /// Uses the `break` union field. |
| 213 | /// Uses the source information from previous instruction. | 210 | /// Uses the source information from previous instruction. |
| 214 | @"break", | 211 | @"break", |
| 215 | /// Same as `break` but has source information in the form of an AST node, and | 212 | /// Return a value from a block. This instruction is used as the terminator |
| 216 | /// the operand is assumed to be the void value. | 213 | /// of a `block_inline`. It allows using the return value from `Sema.analyzeBody`. |
| 217 | /// Uses the `break_void_node` union field. | 214 | /// This instruction may also be used when it is known that there is only one |
| 218 | break_void_node, | 215 | /// break instruction in a block, and the target block is the parent. |
| 219 | /// Return a value from a block. This is a special form that is only valid | 216 | /// Uses the `break` union field. |
| 220 | /// when there is exactly 1 break from a block (this one). This instruction | 217 | break_inline, |
| 221 | /// allows using the return value from `Sema.analyzeBody`. The block is | ||
| 222 | /// assumed to be the direct parent of this instruction. | ||
| 223 | /// Uses the `un_node` union field. The AST node is unused. | ||
| 224 | break_flat, | ||
| 225 | /// Uses the `node` union field. | 218 | /// Uses the `node` union field. |
| 226 | breakpoint, | 219 | breakpoint, |
| 227 | /// Function call with modifier `.auto`. | 220 | /// Function call with modifier `.auto`. |
| ... | @@ -270,7 +263,11 @@ pub const Inst = struct { | ... | @@ -270,7 +263,11 @@ pub const Inst = struct { |
| 270 | /// Uses the `pl_node` union field. AST node is an if, while, for, etc. | 263 | /// Uses the `pl_node` union field. AST node is an if, while, for, etc. |
| 271 | /// Payload is `CondBr`. | 264 | /// Payload is `CondBr`. |
| 272 | condbr, | 265 | condbr, |
| 273 | /// Special case, has no textual representation. | 266 | /// Same as `condbr`, except the condition is coerced to a comptime value, and |
| 267 | /// only the taken branch is analyzed. The then block and else block must | ||
| 268 | /// terminate with an "inline" variant of a noreturn instruction. | ||
| 269 | condbr_inline, | ||
| 270 | /// A comptime known value. | ||
| 274 | /// Uses the `const` union field. | 271 | /// Uses the `const` union field. |
| 275 | @"const", | 272 | @"const", |
| 276 | /// Declares the beginning of a statement. Used for debug info. | 273 | /// Declares the beginning of a statement. Used for debug info. |
| ... | @@ -640,7 +637,7 @@ pub const Inst = struct { | ... | @@ -640,7 +637,7 @@ pub const Inst = struct { |
| 640 | .bitcast_result_ptr, | 637 | .bitcast_result_ptr, |
| 641 | .bit_or, | 638 | .bit_or, |
| 642 | .block, | 639 | .block, |
| 643 | .block_comptime, | 640 | .block_inline, |
| 644 | .loop, | 641 | .loop, |
| 645 | .bool_br_and, | 642 | .bool_br_and, |
| 646 | .bool_br_or, | 643 | .bool_br_or, |
| ... | @@ -744,9 +741,9 @@ pub const Inst = struct { | ... | @@ -744,9 +741,9 @@ pub const Inst = struct { |
| 744 | => false, | 741 | => false, |
| 745 | 742 | ||
| 746 | .@"break", | 743 | .@"break", |
| 747 | .break_void_node, | 744 | .break_inline, |
| 748 | .break_flat, | ||
| 749 | .condbr, | 745 | .condbr, |
| 746 | .condbr_inline, | ||
| 750 | .compile_error, | 747 | .compile_error, |
| 751 | .ret_node, | 748 | .ret_node, |
| 752 | .ret_tok, | 749 | .ret_tok, |
| ... | @@ -1194,16 +1191,6 @@ pub const Inst = struct { | ... | @@ -1194,16 +1191,6 @@ pub const Inst = struct { |
| 1194 | return .{ .node_offset = self.src_node }; | 1191 | return .{ .node_offset = self.src_node }; |
| 1195 | } | 1192 | } |
| 1196 | }, | 1193 | }, |
| 1197 | break_void_node: struct { | ||
| 1198 | /// Offset from Decl AST node index. | ||
| 1199 | /// `Tag` determines which kind of AST node this points to. | ||
| 1200 | src_node: i32, | ||
| 1201 | block_inst: Index, | ||
| 1202 | |||
| 1203 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1204 | return .{ .node_offset = self.src_node }; | ||
| 1205 | } | ||
| 1206 | }, | ||
| 1207 | @"break": struct { | 1194 | @"break": struct { |
| 1208 | block_inst: Index, | 1195 | block_inst: Index, |
| 1209 | operand: Ref, | 1196 | operand: Ref, |
| ... | @@ -1410,7 +1397,6 @@ const Writer = struct { | ... | @@ -1410,7 +1397,6 @@ const Writer = struct { |
| 1410 | .err_union_payload_unsafe_ptr, | 1397 | .err_union_payload_unsafe_ptr, |
| 1411 | .err_union_code, | 1398 | .err_union_code, |
| 1412 | .err_union_code_ptr, | 1399 | .err_union_code_ptr, |
| 1413 | .break_flat, | ||
| 1414 | .is_non_null, | 1400 | .is_non_null, |
| 1415 | .is_null, | 1401 | .is_null, |
| 1416 | .is_non_null_ptr, | 1402 | .is_non_null_ptr, |
| ... | @@ -1438,9 +1424,11 @@ const Writer = struct { | ... | @@ -1438,9 +1424,11 @@ const Writer = struct { |
| 1438 | .int => try self.writeInt(stream, inst), | 1424 | .int => try self.writeInt(stream, inst), |
| 1439 | .str => try self.writeStr(stream, inst), | 1425 | .str => try self.writeStr(stream, inst), |
| 1440 | .elided => try stream.writeAll(")"), | 1426 | .elided => try stream.writeAll(")"), |
| 1441 | .break_void_node => try self.writeBreakVoidNode(stream, inst), | ||
| 1442 | .int_type => try self.writeIntType(stream, inst), | 1427 | .int_type => try self.writeIntType(stream, inst), |
| 1443 | .@"break" => try self.writeBreak(stream, inst), | 1428 | |
| 1429 | .@"break", | ||
| 1430 | .break_inline, | ||
| 1431 | => try self.writeBreak(stream, inst), | ||
| 1444 | 1432 | ||
| 1445 | .@"asm", | 1433 | .@"asm", |
| 1446 | .asm_volatile, | 1434 | .asm_volatile, |
| ... | @@ -1487,11 +1475,13 @@ const Writer = struct { | ... | @@ -1487,11 +1475,13 @@ const Writer = struct { |
| 1487 | => try self.writePlNodeCall(stream, inst), | 1475 | => try self.writePlNodeCall(stream, inst), |
| 1488 | 1476 | ||
| 1489 | .block, | 1477 | .block, |
| 1490 | .block_comptime, | 1478 | .block_inline, |
| 1491 | .loop, | 1479 | .loop, |
| 1492 | => try self.writePlNodeBlock(stream, inst), | 1480 | => try self.writePlNodeBlock(stream, inst), |
| 1493 | 1481 | ||
| 1494 | .condbr => try self.writePlNodeCondBr(stream, inst), | 1482 | .condbr, |
| 1483 | .condbr_inline, | ||
| 1484 | => try self.writePlNodeCondBr(stream, inst), | ||
| 1495 | 1485 | ||
| 1496 | .as_node => try self.writeAs(stream, inst), | 1486 | .as_node => try self.writeAs(stream, inst), |
| 1497 | 1487 | ||
| ... | @@ -1771,13 +1761,6 @@ const Writer = struct { | ... | @@ -1771,13 +1761,6 @@ const Writer = struct { |
| 1771 | return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc); | 1761 | return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc); |
| 1772 | } | 1762 | } |
| 1773 | 1763 | ||
| 1774 | fn writeBreakVoidNode(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1775 | const inst_data = self.code.instructions.items(.data)[inst].break_void_node; | ||
| 1776 | try self.writeInstIndex(stream, inst_data.block_inst); | ||
| 1777 | try stream.writeAll(") "); | ||
| 1778 | try self.writeSrc(stream, inst_data.src()); | ||
| 1779 | } | ||
| 1780 | |||
| 1781 | fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void { | 1764 | fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1782 | const int_type = self.code.instructions.items(.data)[inst].int_type; | 1765 | const int_type = self.code.instructions.items(.data)[inst].int_type; |
| 1783 | const prefix: u8 = switch (int_type.signedness) { | 1766 | const prefix: u8 = switch (int_type.signedness) { |
test/stage2/test.zig+37| ... | @@ -621,6 +621,43 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -621,6 +621,43 @@ pub fn addCases(ctx: *TestContext) !void { |
| 621 | "hello\nhello\nhello\nhello\n", | 621 | "hello\nhello\nhello\nhello\n", |
| 622 | ); | 622 | ); |
| 623 | 623 | ||
| 624 | // inline while requires the condition to be comptime known. | ||
| 625 | case.addError( | ||
| 626 | \\export fn _start() noreturn { | ||
| 627 | \\ var i: u32 = 0; | ||
| 628 | \\ inline while (i < 4) : (i += 1) print(); | ||
| 629 | \\ assert(i == 4); | ||
| 630 | \\ | ||
| 631 | \\ exit(); | ||
| 632 | \\} | ||
| 633 | \\ | ||
| 634 | \\fn print() void { | ||
| 635 | \\ asm volatile ("syscall" | ||
| 636 | \\ : | ||
| 637 | \\ : [number] "{rax}" (1), | ||
| 638 | \\ [arg1] "{rdi}" (1), | ||
| 639 | \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), | ||
| 640 | \\ [arg3] "{rdx}" (6) | ||
| 641 | \\ : "rcx", "r11", "memory" | ||
| 642 | \\ ); | ||
| 643 | \\ return; | ||
| 644 | \\} | ||
| 645 | \\ | ||
| 646 | \\pub fn assert(ok: bool) void { | ||
| 647 | \\ if (!ok) unreachable; // assertion failure | ||
| 648 | \\} | ||
| 649 | \\ | ||
| 650 | \\fn exit() noreturn { | ||
| 651 | \\ asm volatile ("syscall" | ||
| 652 | \\ : | ||
| 653 | \\ : [number] "{rax}" (231), | ||
| 654 | \\ [arg1] "{rdi}" (0) | ||
| 655 | \\ : "rcx", "r11", "memory" | ||
| 656 | \\ ); | ||
| 657 | \\ unreachable; | ||
| 658 | \\} | ||
| 659 | , &[_][]const u8{":3:21: error: unable to resolve comptime value"}); | ||
| 660 | |||
| 624 | // Labeled blocks (no conditional branch) | 661 | // Labeled blocks (no conditional branch) |
| 625 | case.addCompareOutput( | 662 | case.addCompareOutput( |
| 626 | \\export fn _start() noreturn { | 663 | \\export fn _start() noreturn { |