Commit d123a5ec67

Isaac Freund <ifreund@ifreund.xyz>
2021-03-28 19:53:38
AstGen: scope result location related functions
1 parent 402f87a
Changed files (2)
src/AstGen.zig
@@ -138,7 +138,7 @@ pub const ResultLoc = union(enum) {
     /// There is a pointer for the expression to store its result into, however, its type
     /// is inferred based on peer type resolution for a `zir.Inst.Block`.
     /// The result instruction from the expression must be ignored.
-    block_ptr: *Module.Scope.GenZir,
+    block_ptr: *Scope.GenZir,
 
     pub const Strategy = struct {
         elide_store_to_block_ptr_instructions: bool,
@@ -154,6 +154,41 @@ pub const ResultLoc = union(enum) {
             break_operand,
         };
     };
+
+    fn strategy(rl: ResultLoc, block_scope: *Scope.GenZir) Strategy {
+        var elide_store_to_block_ptr_instructions = false;
+        switch (rl) {
+            // In this branch there will not be any store_to_block_ptr instructions.
+            .discard, .none, .ty, .ref => return .{
+                .tag = .break_operand,
+                .elide_store_to_block_ptr_instructions = false,
+            },
+            // The pointer got passed through to the sub-expressions, so we will use
+            // break_void here.
+            // In this branch there will not be any store_to_block_ptr instructions.
+            .ptr => return .{
+                .tag = .break_void,
+                .elide_store_to_block_ptr_instructions = false,
+            },
+            .inferred_ptr, .bitcasted_ptr, .block_ptr => {
+                if (block_scope.rvalue_rl_count == block_scope.break_count) {
+                    // Neither prong of the if consumed the result location, so we can
+                    // use break instructions to create an rvalue.
+                    return .{
+                        .tag = .break_operand,
+                        .elide_store_to_block_ptr_instructions = true,
+                    };
+                } else {
+                    // Allow the store_to_block_ptr instructions to remain so that
+                    // semantic analysis can turn them into bitcasts.
+                    return .{
+                        .tag = .break_void,
+                        .elide_store_to_block_ptr_instructions = false,
+                    };
+                }
+            },
+        }
+    }
 };
 
 pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!zir.Inst.Ref {
@@ -989,7 +1024,7 @@ fn labeledBlockExpr(
             .block_inst = block_inst,
         }),
     };
-    setBlockResultLoc(&block_scope, rl);
+    block_scope.setBreakResultLoc(rl);
     defer block_scope.instructions.deinit(mod.gpa);
     defer block_scope.labeled_breaks.deinit(mod.gpa);
     defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa);
