| author | |
| committer | |
| log | 13ced07f23311bef859d07cdd25e0e4fa95ab76a |
| tree | 6800f8f5e311983d66accee7ef8bf5dd25112685 |
| parent | bf7c3e9355530680b066a573c1743f9d570fddc5 |
also start to form a plan for how inline while loops will work5 files changed, 158 insertions(+), 125 deletions(-)
src/Module.zig+9-20| ... | @@ -700,14 +700,7 @@ pub const Scope = struct { | ... | @@ -700,14 +700,7 @@ pub const Scope = struct { |
| 700 | /// It is shared among all the blocks in an inline or comptime called | 700 | /// It is shared among all the blocks in an inline or comptime called |
| 701 | /// function. | 701 | /// function. |
| 702 | pub const Inlining = struct { | 702 | pub const Inlining = struct { |
| 703 | /// Shared state among the entire inline/comptime call stack. | ||
| 704 | shared: *Shared, | ||
| 705 | merges: Merges, | 703 | merges: Merges, |
| 706 | |||
| 707 | pub const Shared = struct { | ||
| 708 | caller: ?*Fn, | ||
| 709 | branch_count: u32, | ||
| 710 | }; | ||
| 711 | }; | 704 | }; |
| 712 | 705 | ||
| 713 | pub const Merges = struct { | 706 | pub const Merges = struct { |
| ... | @@ -2015,6 +2008,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2015,6 +2008,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { |
| 2015 | .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len), | 2008 | .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len), |
| 2016 | .owner_decl = decl, | 2009 | .owner_decl = decl, |
| 2017 | .func = null, | 2010 | .func = null, |
| 2011 | .owner_func = null, | ||
| 2018 | .param_inst_list = &.{}, | 2012 | .param_inst_list = &.{}, |
| 2019 | }; | 2013 | }; |
| 2020 | var block_scope: Scope.Block = .{ | 2014 | var block_scope: Scope.Block = .{ |
| ... | @@ -2236,6 +2230,7 @@ fn astgenAndSemaFn( | ... | @@ -2236,6 +2230,7 @@ fn astgenAndSemaFn( |
| 2236 | .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len), | 2230 | .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len), |
| 2237 | .owner_decl = decl, | 2231 | .owner_decl = decl, |
| 2238 | .func = null, | 2232 | .func = null, |
| 2233 | .owner_func = null, | ||
| 2239 | .param_inst_list = &.{}, | 2234 | .param_inst_list = &.{}, |
| 2240 | }; | 2235 | }; |
| 2241 | var block_scope: Scope.Block = .{ | 2236 | var block_scope: Scope.Block = .{ |
| ... | @@ -2544,6 +2539,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2544,6 +2539,7 @@ fn astgenAndSemaVarDecl( |
| 2544 | .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), | 2539 | .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), |
| 2545 | .owner_decl = decl, | 2540 | .owner_decl = decl, |
| 2546 | .func = null, | 2541 | .func = null, |
| 2542 | .owner_func = null, | ||
| 2547 | .param_inst_list = &.{}, | 2543 | .param_inst_list = &.{}, |
| 2548 | }; | 2544 | }; |
| 2549 | var block_scope: Scope.Block = .{ | 2545 | var block_scope: Scope.Block = .{ |
| ... | @@ -2608,6 +2604,7 @@ fn astgenAndSemaVarDecl( | ... | @@ -2608,6 +2604,7 @@ fn astgenAndSemaVarDecl( |
| 2608 | .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), | 2604 | .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), |
| 2609 | .owner_decl = decl, | 2605 | .owner_decl = decl, |
| 2610 | .func = null, | 2606 | .func = null, |
| 2607 | .owner_func = null, | ||
| 2611 | .param_inst_list = &.{}, | 2608 | .param_inst_list = &.{}, |
| 2612 | }; | 2609 | }; |
| 2613 | var block_scope: Scope.Block = .{ | 2610 | var block_scope: Scope.Block = .{ |
| ... | @@ -3192,6 +3189,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -3192,6 +3189,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { |
| 3192 | .inst_map = try mod.gpa.alloc(*ir.Inst, func.zir.instructions.len), | 3189 | .inst_map = try mod.gpa.alloc(*ir.Inst, func.zir.instructions.len), |
| 3193 | .owner_decl = decl, | 3190 | .owner_decl = decl, |
| 3194 | .func = func, | 3191 | .func = func, |
| 3192 | .owner_func = func, | ||
| 3195 | .param_inst_list = param_inst_list, | 3193 | .param_inst_list = param_inst_list, |
| 3196 | }; | 3194 | }; |
| 3197 | defer mod.gpa.free(sema.inst_map); | 3195 | defer mod.gpa.free(sema.inst_map); |
| ... | @@ -3681,20 +3679,11 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In | ... | @@ -3681,20 +3679,11 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In |
| 3681 | switch (scope.tag) { | 3679 | switch (scope.tag) { |
| 3682 | .block => { | 3680 | .block => { |
| 3683 | const block = scope.cast(Scope.Block).?; | 3681 | const block = scope.cast(Scope.Block).?; |
| 3684 | if (block.inlining) |inlining| { | 3682 | if (block.sema.owner_func) |func| { |
| 3685 | if (inlining.shared.caller) |func| { | 3683 | func.state = .sema_failure; |
| 3686 | func.state = .sema_failure; | ||
| 3687 | } else { | ||
| 3688 | block.sema.owner_decl.analysis = .sema_failure; | ||
| 3689 | block.sema.owner_decl.generation = mod.generation; | ||
| 3690 | } | ||
| 3691 | } else { | 3684 | } else { |
| 3692 | if (block.sema.func) |func| { | 3685 | block.sema.owner_decl.analysis = .sema_failure; |
| 3693 | func.state = .sema_failure; | 3686 | block.sema.owner_decl.generation = mod.generation; |
| 3694 | } else { | ||
| 3695 | block.sema.owner_decl.analysis = .sema_failure; | ||
| 3696 | block.sema.owner_decl.generation = mod.generation; | ||
| 3697 | } | ||
| 3698 | } | 3687 | } |
| 3699 | mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg); | 3688 | mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg); |
| 3700 | }, | 3689 | }, |
src/Sema.zig+75-28| ... | @@ -17,6 +17,12 @@ inst_map: []*Inst, | ... | @@ -17,6 +17,12 @@ inst_map: []*Inst, |
| 17 | /// and `src_decl` of `Scope.Block` is the `Decl` of the callee. | 17 | /// and `src_decl` of `Scope.Block` is the `Decl` of the callee. |
| 18 | /// This `Decl` owns the arena memory of this `Sema`. | 18 | /// This `Decl` owns the arena memory of this `Sema`. |
| 19 | owner_decl: *Decl, | 19 | owner_decl: *Decl, |
| 20 | /// For an inline or comptime function call, this will be the root parent function | ||
| 21 | /// which contains the callsite. Corresponds to `owner_decl`. | ||
| 22 | owner_func: ?*Module.Fn, | ||
| 23 | /// The function this ZIR code is the body of, according to the source code. | ||
| 24 | /// This starts out the same as `owner_func` and then diverges in the case of | ||
| 25 | /// an inline or comptime function call. | ||
| 20 | func: ?*Module.Fn, | 26 | func: ?*Module.Fn, |
| 21 | /// For now, TZIR requires arg instructions to be the first N instructions in the | 27 | /// For now, TZIR requires arg instructions to be the first N instructions in the |
| 22 | /// TZIR code. We store references here for the purpose of `resolveInst`. | 28 | /// TZIR code. We store references here for the purpose of `resolveInst`. |
| ... | @@ -26,6 +32,7 @@ func: ?*Module.Fn, | ... | @@ -26,6 +32,7 @@ func: ?*Module.Fn, |
| 26 | /// > param_count: u32 | 32 | /// > param_count: u32 |
| 27 | param_inst_list: []const *ir.Inst, | 33 | param_inst_list: []const *ir.Inst, |
| 28 | branch_quota: u32 = 1000, | 34 | branch_quota: u32 = 1000, |
| 35 | branch_count: u32 = 0, | ||
| 29 | /// This field is updated when a new source location becomes active, so that | 36 | /// This field is updated when a new source location becomes active, so that |
| 30 | /// instructions which do not have explicitly mapped source locations still have | 37 | /// instructions which do not have explicitly mapped source locations still have |
| 31 | /// access to the source location set by the previous instruction which did | 38 | /// access to the source location set by the previous instruction which did |
| ... | @@ -86,6 +93,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -86,6 +93,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 86 | 93 | ||
| 87 | const map = block.sema.inst_map; | 94 | const map = block.sema.inst_map; |
| 88 | const tags = block.sema.code.instructions.items(.tag); | 95 | const tags = block.sema.code.instructions.items(.tag); |
| 96 | const datas = block.sema.code.instructions.items(.data); | ||
| 89 | 97 | ||
| 90 | // We use a while(true) loop here to avoid a redundant way of breaking out of | 98 | // We use a while(true) loop here to avoid a redundant way of breaking out of |
| 91 | // the loop. The only way to break out of the loop is with a `noreturn` | 99 | // the loop. The only way to break out of the loop is with a `noreturn` |
| ... | @@ -178,6 +186,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -178,6 +186,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 178 | .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true), | 186 | .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true), |
| 179 | .is_null => try sema.zirIsNull(block, inst, false), | 187 | .is_null => try sema.zirIsNull(block, inst, false), |
| 180 | .is_null_ptr => try sema.zirIsNullPtr(block, inst, false), | 188 | .is_null_ptr => try sema.zirIsNullPtr(block, inst, false), |
| 189 | .loop => try sema.zirLoop(block, inst), | ||
| 181 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), | 190 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), |
| 182 | .mod_rem => try sema.zirArithmetic(block, inst), | 191 | .mod_rem => try sema.zirArithmetic(block, inst), |
| 183 | .mul => try sema.zirArithmetic(block, inst), | 192 | .mul => try sema.zirArithmetic(block, inst), |
| ... | @@ -225,7 +234,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -225,7 +234,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 225 | .ret_node => return sema.zirRetNode(block, inst), | 234 | .ret_node => return sema.zirRetNode(block, inst), |
| 226 | .ret_tok => return sema.zirRetTok(block, inst, false), | 235 | .ret_tok => return sema.zirRetTok(block, inst, false), |
| 227 | .@"unreachable" => return sema.zirUnreachable(block, inst), | 236 | .@"unreachable" => return sema.zirUnreachable(block, inst), |
| 228 | .loop => return sema.zirLoop(block, inst), | 237 | .repeat => return sema.zirRepeat(block, inst), |
| 229 | 238 | ||
| 230 | // Instructions that we know can *never* be noreturn based solely on | 239 | // Instructions that we know can *never* be noreturn based solely on |
| 231 | // their tag. We avoid needlessly checking if they are noreturn and | 240 | // their tag. We avoid needlessly checking if they are noreturn and |
| ... | @@ -276,6 +285,14 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde | ... | @@ -276,6 +285,14 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde |
| 276 | try sema.zirResolveInferredAlloc(block, inst); | 285 | try sema.zirResolveInferredAlloc(block, inst); |
| 277 | continue; | 286 | continue; |
| 278 | }, | 287 | }, |
| 288 | |||
| 289 | // Special case: send comptime control flow back to the beginning of this block. | ||
| 290 | .repeat_inline => { | ||
| 291 | const src: LazySrcLoc = .{ .node_offset = datas[inst].node }; | ||
| 292 | try sema.emitBackwardBranch(block, src); | ||
| 293 | i = 0; | ||
| 294 | continue; | ||
| 295 | }, | ||
| 279 | }; | 296 | }; |
| 280 | if (map[inst].ty.isNoReturn()) | 297 | if (map[inst].ty.isNoReturn()) |
| 281 | return always_noreturn; | 298 | return always_noreturn; |
| ... | @@ -764,14 +781,50 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -764,14 +781,50 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 764 | } | 781 | } |
| 765 | } | 782 | } |
| 766 | 783 | ||
| 767 | fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { | 784 | fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref { |
| 785 | const tracy = trace(@src()); | ||
| 786 | defer tracy.end(); | ||
| 787 | |||
| 788 | const src_node = sema.code.instructions.items(.data)[inst].node; | ||
| 789 | const src: LazySrcLoc = .{ .node_offset = src_node }; | ||
| 790 | try sema.requireRuntimeBlock(block, src); | ||
| 791 | return always_noreturn; | ||
| 792 | } | ||
| 793 | |||
| 794 | fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | ||
| 768 | const tracy = trace(@src()); | 795 | const tracy = trace(@src()); |
| 769 | defer tracy.end(); | 796 | defer tracy.end(); |
| 770 | 797 | ||
| 771 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 798 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 772 | const src = inst_data.src(); | 799 | const src = inst_data.src(); |
| 773 | const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index); | 800 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); |
| 774 | const body = sema.code.extra[extra.end..][0..extra.data.operands_len]; | 801 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 802 | |||
| 803 | // TZIR expects a block outside the loop block too. | ||
| 804 | const block_inst = try sema.arena.create(Inst.Block); | ||
| 805 | block_inst.* = .{ | ||
| 806 | .base = .{ | ||
| 807 | .tag = Inst.Block.base_tag, | ||
| 808 | .ty = undefined, | ||
| 809 | .src = src, | ||
| 810 | }, | ||
| 811 | .body = undefined, | ||
| 812 | }; | ||
| 813 | |||
| 814 | var child_block = parent_block.makeSubBlock(); | ||
| 815 | child_block.label = Scope.Block.Label{ | ||
| 816 | .zir_block = inst, | ||
| 817 | .merges = .{ | ||
| 818 | .results = .{}, | ||
| 819 | .br_list = .{}, | ||
| 820 | .block_inst = block_inst, | ||
| 821 | }, | ||
| 822 | }; | ||
| 823 | const merges = &child_block.label.?.merges; | ||
| 824 | |||
| 825 | defer child_block.instructions.deinit(sema.gpa); | ||
| 826 | defer merges.results.deinit(sema.gpa); | ||
| 827 | defer merges.br_list.deinit(sema.gpa); | ||
| 775 | 828 | ||
| 776 | // Reserve space for a Loop instruction so that generated Break instructions can | 829 | // Reserve space for a Loop instruction so that generated Break instructions can |
| 777 | // point to it, even if it doesn't end up getting used because the code ends up being | 830 | // point to it, even if it doesn't end up getting used because the code ends up being |
| ... | @@ -786,23 +839,17 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -786,23 +839,17 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 786 | .body = undefined, | 839 | .body = undefined, |
| 787 | }; | 840 | }; |
| 788 | 841 | ||
| 789 | var child_block: Scope.Block = .{ | 842 | var loop_block = child_block.makeSubBlock(); |
| 790 | .parent = parent_block, | 843 | defer loop_block.instructions.deinit(sema.gpa); |
| 791 | .sema = sema, | ||
| 792 | .src_decl = parent_block.src_decl, | ||
| 793 | .instructions = .{}, | ||
| 794 | .inlining = parent_block.inlining, | ||
| 795 | .is_comptime = parent_block.is_comptime, | ||
| 796 | }; | ||
| 797 | defer child_block.instructions.deinit(sema.gpa); | ||
| 798 | 844 | ||
| 799 | _ = try sema.analyzeBody(&child_block, body); | 845 | _ = try sema.analyzeBody(&loop_block, body); |
| 800 | 846 | ||
| 801 | // Loop repetition is implied so the last instruction may or may not be a noreturn instruction. | 847 | // Loop repetition is implied so the last instruction may or may not be a noreturn instruction. |
| 802 | 848 | ||
| 803 | try parent_block.instructions.append(sema.gpa, &loop_inst.base); | 849 | try child_block.instructions.append(sema.gpa, &loop_inst.base); |
| 804 | loop_inst.body = .{ .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items) }; | 850 | loop_inst.body = .{ .instructions = try sema.arena.dupe(*Inst, loop_block.instructions.items) }; |
| 805 | return always_noreturn; | 851 | |
| 852 | return sema.analyzeBlockBody(parent_block, &child_block, merges); | ||
| 806 | } | 853 | } |
| 807 | 854 | ||
| 808 | fn zirBlock( | 855 | fn zirBlock( |
| ... | @@ -1160,16 +1207,9 @@ fn analyzeCall( | ... | @@ -1160,16 +1207,9 @@ fn analyzeCall( |
| 1160 | }, | 1207 | }, |
| 1161 | .body = undefined, | 1208 | .body = undefined, |
| 1162 | }; | 1209 | }; |
| 1163 | // If this is the top of the inline/comptime call stack, we use this data. | ||
| 1164 | // Otherwise we pass on the shared data from the parent scope. | ||
| 1165 | var shared_inlining: Scope.Block.Inlining.Shared = .{ | ||
| 1166 | .branch_count = 0, | ||
| 1167 | .caller = sema.func, | ||
| 1168 | }; | ||
| 1169 | // This one is shared among sub-blocks within the same callee, but not | 1210 | // This one is shared among sub-blocks within the same callee, but not |
| 1170 | // shared among the entire inline/comptime call stack. | 1211 | // shared among the entire inline/comptime call stack. |
| 1171 | var inlining: Scope.Block.Inlining = .{ | 1212 | var inlining: Scope.Block.Inlining = .{ |
| 1172 | .shared = if (block.inlining) |inlining| inlining.shared else &shared_inlining, | ||
| 1173 | .merges = .{ | 1213 | .merges = .{ |
| 1174 | .results = .{}, | 1214 | .results = .{}, |
| 1175 | .br_list = .{}, | 1215 | .br_list = .{}, |
| ... | @@ -1183,8 +1223,11 @@ fn analyzeCall( | ... | @@ -1183,8 +1223,11 @@ fn analyzeCall( |
| 1183 | .code = module_fn.zir, | 1223 | .code = module_fn.zir, |
| 1184 | .inst_map = try sema.gpa.alloc(*ir.Inst, module_fn.zir.instructions.len), | 1224 | .inst_map = try sema.gpa.alloc(*ir.Inst, module_fn.zir.instructions.len), |
| 1185 | .owner_decl = sema.owner_decl, | 1225 | .owner_decl = sema.owner_decl, |
| 1226 | .owner_func = sema.owner_func, | ||
| 1186 | .func = module_fn, | 1227 | .func = module_fn, |
| 1187 | .param_inst_list = casted_args, | 1228 | .param_inst_list = casted_args, |
| 1229 | .branch_quota = sema.branch_quota, | ||
| 1230 | .branch_count = sema.branch_count, | ||
| 1188 | }; | 1231 | }; |
| 1189 | defer sema.gpa.free(inline_sema.inst_map); | 1232 | defer sema.gpa.free(inline_sema.inst_map); |
| 1190 | 1233 | ||
| ... | @@ -1210,7 +1253,12 @@ fn analyzeCall( | ... | @@ -1210,7 +1253,12 @@ fn analyzeCall( |
| 1210 | // the block_inst above. | 1253 | // the block_inst above. |
| 1211 | _ = try inline_sema.root(&child_block); | 1254 | _ = try inline_sema.root(&child_block); |
| 1212 | 1255 | ||
| 1213 | break :res try inline_sema.analyzeBlockBody(block, &child_block, merges); | 1256 | const result = try inline_sema.analyzeBlockBody(block, &child_block, merges); |
| 1257 | |||
| 1258 | sema.branch_quota = inline_sema.branch_quota; | ||
| 1259 | sema.branch_count = inline_sema.branch_count; | ||
| 1260 | |||
| 1261 | break :res result; | ||
| 1214 | } else res: { | 1262 | } else res: { |
| 1215 | try sema.requireRuntimeBlock(block, call_src); | 1263 | try sema.requireRuntimeBlock(block, call_src); |
| 1216 | break :res try block.addCall(call_src, ret_type, func, casted_args); | 1264 | break :res try block.addCall(call_src, ret_type, func, casted_args); |
| ... | @@ -3169,9 +3217,8 @@ fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: Pani | ... | @@ -3169,9 +3217,8 @@ fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: Pani |
| 3169 | } | 3217 | } |
| 3170 | 3218 | ||
| 3171 | fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { | 3219 | fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { |
| 3172 | const shared = block.inlining.?.shared; | 3220 | sema.branch_count += 1; |
| 3173 | shared.branch_count += 1; | 3221 | if (sema.branch_count > sema.branch_quota) { |
| 3174 | if (shared.branch_count > sema.branch_quota) { | ||
| 3175 | // TODO show the "called from here" stack | 3222 | // TODO show the "called from here" stack |
| 3176 | return sema.mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{sema.branch_quota}); | 3223 | return sema.mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{sema.branch_quota}); |
| 3177 | } | 3224 | } |
src/astgen.zig+35-62| ... | @@ -1055,6 +1055,7 @@ fn blockExprStmts( | ... | @@ -1055,6 +1055,7 @@ fn blockExprStmts( |
| 1055 | .bit_or, | 1055 | .bit_or, |
| 1056 | .block, | 1056 | .block, |
| 1057 | .block_comptime, | 1057 | .block_comptime, |
| 1058 | .loop, | ||
| 1058 | .bool_br_and, | 1059 | .bool_br_and, |
| 1059 | .bool_br_or, | 1060 | .bool_br_or, |
| 1060 | .bool_not, | 1061 | .bool_not, |
| ... | @@ -1156,12 +1157,13 @@ fn blockExprStmts( | ... | @@ -1156,12 +1157,13 @@ fn blockExprStmts( |
| 1156 | .ret_tok, | 1157 | .ret_tok, |
| 1157 | .ret_coerce, | 1158 | .ret_coerce, |
| 1158 | .@"unreachable", | 1159 | .@"unreachable", |
| 1159 | .loop, | ||
| 1160 | .elided, | 1160 | .elided, |
| 1161 | .store, | 1161 | .store, |
| 1162 | .store_to_block_ptr, | 1162 | .store_to_block_ptr, |
| 1163 | .store_to_inferred_ptr, | 1163 | .store_to_inferred_ptr, |
| 1164 | .resolve_inferred_alloc, | 1164 | .resolve_inferred_alloc, |
| 1165 | .repeat, | ||
| 1166 | .repeat_inline, | ||
| 1165 | => break :b true, | 1167 | => break :b true, |
| 1166 | } | 1168 | } |
| 1167 | } else switch (maybe_unused_result) { | 1169 | } else switch (maybe_unused_result) { |
| ... | @@ -2145,20 +2147,16 @@ fn whileExpr( | ... | @@ -2145,20 +2147,16 @@ fn whileExpr( |
| 2145 | node: ast.Node.Index, | 2147 | node: ast.Node.Index, |
| 2146 | while_full: ast.full.While, | 2148 | while_full: ast.full.While, |
| 2147 | ) InnerError!zir.Inst.Ref { | 2149 | ) InnerError!zir.Inst.Ref { |
| 2148 | if (true) @panic("TODO update for zir-memory-layout"); | ||
| 2149 | if (while_full.label_token) |label_token| { | 2150 | if (while_full.label_token) |label_token| { |
| 2150 | try checkLabelRedefinition(mod, scope, label_token); | 2151 | try checkLabelRedefinition(mod, scope, label_token); |
| 2151 | } | 2152 | } |
| 2152 | if (while_full.inline_token) |inline_token| { | ||
| 2153 | return mod.failTok(scope, inline_token, "TODO inline while", .{}); | ||
| 2154 | } | ||
| 2155 | |||
| 2156 | const parent_gz = scope.getGenZir(); | 2153 | const parent_gz = scope.getGenZir(); |
| 2154 | const loop_block = try parent_gz.addBlock(.loop, node); | ||
| 2155 | try parent_gz.instructions.append(mod.gpa, loop_block); | ||
| 2157 | 2156 | ||
| 2158 | var loop_scope: Scope.GenZir = .{ | 2157 | var loop_scope: Scope.GenZir = .{ |
| 2159 | .parent = scope, | 2158 | .parent = scope, |
| 2160 | .decl = scope.ownerDecl().?, | 2159 | .zir_code = parent_gz.zir_code, |
| 2161 | .arena = scope.arena(), | ||
| 2162 | .force_comptime = parent_gz.force_comptime, | 2160 | .force_comptime = parent_gz.force_comptime, |
| 2163 | .instructions = .{}, | 2161 | .instructions = .{}, |
| 2164 | }; | 2162 | }; |
| ... | @@ -2167,21 +2165,12 @@ fn whileExpr( | ... | @@ -2167,21 +2165,12 @@ fn whileExpr( |
| 2167 | 2165 | ||
| 2168 | var continue_scope: Scope.GenZir = .{ | 2166 | var continue_scope: Scope.GenZir = .{ |
| 2169 | .parent = &loop_scope.base, | 2167 | .parent = &loop_scope.base, |
| 2170 | .decl = loop_scope.decl, | 2168 | .zir_code = parent_gz.zir_code, |
| 2171 | .arena = loop_scope.arena, | ||
| 2172 | .force_comptime = loop_scope.force_comptime, | 2169 | .force_comptime = loop_scope.force_comptime, |
| 2173 | .instructions = .{}, | 2170 | .instructions = .{}, |
| 2174 | }; | 2171 | }; |
| 2175 | defer continue_scope.instructions.deinit(mod.gpa); | 2172 | defer continue_scope.instructions.deinit(mod.gpa); |
| 2176 | 2173 | ||
| 2177 | const tree = gz.tree(); | ||
| 2178 | const main_tokens = tree.nodes.items(.main_token); | ||
| 2179 | |||
| 2180 | const while_src = token_starts[while_full.ast.while_token]; | ||
| 2181 | const void_type = try addZIRInstConst(mod, scope, while_src, .{ | ||
| 2182 | .ty = Type.initTag(.type), | ||
| 2183 | .val = Value.initTag(.void_type), | ||
| 2184 | }); | ||
| 2185 | const cond = c: { | 2174 | const cond = c: { |
| 2186 | // TODO https://github.com/ziglang/zig/issues/7929 | 2175 | // TODO https://github.com/ziglang/zig/issues/7929 |
| 2187 | if (while_full.error_token) |error_token| { | 2176 | if (while_full.error_token) |error_token| { |
| ... | @@ -2189,59 +2178,41 @@ fn whileExpr( | ... | @@ -2189,59 +2178,41 @@ fn whileExpr( |
| 2189 | } else if (while_full.payload_token) |payload_token| { | 2178 | } else if (while_full.payload_token) |payload_token| { |
| 2190 | return mod.failTok(scope, payload_token, "TODO implement while optional", .{}); | 2179 | return mod.failTok(scope, payload_token, "TODO implement while optional", .{}); |
| 2191 | } else { | 2180 | } else { |
| 2192 | const bool_type = try addZIRInstConst(mod, &continue_scope.base, while_src, .{ | 2181 | const bool_type_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.bool_type) }; |
| 2193 | .ty = Type.initTag(.type), | 2182 | break :c try expr(mod, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr); |
| 2194 | .val = Value.initTag(.bool_type), | ||
| 2195 | }); | ||
| 2196 | break :c try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_full.ast.cond_expr); | ||
| 2197 | } | 2183 | } |
| 2198 | }; | 2184 | }; |
| 2199 | 2185 | ||
| 2200 | const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{ | 2186 | const condbr = try continue_scope.addCondBr(node); |
| 2201 | .condition = cond, | 2187 | const cond_block = try loop_scope.addBlock(.block, node); |
| 2202 | .then_body = undefined, // populated below | 2188 | try loop_scope.instructions.append(mod.gpa, cond_block); |
| 2203 | .else_body = undefined, // populated below | 2189 | try continue_scope.setBlockBody(cond_block); |
| 2204 | }, .{}); | 2190 | |
| 2205 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .block, .{ | ||
| 2206 | .instructions = try loop_scope.arena.dupe(zir.Inst.Ref, continue_scope.instructions.items), | ||
| 2207 | }); | ||
| 2208 | // TODO avoid emitting the continue expr when there | 2191 | // TODO avoid emitting the continue expr when there |
| 2209 | // are no jumps to it. This happens when the last statement of a while body is noreturn | 2192 | // are no jumps to it. This happens when the last statement of a while body is noreturn |
| 2210 | // and there are no `continue` statements. | 2193 | // and there are no `continue` statements. |
| 2211 | // The "repeat" at the end of a loop body is implied. | 2194 | // The "repeat" at the end of a loop body is implied. |
| 2212 | if (while_full.ast.cont_expr != 0) { | 2195 | if (while_full.ast.cont_expr != 0) { |
| 2213 | _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, while_full.ast.cont_expr); | 2196 | const void_type_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.void_type) }; |
| 2197 | _ = try expr(mod, &loop_scope.base, void_type_rl, while_full.ast.cont_expr); | ||
| 2214 | } | 2198 | } |
| 2215 | const loop = try scope.arena().create(zir.Inst.Loop); | 2199 | const is_inline = while_full.inline_token != null; |
| 2216 | loop.* = .{ | 2200 | const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; |
| 2217 | .base = .{ | 2201 | _ = try loop_scope.addNode(repeat_tag, node); |
| 2218 | .tag = .loop, | 2202 | |
| 2219 | .src = while_src, | 2203 | try loop_scope.setBlockBody(loop_block); |
| 2220 | }, | 2204 | loop_scope.break_block = loop_block; |
| 2221 | .positionals = .{ | ||
| 2222 | .body = .{ | ||
| 2223 | .instructions = try scope.arena().dupe(zir.Inst.Ref, loop_scope.instructions.items), | ||
| 2224 | }, | ||
| 2225 | }, | ||
| 2226 | .kw_args = .{}, | ||
| 2227 | }; | ||
| 2228 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ | ||
| 2229 | .instructions = try scope.arena().dupe(zir.Inst.Ref, &[1]zir.Inst.Ref{&loop.base}), | ||
| 2230 | }); | ||
| 2231 | loop_scope.break_block = while_block; | ||
| 2232 | loop_scope.continue_block = cond_block; | 2205 | loop_scope.continue_block = cond_block; |
| 2233 | if (while_full.label_token) |label_token| { | 2206 | if (while_full.label_token) |label_token| { |
| 2234 | loop_scope.label = @as(?Scope.GenZir.Label, Scope.GenZir.Label{ | 2207 | loop_scope.label = @as(?Scope.GenZir.Label, Scope.GenZir.Label{ |
| 2235 | .token = label_token, | 2208 | .token = label_token, |
| 2236 | .block_inst = while_block, | 2209 | .block_inst = loop_block, |
| 2237 | }); | 2210 | }); |
| 2238 | } | 2211 | } |
| 2239 | 2212 | ||
| 2240 | const then_src = token_starts[tree.lastToken(while_full.ast.then_expr)]; | ||
| 2241 | var then_scope: Scope.GenZir = .{ | 2213 | var then_scope: Scope.GenZir = .{ |
| 2242 | .parent = &continue_scope.base, | 2214 | .parent = &continue_scope.base, |
| 2243 | .decl = continue_scope.decl, | 2215 | .zir_code = parent_gz.zir_code, |
| 2244 | .arena = continue_scope.arena, | ||
| 2245 | .force_comptime = continue_scope.force_comptime, | 2216 | .force_comptime = continue_scope.force_comptime, |
| 2246 | .instructions = .{}, | 2217 | .instructions = .{}, |
| 2247 | }; | 2218 | }; |
| ... | @@ -2254,29 +2225,31 @@ fn whileExpr( | ... | @@ -2254,29 +2225,31 @@ fn whileExpr( |
| 2254 | 2225 | ||
| 2255 | var else_scope: Scope.GenZir = .{ | 2226 | var else_scope: Scope.GenZir = .{ |
| 2256 | .parent = &continue_scope.base, | 2227 | .parent = &continue_scope.base, |
| 2257 | .decl = continue_scope.decl, | 2228 | .zir_code = parent_gz.zir_code, |
| 2258 | .arena = continue_scope.arena, | ||
| 2259 | .force_comptime = continue_scope.force_comptime, | 2229 | .force_comptime = continue_scope.force_comptime, |
| 2260 | .instructions = .{}, | 2230 | .instructions = .{}, |
| 2261 | }; | 2231 | }; |
| 2262 | defer else_scope.instructions.deinit(mod.gpa); | 2232 | defer else_scope.instructions.deinit(mod.gpa); |
| 2263 | 2233 | ||
| 2264 | const else_node = while_full.ast.else_expr; | 2234 | const else_node = while_full.ast.else_expr; |
| 2265 | const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: { | 2235 | const else_info: struct { |
| 2236 | src: ast.Node.Index, | ||
| 2237 | result: zir.Inst.Ref, | ||
| 2238 | } = if (else_node != 0) blk: { | ||
| 2266 | loop_scope.break_count += 1; | 2239 | loop_scope.break_count += 1; |
| 2267 | const sub_scope = &else_scope.base; | 2240 | const sub_scope = &else_scope.base; |
| 2268 | break :blk .{ | 2241 | break :blk .{ |
| 2269 | .src = token_starts[tree.lastToken(else_node)], | 2242 | .src = else_node, |
| 2270 | .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node), | 2243 | .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node), |
| 2271 | }; | 2244 | }; |
| 2272 | } else .{ | 2245 | } else .{ |
| 2273 | .src = token_starts[tree.lastToken(while_full.ast.then_expr)], | 2246 | .src = while_full.ast.then_expr, |
| 2274 | .result = null, | 2247 | .result = 0, |
| 2275 | }; | 2248 | }; |
| 2276 | 2249 | ||
| 2277 | if (loop_scope.label) |some| { | 2250 | if (loop_scope.label) |some| { |
| 2278 | if (!some.used) { | 2251 | if (!some.used) { |
| 2279 | return mod.fail(scope, token_starts[some.token], "unused while loop label", .{}); | 2252 | return mod.failTok(scope, some.token, "unused while loop label", .{}); |
| 2280 | } | 2253 | } |
| 2281 | } | 2254 | } |
| 2282 | return finishThenElseBlock( | 2255 | return finishThenElseBlock( |
| ... | @@ -2289,11 +2262,11 @@ fn whileExpr( | ... | @@ -2289,11 +2262,11 @@ fn whileExpr( |
| 2289 | &else_scope, | 2262 | &else_scope, |
| 2290 | condbr, | 2263 | condbr, |
| 2291 | cond, | 2264 | cond, |
| 2292 | then_src, | 2265 | while_full.ast.then_expr, |
| 2293 | else_info.src, | 2266 | else_info.src, |
| 2294 | then_result, | 2267 | then_result, |
| 2295 | else_info.result, | 2268 | else_info.result, |
| 2296 | while_block, | 2269 | loop_block, |
| 2297 | cond_block, | 2270 | cond_block, |
| 2298 | ); | 2271 | ); |
| 2299 | } | 2272 | } |
src/ir.zig+10-8| ... | @@ -80,22 +80,24 @@ pub const Inst = struct { | ... | @@ -80,22 +80,24 @@ pub const Inst = struct { |
| 80 | condbr, | 80 | condbr, |
| 81 | constant, | 81 | constant, |
| 82 | dbg_stmt, | 82 | dbg_stmt, |
| 83 | // ?T => bool | 83 | /// ?T => bool |
| 84 | is_null, | 84 | is_null, |
| 85 | // ?T => bool (inverted logic) | 85 | /// ?T => bool (inverted logic) |
| 86 | is_non_null, | 86 | is_non_null, |
| 87 | // *?T => bool | 87 | /// *?T => bool |
| 88 | is_null_ptr, | 88 | is_null_ptr, |
| 89 | // *?T => bool (inverted logic) | 89 | /// *?T => bool (inverted logic) |
| 90 | is_non_null_ptr, | 90 | is_non_null_ptr, |
| 91 | // E!T => bool | 91 | /// E!T => bool |
| 92 | is_err, | 92 | is_err, |
| 93 | // *E!T => bool | 93 | /// *E!T => bool |
| 94 | is_err_ptr, | 94 | is_err_ptr, |
| 95 | bool_and, | 95 | bool_and, |
| 96 | bool_or, | 96 | bool_or, |
| 97 | /// Read a value from a pointer. | 97 | /// Read a value from a pointer. |
| 98 | load, | 98 | load, |
| 99 | /// A labeled block of code that loops forever. At the end of the body it is implied | ||
| 100 | /// to repeat; no explicit "repeat" instruction terminates loop bodies. | ||
| 99 | loop, | 101 | loop, |
| 100 | ptrtoint, | 102 | ptrtoint, |
| 101 | ref, | 103 | ref, |
| ... | @@ -112,9 +114,9 @@ pub const Inst = struct { | ... | @@ -112,9 +114,9 @@ pub const Inst = struct { |
| 112 | not, | 114 | not, |
| 113 | floatcast, | 115 | floatcast, |
| 114 | intcast, | 116 | intcast, |
| 115 | // ?T => T | 117 | /// ?T => T |
| 116 | optional_payload, | 118 | optional_payload, |
| 117 | // *?T => *T | 119 | /// *?T => *T |
| 118 | optional_payload_ptr, | 120 | optional_payload_ptr, |
| 119 | wrap_optional, | 121 | wrap_optional, |
| 120 | /// E!T -> T | 122 | /// E!T -> T |
src/zir.zig+29-7| ... | @@ -649,11 +649,19 @@ pub const Inst = struct { | ... | @@ -649,11 +649,19 @@ pub const Inst = struct { |
| 649 | /// Return a boolean true if dereferenced pointer is an error | 649 | /// Return a boolean true if dereferenced pointer is an error |
| 650 | /// Uses the `un_tok` field. | 650 | /// Uses the `un_tok` field. |
| 651 | is_err_ptr, | 651 | is_err_ptr, |
| 652 | /// A labeled block of code that loops forever. At the end of the body it is implied | 652 | /// A labeled block of code that loops forever. At the end of the body will have either |
| 653 | /// to repeat; no explicit "repeat" instruction terminates loop bodies. | 653 | /// a `repeat` instruction or a `repeat_inline` instruction. |
| 654 | /// Uses the `pl_node` field. The AST node is either a for loop or while loop. | 654 | /// Uses the `pl_node` field. The AST node is either a for loop or while loop. |
| 655 | /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema | ||
| 656 | /// needs to emit more than 1 TZIR block for this instruction. | ||
| 655 | /// The payload is `Block`. | 657 | /// The payload is `Block`. |
| 656 | loop, | 658 | loop, |
| 659 | /// Sends runtime control flow back to the beginning of the current block. | ||
| 660 | /// Uses the `node` field. | ||
| 661 | repeat, | ||
| 662 | /// Sends comptime control flow back to the beginning of the current block. | ||
| 663 | /// Uses the `node` field. | ||
| 664 | repeat_inline, | ||
| 657 | /// Merge two error sets into one, `E1 || E2`. | 665 | /// Merge two error sets into one, `E1 || E2`. |
| 658 | merge_error_sets, | 666 | merge_error_sets, |
| 659 | /// Ambiguously remainder division or modulus. If the computation would possibly have | 667 | /// Ambiguously remainder division or modulus. If the computation would possibly have |
| ... | @@ -736,6 +744,7 @@ pub const Inst = struct { | ... | @@ -736,6 +744,7 @@ pub const Inst = struct { |
| 736 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`. | 744 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`. |
| 737 | slice_sentinel, | 745 | slice_sentinel, |
| 738 | /// Write a value to a pointer. For loading, see `deref`. | 746 | /// Write a value to a pointer. For loading, see `deref`. |
| 747 | /// Uses the `bin` union field. | ||
| 739 | store, | 748 | store, |
| 740 | /// Same as `store` but the type of the value being stored will be used to infer | 749 | /// Same as `store` but the type of the value being stored will be used to infer |
| 741 | /// the block type. The LHS is the pointer to store to. | 750 | /// the block type. The LHS is the pointer to store to. |
| ... | @@ -902,6 +911,7 @@ pub const Inst = struct { | ... | @@ -902,6 +911,7 @@ pub const Inst = struct { |
| 902 | .bit_or, | 911 | .bit_or, |
| 903 | .block, | 912 | .block, |
| 904 | .block_comptime, | 913 | .block_comptime, |
| 914 | .loop, | ||
| 905 | .bool_br_and, | 915 | .bool_br_and, |
| 906 | .bool_br_or, | 916 | .bool_br_or, |
| 907 | .bool_not, | 917 | .bool_not, |
| ... | @@ -1012,7 +1022,8 @@ pub const Inst = struct { | ... | @@ -1012,7 +1022,8 @@ pub const Inst = struct { |
| 1012 | .ret_tok, | 1022 | .ret_tok, |
| 1013 | .ret_coerce, | 1023 | .ret_coerce, |
| 1014 | .@"unreachable", | 1024 | .@"unreachable", |
| 1015 | .loop, | 1025 | .repeat, |
| 1026 | .repeat_inline, | ||
| 1016 | => true, | 1027 | => true, |
| 1017 | }; | 1028 | }; |
| 1018 | } | 1029 | } |
| ... | @@ -1355,12 +1366,13 @@ const Writer = struct { | ... | @@ -1355,12 +1366,13 @@ const Writer = struct { |
| 1355 | .bit_and, | 1366 | .bit_and, |
| 1356 | .bit_or, | 1367 | .bit_or, |
| 1357 | .as, | 1368 | .as, |
| 1358 | .@"break", | ||
| 1359 | .coerce_result_ptr, | 1369 | .coerce_result_ptr, |
| 1360 | .elem_ptr, | 1370 | .elem_ptr, |
| 1361 | .elem_val, | 1371 | .elem_val, |
| 1362 | .intcast, | 1372 | .intcast, |
| 1363 | .merge_error_sets, | 1373 | .merge_error_sets, |
| 1374 | .store, | ||
| 1375 | .store_to_block_ptr, | ||
| 1364 | => try self.writeBin(stream, inst), | 1376 | => try self.writeBin(stream, inst), |
| 1365 | 1377 | ||
| 1366 | .alloc, | 1378 | .alloc, |
| ... | @@ -1425,6 +1437,7 @@ const Writer = struct { | ... | @@ -1425,6 +1437,7 @@ const Writer = struct { |
| 1425 | .elided => try stream.writeAll(")"), | 1437 | .elided => try stream.writeAll(")"), |
| 1426 | .break_void_node => try self.writeBreakVoidNode(stream, inst), | 1438 | .break_void_node => try self.writeBreakVoidNode(stream, inst), |
| 1427 | .int_type => try self.writeIntType(stream, inst), | 1439 | .int_type => try self.writeIntType(stream, inst), |
| 1440 | .@"break" => try self.writeBreak(stream, inst), | ||
| 1428 | 1441 | ||
| 1429 | .@"asm", | 1442 | .@"asm", |
| 1430 | .asm_volatile, | 1443 | .asm_volatile, |
| ... | @@ -1436,7 +1449,6 @@ const Writer = struct { | ... | @@ -1436,7 +1449,6 @@ const Writer = struct { |
| 1436 | .field_ptr_named, | 1449 | .field_ptr_named, |
| 1437 | .field_val_named, | 1450 | .field_val_named, |
| 1438 | .floatcast, | 1451 | .floatcast, |
| 1439 | .loop, | ||
| 1440 | .slice_start, | 1452 | .slice_start, |
| 1441 | .slice_end, | 1453 | .slice_end, |
| 1442 | .slice_sentinel, | 1454 | .slice_sentinel, |
| ... | @@ -1473,6 +1485,7 @@ const Writer = struct { | ... | @@ -1473,6 +1485,7 @@ const Writer = struct { |
| 1473 | 1485 | ||
| 1474 | .block, | 1486 | .block, |
| 1475 | .block_comptime, | 1487 | .block_comptime, |
| 1488 | .loop, | ||
| 1476 | => try self.writePlNodeBlock(stream, inst), | 1489 | => try self.writePlNodeBlock(stream, inst), |
| 1477 | 1490 | ||
| 1478 | .condbr => try self.writePlNodeCondBr(stream, inst), | 1491 | .condbr => try self.writePlNodeCondBr(stream, inst), |
| ... | @@ -1483,6 +1496,8 @@ const Writer = struct { | ... | @@ -1483,6 +1496,8 @@ const Writer = struct { |
| 1483 | .dbg_stmt_node, | 1496 | .dbg_stmt_node, |
| 1484 | .ret_ptr, | 1497 | .ret_ptr, |
| 1485 | .ret_type, | 1498 | .ret_type, |
| 1499 | .repeat, | ||
| 1500 | .repeat_inline, | ||
| 1486 | => try self.writeNode(stream, inst), | 1501 | => try self.writeNode(stream, inst), |
| 1487 | 1502 | ||
| 1488 | .decl_ref, | 1503 | .decl_ref, |
| ... | @@ -1506,8 +1521,6 @@ const Writer = struct { | ... | @@ -1506,8 +1521,6 @@ const Writer = struct { |
| 1506 | .bitcast_result_ptr, | 1521 | .bitcast_result_ptr, |
| 1507 | .error_union_type, | 1522 | .error_union_type, |
| 1508 | .error_set, | 1523 | .error_set, |
| 1509 | .store, | ||
| 1510 | .store_to_block_ptr, | ||
| 1511 | .store_to_inferred_ptr, | 1524 | .store_to_inferred_ptr, |
| 1512 | => try stream.writeAll("TODO)"), | 1525 | => try stream.writeAll("TODO)"), |
| 1513 | } | 1526 | } |
| ... | @@ -1772,6 +1785,15 @@ const Writer = struct { | ... | @@ -1772,6 +1785,15 @@ const Writer = struct { |
| 1772 | try self.writeSrc(stream, int_type.src()); | 1785 | try self.writeSrc(stream, int_type.src()); |
| 1773 | } | 1786 | } |
| 1774 | 1787 | ||
| 1788 | fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1789 | const inst_data = self.code.instructions.items(.data)[inst].@"break"; | ||
| 1790 | |||
| 1791 | try self.writeInstIndex(stream, inst_data.block_inst); | ||
| 1792 | try stream.writeAll(", "); | ||
| 1793 | try self.writeInstRef(stream, inst_data.operand); | ||
| 1794 | try stream.writeAll(")"); | ||
| 1795 | } | ||
| 1796 | |||
| 1775 | fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void { | 1797 | fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1776 | const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; | 1798 | const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; |
| 1777 | const safety_str = if (inst_data.safety) "safe" else "unsafe"; | 1799 | const safety_str = if (inst_data.safety) "safe" else "unsafe"; |