| ... | ... | @@ -7178,7 +7178,8 @@ fn switchExpr( |
| 7178 | 7178 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len + |
| 7179 | 7179 | @intFromBool(multi_cases_len != 0) + |
| 7180 | 7180 | @intFromBool(any_has_tag_capture) + |
| 7181 | | payloads.items.len - case_table_end); |
| 7181 | payloads.items.len - case_table_end + |
| 7182 | (case_table_end - case_table_start) * @typeInfo(Zir.Inst.As).Struct.fields.len); |
| 7182 | 7183 | |
| 7183 | 7184 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{ |
| 7184 | 7185 | .operand = raw_operand, |
| ... | ... | @@ -7205,82 +7206,108 @@ fn switchExpr( |
| 7205 | 7206 | zir_datas[switch_block].pl_node.payload_index = payload_index; |
| 7206 | 7207 | |
| 7207 | 7208 | const strat = ri.rl.strategy(&block_scope); |
| 7208 | | for (payloads.items[case_table_start..case_table_end], 0..) |start_index, i| { |
| 7209 | | var body_len_index = start_index; |
| 7210 | | var end_index = start_index; |
| 7211 | | const table_index = case_table_start + i; |
| 7212 | | if (table_index < scalar_case_table) { |
| 7213 | | end_index += 1; |
| 7214 | | } else if (table_index < multi_case_table) { |
| 7215 | | body_len_index += 1; |
| 7216 | | end_index += 2; |
| 7217 | | } else { |
| 7218 | | body_len_index += 2; |
| 7219 | | const items_len = payloads.items[start_index]; |
| 7220 | | const ranges_len = payloads.items[start_index + 1]; |
| 7221 | | end_index += 3 + items_len + 2 * ranges_len; |
| 7222 | | } |
| 7223 | | |
| 7224 | | const body_len = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(payloads.items[body_len_index])).body_len; |
| 7225 | | end_index += body_len; |
| 7226 | | |
| 7227 | | switch (strat.tag) { |
| 7228 | | .break_operand => blk: { |
| 7229 | | // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus |
| 7230 | | // `elide_store_to_block_ptr_instructions` will either be true, |
| 7231 | | // or all prongs are noreturn. |
| 7232 | | if (!strat.elide_store_to_block_ptr_instructions) |
| 7233 | | break :blk; |
| 7234 | | |
| 7235 | | // There will necessarily be a store_to_block_ptr for |
| 7236 | | // all prongs, except for prongs that ended with a noreturn instruction. |
| 7237 | | // Elide all the `store_to_block_ptr` instructions. |
| 7238 | | |
| 7239 | | // The break instructions need to have their operands coerced if the |
| 7240 | | // switch's result location is a `ty`. In this case we overwrite the |
| 7241 | | // `store_to_block_ptr` instruction with an `as` instruction and repurpose |
| 7242 | | // it as the break operand. |
| 7243 | | if (body_len < 2) |
| 7244 | | break :blk; |
| 7245 | | |
| 7246 | | var store_index = end_index - 2; |
| 7247 | | while (true) : (store_index -= 1) switch (zir_tags[payloads.items[store_index]]) { |
| 7248 | | .dbg_block_end, .dbg_block_begin, .dbg_stmt, .dbg_var_val, .dbg_var_ptr => {}, |
| 7249 | | else => break, |
| 7250 | | }; |
| 7251 | | const store_inst = payloads.items[store_index]; |
| 7252 | | if (zir_tags[store_inst] != .store_to_block_ptr or |
| 7253 | | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) |
| 7254 | | break :blk; |
| 7255 | | const break_inst = payloads.items[end_index - 1]; |
| 7256 | | if (block_scope.rl_ty_inst != .none) { |
| 7257 | | zir_tags[store_inst] = .as; |
| 7258 | | zir_datas[store_inst].bin = .{ |
| 7259 | | .lhs = block_scope.rl_ty_inst, |
| 7260 | | .rhs = zir_datas[break_inst].@"break".operand, |
| 7209 | inline for (.{ .body, .breaks }) |pass| { |
| 7210 | for (payloads.items[case_table_start..case_table_end], 0..) |start_index, i| { |
| 7211 | var body_len_index = start_index; |
| 7212 | var end_index = start_index; |
| 7213 | const table_index = case_table_start + i; |
| 7214 | if (table_index < scalar_case_table) { |
| 7215 | end_index += 1; |
| 7216 | } else if (table_index < multi_case_table) { |
| 7217 | body_len_index += 1; |
| 7218 | end_index += 2; |
| 7219 | } else { |
| 7220 | body_len_index += 2; |
| 7221 | const items_len = payloads.items[start_index]; |
| 7222 | const ranges_len = payloads.items[start_index + 1]; |
| 7223 | end_index += 3 + items_len + 2 * ranges_len; |
| 7224 | } |
| 7225 | |
| 7226 | const prong_info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(payloads.items[body_len_index]); |
| 7227 | end_index += prong_info.body_len; |
| 7228 | |
| 7229 | switch (strat.tag) { |
| 7230 | .break_operand => blk: { |
| 7231 | // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus |
| 7232 | // `elide_store_to_block_ptr_instructions` will either be true, |
| 7233 | // or all prongs are noreturn. |
| 7234 | if (!strat.elide_store_to_block_ptr_instructions) |
| 7235 | break :blk; |
| 7236 | |
| 7237 | // There will necessarily be a store_to_block_ptr for |
| 7238 | // all prongs, except for prongs that ended with a noreturn instruction. |
| 7239 | // Elide all the `store_to_block_ptr` instructions. |
| 7240 | |
| 7241 | // The break instructions need to have their operands coerced if the |
| 7242 | // switch's result location is a `ty`. In this case we overwrite the |
| 7243 | // `store_to_block_ptr` instruction with an `as` instruction and repurpose |
| 7244 | // it as the break operand. |
| 7245 | if (prong_info.body_len < 2) |
| 7246 | break :blk; |
| 7247 | |
| 7248 | var store_index = end_index - 2; |
| 7249 | while (true) : (store_index -= 1) switch (zir_tags[payloads.items[store_index]]) { |
| 7250 | .dbg_block_end, .dbg_block_begin, .dbg_stmt, .dbg_var_val, .dbg_var_ptr => {}, |
| 7251 | else => break, |
| 7261 | 7252 | }; |
| 7262 | | zir_datas[break_inst].@"break".operand = indexToRef(store_inst); |
| 7263 | | } else { |
| 7264 | | payloads.items[body_len_index] -= 1; |
| 7265 | | astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index .. end_index - 2]); |
| 7266 | | astgen.extra.appendAssumeCapacity(break_inst); |
| 7267 | | continue; |
| 7268 | | } |
| 7269 | | }, |
| 7270 | | .break_void => { |
| 7271 | | assert(!strat.elide_store_to_block_ptr_instructions); |
| 7272 | | const last_inst = payloads.items[end_index - 1]; |
| 7273 | | if (zir_tags[last_inst] == .@"break") { |
| 7274 | | const break_data = &zir_datas[last_inst].@"break"; |
| 7275 | | const block_inst = astgen.extra.items[ |
| 7276 | | break_data.payload_index + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").? |
| 7277 | | ]; |
| 7278 | | if (block_inst == switch_block) break_data.operand = .void_value; |
| 7279 | | } |
| 7280 | | }, |
| 7281 | | } |
| 7253 | const store_inst = payloads.items[store_index]; |
| 7254 | if (zir_tags[store_inst] != .store_to_block_ptr or |
| 7255 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) |
| 7256 | break :blk; |
| 7257 | const break_inst = payloads.items[end_index - 1]; |
| 7258 | if (block_scope.rl_ty_inst != .none) { |
| 7259 | if (pass == .breaks) { |
| 7260 | const break_data = &zir_datas[break_inst].@"break"; |
| 7261 | const break_src: i32 = @bitCast(astgen.extra.items[ |
| 7262 | break_data.payload_index + |
| 7263 | std.meta.fieldIndex(Zir.Inst.Break, "operand_src_node").? |
| 7264 | ]); |
| 7265 | if (break_src == Zir.Inst.Break.no_src_node) { |
| 7266 | zir_tags[store_inst] = .as; |
| 7267 | zir_datas[store_inst].bin = .{ |
| 7268 | .lhs = block_scope.rl_ty_inst, |
| 7269 | .rhs = break_data.operand, |
| 7270 | }; |
| 7271 | } else { |
| 7272 | zir_tags[store_inst] = .as_node; |
| 7273 | zir_datas[store_inst] = .{ .pl_node = .{ |
| 7274 | .src_node = break_src, |
| 7275 | .payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.As{ |
| 7276 | .dest_type = block_scope.rl_ty_inst, |
| 7277 | .operand = break_data.operand, |
| 7278 | }), |
| 7279 | } }; |
| 7280 | } |
| 7281 | break_data.operand = indexToRef(store_inst); |
| 7282 | } |
| 7283 | } else { |
| 7284 | if (pass == .body) { |
| 7285 | payloads.items[body_len_index] -= 1; |
| 7286 | astgen.extra.appendSliceAssumeCapacity( |
| 7287 | payloads.items[start_index .. end_index - 2], |
| 7288 | ); |
| 7289 | astgen.extra.appendAssumeCapacity(break_inst); |
| 7290 | } |
| 7291 | continue; |
| 7292 | } |
| 7293 | }, |
| 7294 | .break_void => if (pass == .breaks) { |
| 7295 | assert(!strat.elide_store_to_block_ptr_instructions); |
| 7296 | const last_inst = payloads.items[end_index - 1]; |
| 7297 | if (zir_tags[last_inst] == .@"break") { |
| 7298 | const break_data = &zir_datas[last_inst].@"break"; |
| 7299 | const block_inst = astgen.extra.items[ |
| 7300 | break_data.payload_index + |
| 7301 | std.meta.fieldIndex(Zir.Inst.Break, "block_inst").? |
| 7302 | ]; |
| 7303 | if (block_inst == switch_block) break_data.operand = .void_value; |
| 7304 | } |
| 7305 | }, |
| 7306 | } |
| 7282 | 7307 | |
| 7283 | | astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]); |
| 7308 | if (pass == .body) |
| 7309 | astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]); |
| 7310 | } |
| 7284 | 7311 | } |
| 7285 | 7312 | |
| 7286 | 7313 | const block_ref = indexToRef(switch_block); |