authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-03-28 19:53:38+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-03-28 19:53:38+02:00
logd123a5ec67b517c6e2a7e7005575a745b511ea92
tree9cd49fe5785231609682b2a107e08ed4f0a2434e
parent402f87a213b9f3d5e19d5a1d412d8963957d8849
signature Commit is signed but in an unrecognized format.

AstGen: scope result location related functions


2 files changed, 76 insertions(+), 76 deletions(-)

src/AstGen.zig+44-75
...@@ -138,7 +138,7 @@ pub const ResultLoc = union(enum) {...@@ -138,7 +138,7 @@ pub const ResultLoc = union(enum) {
138 /// There is a pointer for the expression to store its result into, however, its type138 /// There is a pointer for the expression to store its result into, however, its type
139 /// is inferred based on peer type resolution for a `zir.Inst.Block`.139 /// is inferred based on peer type resolution for a `zir.Inst.Block`.
140 /// The result instruction from the expression must be ignored.140 /// The result instruction from the expression must be ignored.
141 block_ptr: *Module.Scope.GenZir,141 block_ptr: *Scope.GenZir,
142142
143 pub const Strategy = struct {143 pub const Strategy = struct {
144 elide_store_to_block_ptr_instructions: bool,144 elide_store_to_block_ptr_instructions: bool,
...@@ -154,6 +154,41 @@ pub const ResultLoc = union(enum) {...@@ -154,6 +154,41 @@ pub const ResultLoc = union(enum) {
154 break_operand,154 break_operand,
155 };155 };
156 };156 };
157
158 fn strategy(rl: ResultLoc, block_scope: *Scope.GenZir) Strategy {
159 var elide_store_to_block_ptr_instructions = false;
160 switch (rl) {
161 // In this branch there will not be any store_to_block_ptr instructions.
162 .discard, .none, .ty, .ref => return .{
163 .tag = .break_operand,
164 .elide_store_to_block_ptr_instructions = false,
165 },
166 // The pointer got passed through to the sub-expressions, so we will use
167 // break_void here.
168 // In this branch there will not be any store_to_block_ptr instructions.
169 .ptr => return .{
170 .tag = .break_void,
171 .elide_store_to_block_ptr_instructions = false,
172 },
173 .inferred_ptr, .bitcasted_ptr, .block_ptr => {
174 if (block_scope.rvalue_rl_count == block_scope.break_count) {
175 // Neither prong of the if consumed the result location, so we can
176 // use break instructions to create an rvalue.
177 return .{
178 .tag = .break_operand,
179 .elide_store_to_block_ptr_instructions = true,
180 };
181 } else {
182 // Allow the store_to_block_ptr instructions to remain so that
183 // semantic analysis can turn them into bitcasts.
184 return .{
185 .tag = .break_void,
186 .elide_store_to_block_ptr_instructions = false,
187 };
188 }
189 },
190 }
191 }
157};192};
158193
159pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!zir.Inst.Ref {194pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!zir.Inst.Ref {
...@@ -989,7 +1024,7 @@ fn labeledBlockExpr(...@@ -989,7 +1024,7 @@ fn labeledBlockExpr(
989 .block_inst = block_inst,1024 .block_inst = block_inst,
990 }),1025 }),
991 };1026 };
992 setBlockResultLoc(&block_scope, rl);1027 block_scope.setBreakResultLoc(rl);
993 defer block_scope.instructions.deinit(mod.gpa);1028 defer block_scope.instructions.deinit(mod.gpa);
994 defer block_scope.labeled_breaks.deinit(mod.gpa);1029 defer block_scope.labeled_breaks.deinit(mod.gpa);
995 defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa);1030 defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa);
...@@ -1003,7 +1038,7 @@ fn labeledBlockExpr(...@@ -1003,7 +1038,7 @@ fn labeledBlockExpr(
1003 const zir_tags = gz.astgen.instructions.items(.tag);1038 const zir_tags = gz.astgen.instructions.items(.tag);
1004 const zir_datas = gz.astgen.instructions.items(.data);1039 const zir_datas = gz.astgen.instructions.items(.data);
10051040
1006 const strat = rlStrategy(rl, &block_scope);1041 const strat = rl.strategy(&block_scope);
1007 switch (strat.tag) {1042 switch (strat.tag) {
1008 .break_void => {1043 .break_void => {
1009 // The code took advantage of the result location as a pointer.1044 // The code took advantage of the result location as a pointer.
...@@ -1740,7 +1775,7 @@ fn orelseCatchExpr(...@@ -1740,7 +1775,7 @@ fn orelseCatchExpr(
1740 .force_comptime = parent_gz.force_comptime,1775 .force_comptime = parent_gz.force_comptime,
1741 .instructions = .{},1776 .instructions = .{},
1742 };1777 };
1743 setBlockResultLoc(&block_scope, rl);1778 block_scope.setBreakResultLoc(rl);
1744 defer block_scope.instructions.deinit(mod.gpa);1779 defer block_scope.instructions.deinit(mod.gpa);
17451780
1746 // This could be a pointer or value depending on the `operand_rl` parameter.1781 // This could be a pointer or value depending on the `operand_rl` parameter.
...@@ -1856,7 +1891,7 @@ fn finishThenElseBlock(...@@ -1856,7 +1891,7 @@ fn finishThenElseBlock(
1856) InnerError!zir.Inst.Ref {1891) InnerError!zir.Inst.Ref {
1857 // We now have enough information to decide whether the result instruction should1892 // We now have enough information to decide whether the result instruction should
1858 // be communicated via result location pointer or break instructions.1893 // be communicated via result location pointer or break instructions.
1859 const strat = rlStrategy(rl, block_scope);1894 const strat = rl.strategy(block_scope);
1860 const astgen = block_scope.astgen;1895 const astgen = block_scope.astgen;
1861 switch (strat.tag) {1896 switch (strat.tag) {
1862 .break_void => {1897 .break_void => {
...@@ -2035,7 +2070,7 @@ fn ifExpr(...@@ -2035,7 +2070,7 @@ fn ifExpr(
2035 .force_comptime = parent_gz.force_comptime,2070 .force_comptime = parent_gz.force_comptime,
2036 .instructions = .{},2071 .instructions = .{},
2037 };2072 };
2038 setBlockResultLoc(&block_scope, rl);2073 block_scope.setBreakResultLoc(rl);
2039 defer block_scope.instructions.deinit(mod.gpa);2074 defer block_scope.instructions.deinit(mod.gpa);
20402075
2041 const cond = c: {2076 const cond = c: {
...@@ -2190,7 +2225,7 @@ fn whileExpr(...@@ -2190,7 +2225,7 @@ fn whileExpr(
2190 .force_comptime = parent_gz.force_comptime,2225 .force_comptime = parent_gz.force_comptime,
2191 .instructions = .{},2226 .instructions = .{},
2192 };2227 };
2193 setBlockResultLoc(&loop_scope, rl);2228 loop_scope.setBreakResultLoc(rl);
2194 defer loop_scope.instructions.deinit(mod.gpa);2229 defer loop_scope.instructions.deinit(mod.gpa);
21952230
2196 var continue_scope: Scope.GenZir = .{2231 var continue_scope: Scope.GenZir = .{
...@@ -2338,7 +2373,7 @@ fn forExpr(...@@ -2338,7 +2373,7 @@ fn forExpr(
2338 .force_comptime = parent_gz.force_comptime,2373 .force_comptime = parent_gz.force_comptime,
2339 .instructions = .{},2374 .instructions = .{},
2340 };2375 };
2341 setBlockResultLoc(&loop_scope, rl);2376 loop_scope.setBreakResultLoc(rl);
2342 defer loop_scope.instructions.deinit(mod.gpa);2377 defer loop_scope.instructions.deinit(mod.gpa);
23432378
2344 var cond_scope: Scope.GenZir = .{2379 var cond_scope: Scope.GenZir = .{
...@@ -2520,7 +2555,7 @@ fn switchExpr(...@@ -2520,7 +2555,7 @@ fn switchExpr(
2520 .force_comptime = parent_gz.force_comptime,2555 .force_comptime = parent_gz.force_comptime,
2521 .instructions = .{},2556 .instructions = .{},
2522 };2557 };
2523 setBlockResultLoc(&block_scope, rl);2558 block_scope.setBreakResultLoc(rl);
2524 defer block_scope.instructions.deinit(mod.gpa);2559 defer block_scope.instructions.deinit(mod.gpa);
25252560
2526 var items = std.ArrayList(zir.Inst.Ref).init(mod.gpa);2561 var items = std.ArrayList(zir.Inst.Ref).init(mod.gpa);
...@@ -3911,69 +3946,3 @@ fn rvalue(...@@ -3911,69 +3946,3 @@ fn rvalue(
3911 },3946 },
3912 }3947 }
3913}3948}
3914
3915fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZir) ResultLoc.Strategy {
3916 var elide_store_to_block_ptr_instructions = false;
3917 switch (rl) {
3918 // In this branch there will not be any store_to_block_ptr instructions.
3919 .discard, .none, .ty, .ref => return .{
3920 .tag = .break_operand,
3921 .elide_store_to_block_ptr_instructions = false,
3922 },
3923 // The pointer got passed through to the sub-expressions, so we will use
3924 // break_void here.
3925 // In this branch there will not be any store_to_block_ptr instructions.
3926 .ptr => return .{
3927 .tag = .break_void,
3928 .elide_store_to_block_ptr_instructions = false,
3929 },
3930 .inferred_ptr, .bitcasted_ptr, .block_ptr => {
3931 if (block_scope.rvalue_rl_count == block_scope.break_count) {
3932 // Neither prong of the if consumed the result location, so we can
3933 // use break instructions to create an rvalue.
3934 return .{
3935 .tag = .break_operand,
3936 .elide_store_to_block_ptr_instructions = true,
3937 };
3938 } else {
3939 // Allow the store_to_block_ptr instructions to remain so that
3940 // semantic analysis can turn them into bitcasts.
3941 return .{
3942 .tag = .break_void,
3943 .elide_store_to_block_ptr_instructions = false,
3944 };
3945 }
3946 },
3947 }
3948}
3949
3950fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {
3951 // Depending on whether the result location is a pointer or value, different
3952 // ZIR needs to be generated. In the former case we rely on storing to the
3953 // pointer to communicate the result, and use breakvoid; in the latter case
3954 // the block break instructions will have the result values.
3955 // One more complication: when the result location is a pointer, we detect
3956 // the scenario where the result location is not consumed. In this case
3957 // we emit ZIR for the block break instructions to have the result values,
3958 // and then rvalue() on that to pass the value to the result location.
3959 switch (parent_rl) {
3960 .discard, .none, .ty, .ptr, .ref => {
3961 block_scope.break_result_loc = parent_rl;
3962 },
3963
3964 .inferred_ptr => |ptr| {
3965 block_scope.rl_ptr = ptr;
3966 block_scope.break_result_loc = .{ .block_ptr = block_scope };
3967 },
3968
3969 .bitcasted_ptr => |ptr| {
3970 block_scope.rl_ptr = ptr;
3971 block_scope.break_result_loc = .{ .block_ptr = block_scope };
3972 },
3973
3974 .block_ptr => |parent_block_scope| {
3975 block_scope.rl_ptr = parent_block_scope.rl_ptr;
3976 block_scope.break_result_loc = .{ .block_ptr = block_scope };
3977 },
3978 }
3979}
src/Module.zig+32-1
...@@ -920,7 +920,7 @@ pub const Scope = struct {...@@ -920,7 +920,7 @@ pub const Scope = struct {
920 label: ?Label = null,920 label: ?Label = null,
921 break_block: zir.Inst.Index = 0,921 break_block: zir.Inst.Index = 0,
922 continue_block: zir.Inst.Index = 0,922 continue_block: zir.Inst.Index = 0,
923 /// Only valid when setBlockResultLoc is called.923 /// Only valid when setBreakResultLoc is called.
924 break_result_loc: AstGen.ResultLoc = undefined,924 break_result_loc: AstGen.ResultLoc = undefined,
925 /// When a block has a pointer result location, here it is.925 /// When a block has a pointer result location, here it is.
926 rl_ptr: zir.Inst.Ref = .none,926 rl_ptr: zir.Inst.Ref = .none,
...@@ -973,6 +973,37 @@ pub const Scope = struct {...@@ -973,6 +973,37 @@ pub const Scope = struct {
973 return &gz.astgen.decl.container.file_scope.tree;973 return &gz.astgen.decl.container.file_scope.tree;
974 }974 }
975975
976 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
977 // Depending on whether the result location is a pointer or value, different
978 // ZIR needs to be generated. In the former case we rely on storing to the
979 // pointer to communicate the result, and use breakvoid; in the latter case
980 // the block break instructions will have the result values.
981 // One more complication: when the result location is a pointer, we detect
982 // the scenario where the result location is not consumed. In this case
983 // we emit ZIR for the block break instructions to have the result values,
984 // and then rvalue() on that to pass the value to the result location.
985 switch (parent_rl) {
986 .discard, .none, .ty, .ptr, .ref => {
987 gz.break_result_loc = parent_rl;
988 },
989
990 .inferred_ptr => |ptr| {
991 gz.rl_ptr = ptr;
992 gz.break_result_loc = .{ .block_ptr = gz };
993 },
994
995 .bitcasted_ptr => |ptr| {
996 gz.rl_ptr = ptr;
997 gz.break_result_loc = .{ .block_ptr = gz };
998 },
999
1000 .block_ptr => |parent_block_scope| {
1001 gz.rl_ptr = parent_block_scope.rl_ptr;
1002 gz.break_result_loc = .{ .block_ptr = gz };
1003 },
1004 }
1005 }
1006
976 pub fn setBoolBrBody(gz: GenZir, inst: zir.Inst.Index) !void {1007 pub fn setBoolBrBody(gz: GenZir, inst: zir.Inst.Index) !void {
977 const gpa = gz.astgen.mod.gpa;1008 const gpa = gz.astgen.mod.gpa;
978 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1009 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +