Commit 63788b2a51

Veikka Tuominen <git@vexu.eu>
2022-02-24 22:45:49
stage2: change how stale `store_to_block_ptr`s are detected
Instead of explicitly setting lhs to .none, check if the lhs instruction was analyzed. This simpler approach also handles stores from nested blocks correctly.
1 parent 52a2aa1
Changed files (4)
src/AstGen.zig
@@ -1760,19 +1760,6 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
                     .block_ptr => {
                         const br = try parent_gz.addBreak(break_tag, block_inst, operand);
                         try block_gz.labeled_breaks.append(astgen.gpa, br);
-
-                        // if list grew as much as rvalue_rl_count, then a break
-                        // inside operand already saved the store_to_block_ptr
-                        const have_store_to_block = block_gz.rvalue_rl_count >
-                            block_gz.labeled_store_to_block_ptr_list.items.len;
-                        if (have_store_to_block) {
-                            const zir_tags = parent_gz.astgen.instructions.items(.tag);
-                            const zir_datas = parent_gz.astgen.instructions.items(.data);
-                            const store_inst = @intCast(u32, zir_tags.len - 2);
-                            assert(zir_tags[store_inst] == .store_to_block_ptr);
-                            assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr);
-                            try block_gz.labeled_store_to_block_ptr_list.append(astgen.gpa, store_inst);
-                        }
                     },
                     .ptr => {
                         // In this case we don't have any mechanism to intercept it;
@@ -1955,7 +1942,6 @@ fn labeledBlockExpr(
     block_scope.setBreakResultLoc(rl);
     defer block_scope.unstack();
     defer block_scope.labeled_breaks.deinit(astgen.gpa);
-    defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
 
     try blockExprStmts(&block_scope, &block_scope.base, statements);
 
@@ -1963,9 +1949,7 @@ fn labeledBlockExpr(
         try astgen.appendErrorTok(label_token, "unused block label", .{});
     }
 
-    const zir_tags = gz.astgen.instructions.items(.tag);
     const zir_datas = gz.astgen.instructions.items(.data);
-
     const strat = rl.strategy(&block_scope);
     switch (strat.tag) {
         .break_void => {
@@ -1981,11 +1965,6 @@ fn labeledBlockExpr(
         .break_operand => {
             // All break operands are values that did not use the result location pointer.
             if (strat.elide_store_to_block_ptr_instructions) {
-                for (block_scope.labeled_store_to_block_ptr_list.items) |inst| {
-                    // Mark as elided for removal below.
-                    assert(zir_tags[inst] == .store_to_block_ptr);
-                    zir_datas[inst].bin.lhs = .none;
-                }
                 try block_scope.setBlockBodyEliding(block_inst);
             } else {
                 try block_scope.setBlockBody(block_inst);
@@ -5322,7 +5301,6 @@ fn whileExpr(
     loop_scope.setBreakResultLoc(rl);
     defer loop_scope.unstack();
     defer loop_scope.labeled_breaks.deinit(astgen.gpa);
-    defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
 
     var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);
     defer continue_scope.unstack();
@@ -5573,7 +5551,6 @@ fn forExpr(
     loop_scope.setBreakResultLoc(rl);
     defer loop_scope.unstack();
     defer loop_scope.labeled_breaks.deinit(astgen.gpa);
-    defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
 
     var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
     defer cond_scope.unstack();
@@ -9553,10 +9530,6 @@ const GenZir = struct {
     /// Tracks `break :foo bar` instructions so they can possibly be elided later if
     /// the labeled block ends up not needing a result location pointer.
     labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{},
-    /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
-    /// so they can possibly be elided later if the labeled block ends up not needing
-    /// a result location pointer.
-    labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{},
 
     suspend_node: Ast.Node.Index = 0,
     nosuspend_node: Ast.Node.Index = 0,
src/Sema.zig
@@ -3247,12 +3247,10 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
     defer tracy.end();
 
     const bin_inst = sema.code.instructions.items(.data)[inst].bin;
-    if (bin_inst.lhs == .none) {
-        // This is an elided instruction, but AstGen was not smart enough
-        // to omit it.
+    const ptr = sema.inst_map.get(@enumToInt(bin_inst.lhs) - @as(u32, Zir.Inst.Ref.typed_value_map.len)) orelse {
+        // This is an elided instruction, but AstGen was unable to omit it.
         return;
-    }
-    const ptr = sema.resolveInst(bin_inst.lhs);
+    };
     const value = sema.resolveInst(bin_inst.rhs);
     const ptr_ty = try Type.ptr(sema.arena, .{
         .pointee_type = sema.typeOf(value),
test/behavior/bugs/10970.zig
@@ -0,0 +1,15 @@
+const builtin = @import("builtin");
+
+fn retOpt() ?u32 {
+    return null;
+}
+test {
+    var cond = true;
+    const opt = while (cond) {
+        if (retOpt()) |opt| {
+            break opt;
+        }
+        break 1;
+    } else 2;
+    _ = opt;
+}
test/behavior.zig
@@ -103,6 +103,7 @@ test {
     {
         // Tests that pass for stage1, llvm backend, C backend
         _ = @import("behavior/bugs/9584.zig");
+        _ = @import("behavior/bugs/10970.zig");
         _ = @import("behavior/cast_int.zig");
         _ = @import("behavior/eval.zig");
         _ = @import("behavior/int128.zig");