authorgravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-10-02 08:06:26-04:00
committergravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-10-02 08:06:26-04:00
loga3842cbafd25c29dd46954acda6cd7e3dfd18243
treea7c5e0f9f283bd5fa8b758390cf9d94de7f23c83
parenta1c802cbba07f2fdb009867393d3f39a091d939f

astgen.zig: make switchExpr generate cases in source order to keep source cursor increasing monotonically


1 files changed, 80 insertions(+), 118 deletions(-)

src/AstGen.zig+80-118
...@@ -5936,10 +5936,11 @@ fn switchExpr(...@@ -5936,10 +5936,11 @@ fn switchExpr(
5936 const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node);5936 const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node);
5937 const item_rl: ResultLoc = .{ .ty = operand_ty_inst };5937 const item_rl: ResultLoc = .{ .ty = operand_ty_inst };
59385938
5939 // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti.5939 // These contain the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti.
5940 // This is the header as well as the optional else prong body, as well as all the5940 // This is the optional else prong body.
5941 // scalar cases.5941 var special_case_payload = ArrayListUnmanaged(u32){};
5942 // At the end we will memcpy this into place.5942 defer special_case_payload.deinit(gpa);
5943 // This is all the scalar cases.
5943 var scalar_cases_payload = ArrayListUnmanaged(u32){};5944 var scalar_cases_payload = ArrayListUnmanaged(u32){};
5944 defer scalar_cases_payload.deinit(gpa);5945 defer scalar_cases_payload.deinit(gpa);
5945 // Same deal, but this is only the `extra` data for the multi cases.5946 // Same deal, but this is only the `extra` data for the multi cases.
...@@ -5957,86 +5958,10 @@ fn switchExpr(...@@ -5957,86 +5958,10 @@ fn switchExpr(
5957 var case_scope = parent_gz.makeSubBlock(&block_scope.base);5958 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
5958 defer case_scope.instructions.deinit(gpa);5959 defer case_scope.instructions.deinit(gpa);
59595960
5960 // Do the else/`_` first because it goes first in the payload.5961 // In this pass we generate all the item and prong expressions.
5961 var capture_val_scope: Scope.LocalVal = undefined;
5962 if (special_node != 0) {
5963 const case = switch (node_tags[special_node]) {
5964 .switch_case_one => tree.switchCaseOne(special_node),
5965 .switch_case => tree.switchCase(special_node),
5966 else => unreachable,
5967 };
5968 const sub_scope = blk: {
5969 const payload_token = case.payload_token orelse break :blk &case_scope.base;
5970 const ident = if (token_tags[payload_token] == .asterisk)
5971 payload_token + 1
5972 else
5973 payload_token;
5974 const is_ptr = ident != payload_token;
5975 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
5976 if (is_ptr) {
5977 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
5978 }
5979 break :blk &case_scope.base;
5980 }
5981 const capture_tag: Zir.Inst.Tag = if (is_ptr)
5982 .switch_capture_else_ref
5983 else
5984 .switch_capture_else;
5985 const capture = try case_scope.add(.{
5986 .tag = capture_tag,
5987 .data = .{ .switch_capture = .{
5988 .switch_inst = switch_block,
5989 .prong_index = undefined,
5990 } },
5991 });
5992 const capture_name = try astgen.identAsString(payload_token);
5993 capture_val_scope = .{
5994 .parent = &case_scope.base,
5995 .gen_zir = &case_scope,
5996 .name = capture_name,
5997 .inst = capture,
5998 .token_src = payload_token,
5999 .id_cat = .@"capture",
6000 };
6001 break :blk &capture_val_scope.base;
6002 };
6003 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
6004 try checkUsed(parent_gz, &case_scope.base, sub_scope);
6005 if (!parent_gz.refIsNoReturn(case_result)) {
6006 block_scope.break_count += 1;
6007 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
6008 }
6009 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
6010 try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len +
6011 3 + // operand, scalar_cases_len, else body len
6012 @boolToInt(multi_cases_len != 0));
6013 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
6014 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
6015 if (multi_cases_len != 0) {
6016 scalar_cases_payload.appendAssumeCapacity(multi_cases_len);
6017 }
6018 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
6019 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
6020 } else {
6021 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
6022 try scalar_cases_payload.ensureUnusedCapacity(
6023 gpa,
6024 @as(usize, 2) + // operand, scalar_cases_len
6025 @boolToInt(multi_cases_len != 0),
6026 );
6027 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
6028 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
6029 if (multi_cases_len != 0) {
6030 scalar_cases_payload.appendAssumeCapacity(multi_cases_len);
6031 }
6032 }
6033
6034 // In this pass we generate all the item and prong expressions except the special case.
6035 var multi_case_index: u32 = 0;5962 var multi_case_index: u32 = 0;
6036 var scalar_case_index: u32 = 0;5963 var scalar_case_index: u32 = 0;
6037 for (case_nodes) |case_node| {5964 for (case_nodes) |case_node| {
6038 if (case_node == special_node)
6039 continue;
6040 const case = switch (node_tags[case_node]) {5965 const case = switch (node_tags[case_node]) {
6041 .switch_case_one => tree.switchCaseOne(case_node),5966 .switch_case_one => tree.switchCaseOne(case_node),
6042 .switch_case => tree.switchCase(case_node),5967 .switch_case => tree.switchCase(case_node),
...@@ -6046,9 +5971,10 @@ fn switchExpr(...@@ -6046,9 +5971,10 @@ fn switchExpr(
6046 // Reset the scope.5971 // Reset the scope.
6047 case_scope.instructions.shrinkRetainingCapacity(0);5972 case_scope.instructions.shrinkRetainingCapacity(0);
60485973
6049 const is_multi_case = case.ast.values.len != 1 or5974 const is_multi_case = case.ast.values.len > 1 or
6050 node_tags[case.ast.values[0]] == .switch_range;5975 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range);
60515976
5977 var capture_val_scope: Scope.LocalVal = undefined;
6052 const sub_scope = blk: {5978 const sub_scope = blk: {
6053 const payload_token = case.payload_token orelse break :blk &case_scope.base;5979 const payload_token = case.payload_token orelse break :blk &case_scope.base;
6054 const ident = if (token_tags[payload_token] == .asterisk)5980 const ident = if (token_tags[payload_token] == .asterisk)
...@@ -6062,28 +5988,42 @@ fn switchExpr(...@@ -6062,28 +5988,42 @@ fn switchExpr(
6062 }5988 }
6063 break :blk &case_scope.base;5989 break :blk &case_scope.base;
6064 }5990 }
6065 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);5991 const capture = if (case_node == special_node) capture: {
6066 const is_ptr_bits: u2 = @boolToInt(is_ptr);5992 const capture_tag: Zir.Inst.Tag = if (is_ptr)
6067 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {5993 .switch_capture_else_ref
6068 0b00 => .switch_capture,5994 else
6069 0b01 => .switch_capture_ref,5995 .switch_capture_else;
6070 0b10 => .switch_capture_multi,5996 break :capture try case_scope.add(.{
6071 0b11 => .switch_capture_multi_ref,5997 .tag = capture_tag,
6072 };5998 .data = .{ .switch_capture = .{
6073 const capture_index = if (is_multi_case) ci: {5999 .switch_inst = switch_block,
6074 multi_case_index += 1;6000 .prong_index = undefined,
6075 break :ci multi_case_index - 1;6001 } },
6076 } else ci: {6002 });
6077 scalar_case_index += 1;6003 } else capture: {
6078 break :ci scalar_case_index - 1;6004 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
6005 const is_ptr_bits: u2 = @boolToInt(is_ptr);
6006 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {
6007 0b00 => .switch_capture,
6008 0b01 => .switch_capture_ref,
6009 0b10 => .switch_capture_multi,
6010 0b11 => .switch_capture_multi_ref,
6011 };
6012 const capture_index = if (is_multi_case) ci: {
6013 multi_case_index += 1;
6014 break :ci multi_case_index - 1;
6015 } else ci: {
6016 scalar_case_index += 1;
6017 break :ci scalar_case_index - 1;
6018 };
6019 break :capture try case_scope.add(.{
6020 .tag = capture_tag,
6021 .data = .{ .switch_capture = .{
6022 .switch_inst = switch_block,
6023 .prong_index = capture_index,
6024 } },
6025 });
6079 };6026 };
6080 const capture = try case_scope.add(.{
6081 .tag = capture_tag,
6082 .data = .{ .switch_capture = .{
6083 .switch_inst = switch_block,
6084 .prong_index = capture_index,
6085 } },
6086 });
6087 const capture_name = try astgen.identAsString(ident);6027 const capture_name = try astgen.identAsString(ident);
6088 capture_val_scope = .{6028 capture_val_scope = .{
6089 .parent = &case_scope.base,6029 .parent = &case_scope.base,
...@@ -6135,6 +6075,17 @@ fn switchExpr(...@@ -6135,6 +6075,17 @@ fn switchExpr(
6135 multi_cases_payload.items[header_index + 1] = ranges_len;6075 multi_cases_payload.items[header_index + 1] = ranges_len;
6136 multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len);6076 multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len);
6137 try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items);6077 try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items);
6078 } else if (case_node == special_node) {
6079 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
6080 try checkUsed(parent_gz, &case_scope.base, sub_scope);
6081 if (!parent_gz.refIsNoReturn(case_result)) {
6082 block_scope.break_count += 1;
6083 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
6084 }
6085 try special_case_payload.ensureUnusedCapacity(gpa, 1 + // body_len
6086 case_scope.instructions.items.len);
6087 special_case_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
6088 special_case_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
6138 } else {6089 } else {
6139 const item_node = case.ast.values[0];6090 const item_node = case.ast.values[0];
6140 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);6091 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
...@@ -6144,7 +6095,7 @@ fn switchExpr(...@@ -6144,7 +6095,7 @@ fn switchExpr(
6144 block_scope.break_count += 1;6095 block_scope.break_count += 1;
6145 _ = try case_scope.addBreak(.@"break", switch_block, case_result);6096 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
6146 }6097 }
6147 try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 +6098 try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 + // item + body_len
6148 case_scope.instructions.items.len);6099 case_scope.instructions.items.len);
6149 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));6100 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));
6150 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));6101 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
...@@ -6181,8 +6132,18 @@ fn switchExpr(...@@ -6181,8 +6132,18 @@ fn switchExpr(
6181 const payload_index = astgen.extra.items.len;6132 const payload_index = astgen.extra.items.len;
6182 const zir_datas = astgen.instructions.items(.data);6133 const zir_datas = astgen.instructions.items(.data);
6183 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);6134 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);
6184 try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len +6135 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
6136 try astgen.extra.ensureUnusedCapacity(gpa,
6137 @as(usize, 2) + // operand, scalar_cases_len
6138 @boolToInt(multi_cases_len != 0) +
6139 special_case_payload.items.len +
6140 scalar_cases_payload.items.len +
6185 multi_cases_payload.items.len);6141 multi_cases_payload.items.len);
6142 astgen.extra.appendAssumeCapacity(@enumToInt(operand));
6143 astgen.extra.appendAssumeCapacity(scalar_cases_len);
6144 if (multi_cases_len != 0) {
6145 astgen.extra.appendAssumeCapacity(multi_cases_len);
6146 }
6186 const strat = rl.strategy(&block_scope);6147 const strat = rl.strategy(&block_scope);
6187 switch (strat.tag) {6148 switch (strat.tag) {
6188 .break_operand => {6149 .break_operand => {
...@@ -6190,6 +6151,7 @@ fn switchExpr(...@@ -6190,6 +6151,7 @@ fn switchExpr(
6190 // `elide_store_to_block_ptr_instructions` will either be true,6151 // `elide_store_to_block_ptr_instructions` will either be true,
6191 // or all prongs are noreturn.6152 // or all prongs are noreturn.
6192 if (!strat.elide_store_to_block_ptr_instructions) {6153 if (!strat.elide_store_to_block_ptr_instructions) {
6154 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items);
6193 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);6155 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
6194 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);6156 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
6195 return indexToRef(switch_block);6157 return indexToRef(switch_block);
...@@ -6205,32 +6167,30 @@ fn switchExpr(...@@ -6205,32 +6167,30 @@ fn switchExpr(
6205 // it as the break operand.6167 // it as the break operand.
62066168
6207 var extra_index: usize = 0;6169 var extra_index: usize = 0;
6208 extra_index += 2;
6209 extra_index += @boolToInt(multi_cases_len != 0);
6210 if (special_prong != .none) special_prong: {6170 if (special_prong != .none) special_prong: {
6211 const body_len_index = extra_index;6171 const body_len_index = extra_index;
6212 const body_len = scalar_cases_payload.items[extra_index];6172 const body_len = special_case_payload.items[extra_index];
6213 extra_index += 1;6173 extra_index += 1;
6214 if (body_len < 2) {6174 if (body_len < 2) {
6215 extra_index += body_len;6175 extra_index += body_len;
6216 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);6176 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6217 break :special_prong;6177 break :special_prong;
6218 }6178 }
6219 extra_index += body_len - 2;6179 extra_index += body_len - 2;
6220 const store_inst = scalar_cases_payload.items[extra_index];6180 const store_inst = special_case_payload.items[extra_index];
6221 if (zir_tags[store_inst] != .store_to_block_ptr or6181 if (zir_tags[store_inst] != .store_to_block_ptr or
6222 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)6182 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
6223 {6183 {
6224 extra_index += 2;6184 extra_index += 2;
6225 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);6185 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6226 break :special_prong;6186 break :special_prong;
6227 }6187 }
6228 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);6188 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
6229 if (block_scope.rl_ty_inst != .none) {6189 if (block_scope.rl_ty_inst != .none) {
6230 extra_index += 1;6190 extra_index += 1;
6231 const break_inst = scalar_cases_payload.items[extra_index];6191 const break_inst = special_case_payload.items[extra_index];
6232 extra_index += 1;6192 extra_index += 1;
6233 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);6193 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6234 zir_tags[store_inst] = .as;6194 zir_tags[store_inst] = .as;
6235 zir_datas[store_inst].bin = .{6195 zir_datas[store_inst].bin = .{
6236 .lhs = block_scope.rl_ty_inst,6196 .lhs = block_scope.rl_ty_inst,
...@@ -6238,15 +6198,16 @@ fn switchExpr(...@@ -6238,15 +6198,16 @@ fn switchExpr(
6238 };6198 };
6239 zir_datas[break_inst].@"break".operand = indexToRef(store_inst);6199 zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
6240 } else {6200 } else {
6241 scalar_cases_payload.items[body_len_index] -= 1;6201 special_case_payload.items[body_len_index] -= 1;
6242 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);6202 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6243 extra_index += 1;6203 extra_index += 1;
6244 astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]);6204 astgen.extra.appendAssumeCapacity(special_case_payload.items[extra_index]);
6245 extra_index += 1;6205 extra_index += 1;
6246 }6206 }
6247 } else {6207 } else {
6248 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);6208 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6249 }6209 }
6210 extra_index = 0;
6250 var scalar_i: u32 = 0;6211 var scalar_i: u32 = 0;
6251 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {6212 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
6252 const start_index = extra_index;6213 const start_index = extra_index;
...@@ -6343,6 +6304,7 @@ fn switchExpr(...@@ -6343,6 +6304,7 @@ fn switchExpr(
6343 },6304 },
6344 .break_void => {6305 .break_void => {
6345 assert(!strat.elide_store_to_block_ptr_instructions);6306 assert(!strat.elide_store_to_block_ptr_instructions);
6307 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items);
6346 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);6308 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
6347 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);6309 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
6348 // Modify all the terminating instruction tags to become `break` variants.6310 // Modify all the terminating instruction tags to become `break` variants.