| ... | ... | @@ -5936,10 +5936,11 @@ fn switchExpr( |
| 5936 | 5936 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); |
| 5937 | 5937 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; |
| 5938 | 5938 | |
| 5939 | | // Contains 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 the |
| 5941 | | // scalar cases. |
| 5942 | | // At the end we will memcpy this into place. |
| 5939 | // These contain the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. |
| 5940 | // This is the optional else prong body. |
| 5941 | var special_case_payload = ArrayListUnmanaged(u32){}; |
| 5942 | defer special_case_payload.deinit(gpa); |
| 5943 | // This is all the scalar cases. |
| 5943 | 5944 | var scalar_cases_payload = ArrayListUnmanaged(u32){}; |
| 5944 | 5945 | defer scalar_cases_payload.deinit(gpa); |
| 5945 | 5946 | // Same deal, but this is only the `extra` data for the multi cases. |
| ... | ... | @@ -5957,86 +5958,10 @@ fn switchExpr( |
| 5957 | 5958 | var case_scope = parent_gz.makeSubBlock(&block_scope.base); |
| 5958 | 5959 | defer case_scope.instructions.deinit(gpa); |
| 5959 | 5960 | |
| 5960 | | // Do the else/`_` first because it goes first in the payload. |
| 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. |
| 5961 | // In this pass we generate all the item and prong expressions. |
| 6035 | 5962 | var multi_case_index: u32 = 0; |
| 6036 | 5963 | var scalar_case_index: u32 = 0; |
| 6037 | 5964 | for (case_nodes) |case_node| { |
| 6038 | | if (case_node == special_node) |
| 6039 | | continue; |
| 6040 | 5965 | const case = switch (node_tags[case_node]) { |
| 6041 | 5966 | .switch_case_one => tree.switchCaseOne(case_node), |
| 6042 | 5967 | .switch_case => tree.switchCase(case_node), |
| ... | ... | @@ -6046,9 +5971,10 @@ fn switchExpr( |
| 6046 | 5971 | // Reset the scope. |
| 6047 | 5972 | case_scope.instructions.shrinkRetainingCapacity(0); |
| 6048 | 5973 | |
| 6049 | | const is_multi_case = case.ast.values.len != 1 or |
| 6050 | | node_tags[case.ast.values[0]] == .switch_range; |
| 5974 | const is_multi_case = case.ast.values.len > 1 or |
| 5975 | (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range); |
| 6051 | 5976 | |
| 5977 | var capture_val_scope: Scope.LocalVal = undefined; |
| 6052 | 5978 | const sub_scope = blk: { |
| 6053 | 5979 | const payload_token = case.payload_token orelse break :blk &case_scope.base; |
| 6054 | 5980 | const ident = if (token_tags[payload_token] == .asterisk) |
| ... | ... | @@ -6062,28 +5988,42 @@ fn switchExpr( |
| 6062 | 5988 | } |
| 6063 | 5989 | break :blk &case_scope.base; |
| 6064 | 5990 | } |
| 6065 | | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); |
| 6066 | | const is_ptr_bits: u2 = @boolToInt(is_ptr); |
| 6067 | | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { |
| 6068 | | 0b00 => .switch_capture, |
| 6069 | | 0b01 => .switch_capture_ref, |
| 6070 | | 0b10 => .switch_capture_multi, |
| 6071 | | 0b11 => .switch_capture_multi_ref, |
| 6072 | | }; |
| 6073 | | const capture_index = if (is_multi_case) ci: { |
| 6074 | | multi_case_index += 1; |
| 6075 | | break :ci multi_case_index - 1; |
| 6076 | | } else ci: { |
| 6077 | | scalar_case_index += 1; |
| 6078 | | break :ci scalar_case_index - 1; |
| 5991 | const capture = if (case_node == special_node) capture: { |
| 5992 | const capture_tag: Zir.Inst.Tag = if (is_ptr) |
| 5993 | .switch_capture_else_ref |
| 5994 | else |
| 5995 | .switch_capture_else; |
| 5996 | break :capture try case_scope.add(.{ |
| 5997 | .tag = capture_tag, |
| 5998 | .data = .{ .switch_capture = .{ |
| 5999 | .switch_inst = switch_block, |
| 6000 | .prong_index = undefined, |
| 6001 | } }, |
| 6002 | }); |
| 6003 | } else capture: { |
| 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 | 6027 | const capture_name = try astgen.identAsString(ident); |
| 6088 | 6028 | capture_val_scope = .{ |
| 6089 | 6029 | .parent = &case_scope.base, |
| ... | ... | @@ -6135,6 +6075,17 @@ fn switchExpr( |
| 6135 | 6075 | multi_cases_payload.items[header_index + 1] = ranges_len; |
| 6136 | 6076 | multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len); |
| 6137 | 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 | 6089 | } else { |
| 6139 | 6090 | const item_node = case.ast.values[0]; |
| 6140 | 6091 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); |
| ... | ... | @@ -6144,7 +6095,7 @@ fn switchExpr( |
| 6144 | 6095 | block_scope.break_count += 1; |
| 6145 | 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 | 6099 | case_scope.instructions.items.len); |
| 6149 | 6100 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); |
| 6150 | 6101 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); |
| ... | ... | @@ -6181,8 +6132,18 @@ fn switchExpr( |
| 6181 | 6132 | const payload_index = astgen.extra.items.len; |
| 6182 | 6133 | const zir_datas = astgen.instructions.items(.data); |
| 6183 | 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 | 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 | 6147 | const strat = rl.strategy(&block_scope); |
| 6187 | 6148 | switch (strat.tag) { |
| 6188 | 6149 | .break_operand => { |
| ... | ... | @@ -6190,6 +6151,7 @@ fn switchExpr( |
| 6190 | 6151 | // `elide_store_to_block_ptr_instructions` will either be true, |
| 6191 | 6152 | // or all prongs are noreturn. |
| 6192 | 6153 | if (!strat.elide_store_to_block_ptr_instructions) { |
| 6154 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items); |
| 6193 | 6155 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); |
| 6194 | 6156 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); |
| 6195 | 6157 | return indexToRef(switch_block); |
| ... | ... | @@ -6205,32 +6167,30 @@ fn switchExpr( |
| 6205 | 6167 | // it as the break operand. |
| 6206 | 6168 | |
| 6207 | 6169 | var extra_index: usize = 0; |
| 6208 | | extra_index += 2; |
| 6209 | | extra_index += @boolToInt(multi_cases_len != 0); |
| 6210 | 6170 | if (special_prong != .none) special_prong: { |
| 6211 | 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 | 6173 | extra_index += 1; |
| 6214 | 6174 | if (body_len < 2) { |
| 6215 | 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 | 6177 | break :special_prong; |
| 6218 | 6178 | } |
| 6219 | 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 | 6181 | if (zir_tags[store_inst] != .store_to_block_ptr or |
| 6222 | 6182 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) |
| 6223 | 6183 | { |
| 6224 | 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 | 6186 | break :special_prong; |
| 6227 | 6187 | } |
| 6228 | 6188 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| 6229 | 6189 | if (block_scope.rl_ty_inst != .none) { |
| 6230 | 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 | 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 | 6194 | zir_tags[store_inst] = .as; |
| 6235 | 6195 | zir_datas[store_inst].bin = .{ |
| 6236 | 6196 | .lhs = block_scope.rl_ty_inst, |
| ... | ... | @@ -6238,15 +6198,16 @@ fn switchExpr( |
| 6238 | 6198 | }; |
| 6239 | 6199 | zir_datas[break_inst].@"break".operand = indexToRef(store_inst); |
| 6240 | 6200 | } else { |
| 6241 | | scalar_cases_payload.items[body_len_index] -= 1; |
| 6242 | | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| 6201 | special_case_payload.items[body_len_index] -= 1; |
| 6202 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]); |
| 6243 | 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 | 6205 | extra_index += 1; |
| 6246 | 6206 | } |
| 6247 | 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 | 6211 | var scalar_i: u32 = 0; |
| 6251 | 6212 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 6252 | 6213 | const start_index = extra_index; |
| ... | ... | @@ -6343,6 +6304,7 @@ fn switchExpr( |
| 6343 | 6304 | }, |
| 6344 | 6305 | .break_void => { |
| 6345 | 6306 | assert(!strat.elide_store_to_block_ptr_instructions); |
| 6307 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items); |
| 6346 | 6308 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); |
| 6347 | 6309 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); |
| 6348 | 6310 | // Modify all the terminating instruction tags to become `break` variants. |