@@ -1003,7 +1038,7 @@ fn labeledBlockExpr(
     const zir_tags = gz.astgen.instructions.items(.tag);
     const zir_datas = gz.astgen.instructions.items(.data);
 
-    const strat = rlStrategy(rl, &block_scope);
+    const strat = rl.strategy(&block_scope);
     switch (strat.tag) {
         .break_void => {
             // The code took advantage of the result location as a pointer.
@@ -1740,7 +1775,7 @@ fn orelseCatchExpr(
         .force_comptime = parent_gz.force_comptime,
         .instructions = .{},
     };
-    setBlockResultLoc(&block_scope, rl);
+    block_scope.setBreakResultLoc(rl);
     defer block_scope.instructions.deinit(mod.gpa);
 
     // This could be a pointer or value depending on the `operand_rl` parameter.
@@ -1856,7 +1891,7 @@ fn finishThenElseBlock(
 ) InnerError!zir.Inst.Ref {
     // We now have enough information to decide whether the result instruction should
     // be communicated via result location pointer or break instructions.
-    const strat = rlStrategy(rl, block_scope);
+    const strat = rl.strategy(block_scope);
     const astgen = block_scope.astgen;
     switch (strat.tag) {
         .break_void => {
@@ -2035,7 +2070,7 @@ fn ifExpr(
         .force_comptime = parent_gz.force_comptime,
         .instructions = .{},
     };
-    setBlockResultLoc(&block_scope, rl);
+    block_scope.setBreakResultLoc(rl);
     defer block_scope.instructions.deinit(mod.gpa);
 
     const cond = c: {
@@ -2190,7 +2225,7 @@ fn whileExpr(
         .force_comptime = parent_gz.force_comptime,
         .instructions = .{},
     };
-    setBlockResultLoc(&loop_scope, rl);
+    loop_scope.setBreakResultLoc(rl);
     defer loop_scope.instructions.deinit(mod.gpa);
 
     var continue_scope: Scope.GenZir = .{
@@ -2338,7 +2373,7 @@ fn forExpr(
         .force_comptime = parent_gz.force_comptime,
         .instructions = .{},
     };
-    setBlockResultLoc(&loop_scope, rl);
+    loop_scope.setBreakResultLoc(rl);
     defer loop_scope.instructions.deinit(mod.gpa);
 
     var cond_scope: Scope.GenZir = .{
@@ -2520,7 +2555,7 @@ fn switchExpr(
         .force_comptime = parent_gz.force_comptime,
         .instructions = .{},
     };
-    setBlockResultLoc(&block_scope, rl);
+    block_scope.setBreakResultLoc(rl);
     defer block_scope.instructions.deinit(mod.gpa);
 
     var items = std.ArrayList(zir.Inst.Ref).init(mod.gpa);
@@ -3911,69 +3946,3 @@ fn rvalue(
         },
     }
 }
-
-fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZir) ResultLoc.Strategy {
-    var elide_store_to_block_ptr_instructions = false;
-    switch (rl) {
-        // In this branch there will not be any store_to_block_ptr instructions.
-        .discard, .none, .ty, .ref => return .{
-            .tag = .break_operand,
-            .elide_store_to_block_ptr_instructions = false,
-        },
-        // The pointer got passed through to the sub-expressions, so we will use
-        // break_void here.
-        // In this branch there will not be any store_to_block_ptr instructions.
-        .ptr => return .{
-            .tag = .break_void,
-            .elide_store_to_block_ptr_instructions = false,
-        },
-        .inferred_ptr, .bitcasted_ptr, .block_ptr => {
-            if (block_scope.rvalue_rl_count == block_scope.break_count) {
-                // Neither prong of the if consumed the result location, so we can
-                // use break instructions to create an rvalue.
-                return .{
-                    .tag = .break_operand,
-                    .elide_store_to_block_ptr_instructions = true,
-                };
-            } else {
-                // Allow the store_to_block_ptr instructions to remain so that
-                // semantic analysis can turn them into bitcasts.
-                return .{
-                    .tag = .break_void,
-                    .elide_store_to_block_ptr_instructions = false,
-                };
-            }
-        },
-    }
-}
-
-fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {
-    // Depending on whether the result location is a pointer or value, different
-    // ZIR needs to be generated. In the former case we rely on storing to the
-    // pointer to communicate the result, and use breakvoid; in the latter case
-    // the block break instructions will have the result values.
-    // One more complication: when the result location is a pointer, we detect
-    // the scenario where the result location is not consumed. In this case
-    // we emit ZIR for the block break instructions to have the result values,
-    // and then rvalue() on that to pass the value to the result location.
-    switch (parent_rl) {
-        .discard, .none, .ty, .ptr, .ref => {
-            block_scope.break_result_loc = parent_rl;
-        },
-
-        .inferred_ptr => |ptr| {
-            block_scope.rl_ptr = ptr;
-            block_scope.break_result_loc = .{ .block_ptr = block_scope };
-        },
-
-        .bitcasted_ptr => |ptr| {
-            block_scope.rl_ptr = ptr;
-            block_scope.break_result_loc = .{ .block_ptr = block_scope };
-        },
-
-        .block_ptr => |parent_block_scope| {
-            block_scope.rl_ptr = parent_block_scope.rl_ptr;
-            block_scope.break_result_loc = .{ .block_ptr = block_scope };
-        },
-    }
-}
src/Module.zig
@@ -920,7 +920,7 @@ pub const Scope = struct {
         label: ?Label = null,
         break_block: zir.Inst.Index = 0,
         continue_block: zir.Inst.Index = 0,
-        /// Only valid when setBlockResultLoc is called.
+        /// Only valid when setBreakResultLoc is called.
         break_result_loc: AstGen.ResultLoc = undefined,
         /// When a block has a pointer result location, here it is.
         rl_ptr: zir.Inst.Ref = .none,
@@ -973,6 +973,37 @@ pub const Scope = struct {
             return &gz.astgen.decl.container.file_scope.tree;
         }
 
+        pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
+            // Depending on whether the result location is a pointer or value, different
+            // ZIR needs to be generated. In the former case we rely on storing to the
+            // pointer to communicate the result, and use breakvoid; in the latter case
+            // the block break instructions will have the result values.
+            // One more complication: when the result location is a pointer, we detect
+            // the scenario where the result location is not consumed. In this case
+            // we emit ZIR for the block break instructions to have the result values,
+            // and then rvalue() on that to pass the value to the result location.
+            switch (parent_rl) {
+                .discard, .none, .ty, .ptr, .ref => {
+                    gz.break_result_loc = parent_rl;
+                },
+
+                .inferred_ptr => |ptr| {
+                    gz.rl_ptr = ptr;
+                    gz.break_result_loc = .{ .block_ptr = gz };
+                },
+
+                .bitcasted_ptr => |ptr| {
+                    gz.rl_ptr = ptr;
+                    gz.break_result_loc = .{ .block_ptr = gz };
+                },
+
+                .block_ptr => |parent_block_scope| {
+                    gz.rl_ptr = parent_block_scope.rl_ptr;
+                    gz.break_result_loc = .{ .block_ptr = gz };
+                },
+            }
+        }
+
         pub fn setBoolBrBody(gz: GenZir, inst: zir.Inst.Index) !void {
             const gpa = gz.astgen.mod.gpa;
             try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +