mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
stage2 ARM: more support for switch statements
This commit is contained in:
parent
e863292fe2
commit
0fc79d602b
@ -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 {
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user