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