mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 13:30:45 +00:00
AstGen: improve switch expressions
* use the proper result location strategy even when there are noreturn prongs in the switch expression * when using break_operand strategy, actually omit the store_to_block_ptr instructions rather than eliding them. * for both strategies, properly handle noreturn prongs.
This commit is contained in:
parent
549af582e7
commit
c7b09be8de
129
src/AstGen.zig
129
src/AstGen.zig
@ -2752,9 +2752,9 @@ fn switchExpr(
|
||||
};
|
||||
break :blk &capture_val_scope.base;
|
||||
};
|
||||
block_scope.break_count += 1;
|
||||
const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
|
||||
if (!astgen.refIsNoReturn(case_result)) {
|
||||
block_scope.break_count += 1;
|
||||
_ = try case_scope.addBreak(.@"break", switch_block, case_result);
|
||||
}
|
||||
// Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`.
|
||||
@ -2873,9 +2873,9 @@ fn switchExpr(
|
||||
});
|
||||
}
|
||||
|
||||
block_scope.break_count += 1;
|
||||
const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
|
||||
if (!astgen.refIsNoReturn(case_result)) {
|
||||
block_scope.break_count += 1;
|
||||
_ = try case_scope.addBreak(.@"break", switch_block, case_result);
|
||||
}
|
||||
|
||||
@ -2886,9 +2886,9 @@ fn switchExpr(
|
||||
} else {
|
||||
const item_node = case.ast.values[0];
|
||||
const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
|
||||
block_scope.break_count += 1;
|
||||
const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
|
||||
if (!astgen.refIsNoReturn(case_result)) {
|
||||
block_scope.break_count += 1;
|
||||
_ = try case_scope.addBreak(.@"break", switch_block, case_result);
|
||||
}
|
||||
try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +
|
||||
@ -2925,13 +2925,11 @@ fn switchExpr(
|
||||
0b1_10_1 => .switch_block_ref_under_multi,
|
||||
else => unreachable,
|
||||
};
|
||||
const zir_datas = astgen.instructions.items(.data);
|
||||
const payload_index = astgen.extra.items.len;
|
||||
const zir_datas = astgen.instructions.items(.data);
|
||||
zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);
|
||||
try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
|
||||
scalar_cases_payload.items.len + multi_cases_payload.items.len);
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
|
||||
astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
|
||||
const strat = rl.strategy(&block_scope);
|
||||
switch (strat.tag) {
|
||||
.break_operand => {
|
||||
@ -2939,51 +2937,90 @@ fn switchExpr(
|
||||
// this is always true.
|
||||
assert(strat.elide_store_to_block_ptr_instructions);
|
||||
|
||||
// There will necessarily be a store_to_block_ptr for
|
||||
// all prongs, except for prongs that ended with a noreturn instruction.
|
||||
// Elide all the `store_to_block_ptr` instructions.
|
||||
var extra_index: usize = payload_index;
|
||||
|
||||
var extra_index: usize = 0;
|
||||
extra_index += 2;
|
||||
extra_index += @boolToInt(multi_cases_len != 0);
|
||||
if (special_prong != .none) {
|
||||
const body_len = astgen.extra.items[extra_index];
|
||||
const body_len_index = extra_index;
|
||||
const body_len = scalar_cases_payload.items[extra_index];
|
||||
extra_index += 1;
|
||||
const body = astgen.extra.items[extra_index..][0..body_len];
|
||||
extra_index += body_len;
|
||||
const store_inst = body[body.len - 2];
|
||||
assert(zir_tags[store_inst] == .store_to_block_ptr);
|
||||
assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
|
||||
zir_tags[store_inst] = .elided;
|
||||
zir_datas[store_inst] = undefined;
|
||||
extra_index += body_len - 2;
|
||||
const store_inst = scalar_cases_payload.items[extra_index];
|
||||
if (zir_tags[store_inst] == .store_to_block_ptr) {
|
||||
assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
|
||||
scalar_cases_payload.items[body_len_index] -= 1;
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
|
||||
extra_index += 1;
|
||||
astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]);
|
||||
extra_index += 1;
|
||||
} else {
|
||||
extra_index += 2;
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
|
||||
}
|
||||
} else {
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
|
||||
}
|
||||
var scalar_i: u32 = 0;
|
||||
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
|
||||
const start_index = extra_index;
|
||||
extra_index += 1;
|
||||
const body_len = astgen.extra.items[extra_index];
|
||||
const body_len_index = extra_index;
|
||||
const body_len = scalar_cases_payload.items[extra_index];
|
||||
extra_index += 1;
|
||||
const body = astgen.extra.items[extra_index..][0..body_len];
|
||||
extra_index += body_len;
|
||||
const store_inst = body[body.len - 2];
|
||||
assert(zir_tags[store_inst] == .store_to_block_ptr);
|
||||
assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
|
||||
zir_tags[store_inst] = .elided;
|
||||
zir_datas[store_inst] = undefined;
|
||||
if (body_len < 2) {
|
||||
extra_index += body_len;
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
|
||||
continue;
|
||||
}
|
||||
extra_index += body_len - 2;
|
||||
const store_inst = scalar_cases_payload.items[extra_index];
|
||||
if (zir_tags[store_inst] == .store_to_block_ptr) {
|
||||
assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
|
||||
scalar_cases_payload.items[body_len_index] -= 1;
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
|
||||
extra_index += 1;
|
||||
astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]);
|
||||
extra_index += 1;
|
||||
} else {
|
||||
extra_index += 2;
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
|
||||
}
|
||||
}
|
||||
extra_index = 0;
|
||||
var multi_i: u32 = 0;
|
||||
while (multi_i < multi_cases_len) : (multi_i += 1) {
|
||||
const items_len = astgen.extra.items[extra_index];
|
||||
const start_index = extra_index;
|
||||
const items_len = multi_cases_payload.items[extra_index];
|
||||
extra_index += 1;
|
||||
const ranges_len = astgen.extra.items[extra_index];
|
||||
const ranges_len = multi_cases_payload.items[extra_index];
|
||||
extra_index += 1;
|
||||
const body_len = astgen.extra.items[extra_index];
|
||||
const body_len_index = extra_index;
|
||||
const body_len = multi_cases_payload.items[extra_index];
|
||||
extra_index += 1;
|
||||
extra_index += items_len;
|
||||
extra_index += 2 * ranges_len;
|
||||
const body = astgen.extra.items[extra_index..][0..body_len];
|
||||
extra_index += body_len;
|
||||
const store_inst = body[body.len - 2];
|
||||
assert(zir_tags[store_inst] == .store_to_block_ptr);
|
||||
assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
|
||||
zir_tags[store_inst] = .elided;
|
||||
zir_datas[store_inst] = undefined;
|
||||
if (body_len < 2) {
|
||||
extra_index += body_len;
|
||||
astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
|
||||
continue;
|
||||
}
|
||||
extra_index += body_len - 2;
|
||||
const store_inst = multi_cases_payload.items[extra_index];
|
||||
if (zir_tags[store_inst] == .store_to_block_ptr) {
|
||||
assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
|
||||
multi_cases_payload.items[body_len_index] -= 1;
|
||||
astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
|
||||
extra_index += 1;
|
||||
astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]);
|
||||
extra_index += 1;
|
||||
} else {
|
||||
extra_index += 2;
|
||||
astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
|
||||
}
|
||||
}
|
||||
|
||||
const block_ref = astgen.indexToRef(switch_block);
|
||||
@ -2994,6 +3031,8 @@ fn switchExpr(
|
||||
},
|
||||
.break_void => {
|
||||
assert(!strat.elide_store_to_block_ptr_instructions);
|
||||
astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
|
||||
astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
|
||||
// Modify all the terminating instruction tags to become `break` variants.
|
||||
var extra_index: usize = payload_index;
|
||||
extra_index += 2;
|
||||
@ -3004,9 +3043,11 @@ fn switchExpr(
|
||||
const body = astgen.extra.items[extra_index..][0..body_len];
|
||||
extra_index += body_len;
|
||||
const last = body[body.len - 1];
|
||||
assert(zir_tags[last] == .@"break");
|
||||
assert(zir_datas[last].@"break".block_inst == switch_block);
|
||||
zir_datas[last].@"break".operand = .void_value;
|
||||
if (zir_tags[last] == .@"break" and
|
||||
zir_datas[last].@"break".block_inst == switch_block)
|
||||
{
|
||||
zir_datas[last].@"break".operand = .void_value;
|
||||
}
|
||||
}
|
||||
var scalar_i: u32 = 0;
|
||||
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
|
||||
@ -3016,9 +3057,11 @@ fn switchExpr(
|
||||
const body = astgen.extra.items[extra_index..][0..body_len];
|
||||
extra_index += body_len;
|
||||
const last = body[body.len - 1];
|
||||
assert(zir_tags[last] == .@"break");
|
||||
assert(zir_datas[last].@"break".block_inst == switch_block);
|
||||
zir_datas[last].@"break".operand = .void_value;
|
||||
if (zir_tags[last] == .@"break" and
|
||||
zir_datas[last].@"break".block_inst == switch_block)
|
||||
{
|
||||
zir_datas[last].@"break".operand = .void_value;
|
||||
}
|
||||
}
|
||||
var multi_i: u32 = 0;
|
||||
while (multi_i < multi_cases_len) : (multi_i += 1) {
|
||||
@ -3033,9 +3076,11 @@ fn switchExpr(
|
||||
const body = astgen.extra.items[extra_index..][0..body_len];
|
||||
extra_index += body_len;
|
||||
const last = body[body.len - 1];
|
||||
assert(zir_tags[last] == .@"break");
|
||||
assert(zir_datas[last].@"break".block_inst == switch_block);
|
||||
zir_datas[last].@"break".operand = .void_value;
|
||||
if (zir_tags[last] == .@"break" and
|
||||
zir_datas[last].@"break".block_inst == switch_block)
|
||||
{
|
||||
zir_datas[last].@"break".operand = .void_value;
|
||||
}
|
||||
}
|
||||
|
||||
return astgen.indexToRef(switch_block);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user