stage2 ARM: more support for switch statements

This commit is contained in:
joachimschmidt557 2022-07-27 20:24:33 +02:00 committed by Joachim Schmidt
parent e863292fe2
commit 0fc79d602b
2 changed files with 33 additions and 35 deletions

View File

@ -4300,17 +4300,6 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
);
defer self.gpa.free(liveness.deaths);
// If the condition dies here in this switch instruction, process
// that death now instead of later as this has an effect on
// whether it needs to be spilled in the branches
if (self.liveness.operandDies(inst, 0)) {
const op_int = @enumToInt(pl_op.operand);
if (op_int >= Air.Inst.Ref.typed_value_map.len) {
const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
self.processDeath(op_index);
}
}
var extra_index: usize = switch_br.end;
var case_i: u32 = 0;
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + items.len + case_body.len;
var relocs = try self.gpa.alloc(u32, items.len);
defer self.gpa.free(relocs);
// For every item, we compare it to condition and branch into
// the prong if they are equal. After we compared to all
// items, we branch into the next prong (or if no other prongs
// exist out of the switch statement).
//
// cmp condition, item1
// beq prong
// cmp condition, item2
// beq prong
// cmp condition, item3
// beq prong
// b out
// prong: ...
// ...
// out: ...
const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len);
defer self.gpa.free(branch_into_prong_relocs);
if (items.len == 1) {
for (items) |item, idx| {
const condition = try self.resolveInst(pl_op.operand);
const item = try self.resolveInst(items[0]);
const item_mcv = try self.resolveInst(item);
const operands: BinOpOperands = .{ .mcv = .{
.lhs = condition,
.rhs = item,
.rhs = item_mcv,
} };
const cmp_result = try self.cmp(operands, condition_ty, .eq);
relocs[0] = try self.condBr(cmp_result);
} else {
return self.fail("TODO switch with multiple items", .{});
const cmp_result = try self.cmp(operands, condition_ty, .neq);
branch_into_prong_relocs[idx] = try self.condBr(cmp_result);
}
const branch_away_from_prong_reloc = try self.addInst(.{
.tag = .b,
.data = .{ .inst = undefined }, // populated later through performReloc
});
for (branch_into_prong_relocs) |reloc| {
try self.performReloc(reloc);
}
// Capture the state of register and stack allocation state so that we can revert to it.
@ -4369,9 +4380,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
self.next_stack_offset = parent_next_stack_offset;
self.register_manager.free_registers = parent_free_registers;
for (relocs) |reloc| {
try self.performReloc(reloc);
}
try self.performReloc(branch_away_from_prong_reloc);
}
if (switch_br.data.else_body_len > 0) {
@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
// in airCondBr.
}
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
}
fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {

View File

@ -53,7 +53,6 @@ test "implicit comptime switch" {
}
test "switch on enum" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const fruit = Fruit.Orange;
@ -73,7 +72,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {
}
test "switch statement" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try nonConstSwitch(SwitchStatementFoo.C);
@ -91,7 +89,6 @@ const SwitchStatementFoo = enum { A, B, C, D };
test "switch with multiple expressions" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const x = switch (returnsFive()) {
@ -120,7 +117,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {
}
test "switching on booleans" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try testSwitchOnBools();
@ -218,7 +214,6 @@ fn poll() void {
}
test "switch on global mutable var isn't constant-folded" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
while (state < 2) {
@ -278,7 +273,6 @@ fn testSwitchEnumPtrCapture() !void {
test "switch handles all cases of number" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try testSwitchHandleAllCases();
@ -370,7 +364,6 @@ test "anon enum literal used in switch on union enum" {
}
test "switch all prongs unreachable" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try testAllProngsUnreachable();
@ -582,7 +575,6 @@ test "switch on pointer type" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
const X = struct {
@ -674,7 +666,6 @@ test "capture of integer forwards the switch condition directly" {
}
test "enum value without tag name used as switch item" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const E = enum(u32) {