Skip to content

Commit 7c349da

Browse files
committed
aarch64: implement complex switch prongs
1 parent a51cdf3 commit 7c349da

File tree

3 files changed

+106
-57
lines changed

3 files changed

+106
-57
lines changed

src/codegen/aarch64/Select.zig

Lines changed: 106 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,7 +4328,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
43284328
};
43294329
var cond_mat: ?Value.Materialize = null;
43304330
var cond_reg: Register = undefined;
4331-
var temp_reg: Register = undefined;
43324331
var cases_it = switch_br.iterateCases();
43334332
while (cases_it.next()) |case| {
43344333
const next_label = isel.instructions.items.len;
@@ -4342,11 +4341,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
43424341
if (cond_mat == null) {
43434342
var cond_vi = try isel.use(switch_br.operand);
43444343
cond_mat = try cond_vi.matReg(isel);
4345-
const temp_ra = try isel.allocIntReg();
4346-
cond_reg, temp_reg = switch (cond_int_info.bits) {
4344+
cond_reg = switch (cond_int_info.bits) {
43474345
else => unreachable,
4348-
1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() },
4349-
33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() },
4346+
1...32 => cond_mat.?.ra.w(),
4347+
33...64 => cond_mat.?.ra.x(),
43504348
};
43514349
}
43524350
if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned(
@@ -4387,17 +4385,45 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
43874385
) else high_bigint.toInt(i64) catch
43884386
return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)});
43894387

4388+
const adjusted_ra = switch (low_int) {
4389+
0 => cond_mat.?.ra,
4390+
else => try isel.allocIntReg(),
4391+
};
4392+
defer if (adjusted_ra != cond_mat.?.ra) isel.freeReg(adjusted_ra);
4393+
const adjusted_reg = switch (cond_int_info.bits) {
4394+
else => unreachable,
4395+
1...32 => adjusted_ra.w(),
4396+
33...64 => adjusted_ra.x(),
4397+
};
43904398
const delta_int = high_int -% low_int;
4391-
if (case_range_index > 0) {
4392-
return isel.fail("case range", .{});
4393-
} else if (case.items.len > 0) {
4394-
return isel.fail("case range", .{});
4399+
if (case_range_index | case.items.len > 0) {
4400+
if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp(
4401+
adjusted_reg,
4402+
.{ .immediate = pos_imm },
4403+
.{ .n = false, .z = true, .c = false, .v = false },
4404+
if (case_range_index > 0) .hi else .ne,
4405+
)) else if (std.math.cast(u5, -delta_int)) |neg_imm| try isel.emit(.ccmn(
4406+
adjusted_reg,
4407+
.{ .immediate = neg_imm },
4408+
.{ .n = false, .z = true, .c = false, .v = false },
4409+
if (case_range_index > 0) .hi else .ne,
4410+
)) else {
4411+
const imm_ra = try isel.allocIntReg();
4412+
defer isel.freeReg(imm_ra);
4413+
const imm_reg = switch (cond_int_info.bits) {
4414+
else => unreachable,
4415+
1...32 => imm_ra.w(),
4416+
33...64 => imm_ra.x(),
4417+
};
4418+
try isel.emit(.ccmp(
4419+
cond_reg,
4420+
.{ .register = imm_reg },
4421+
.{ .n = false, .z = true, .c = false, .v = false },
4422+
if (case_range_index > 0) .hi else .ne,
4423+
));
4424+
try isel.movImmediate(imm_reg, @bitCast(delta_int));
4425+
}
43954426
} else {
4396-
const adjusted_reg = switch (low_int) {
4397-
0 => cond_reg,
4398-
else => temp_reg,
4399-
};
4400-
44014427
if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(
44024428
zero_reg,
44034429
adjusted_reg,
@@ -4421,41 +4447,55 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
44214447
adjusted_reg,
44224448
.{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
44234449
)) else {
4424-
try isel.movImmediate(temp_reg, @bitCast(delta_int));
4425-
try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg }));
4450+
const imm_ra = try isel.allocIntReg();
4451+
defer isel.freeReg(imm_ra);
4452+
const imm_reg = switch (cond_int_info.bits) {
4453+
else => unreachable,
4454+
1...32 => imm_ra.w(),
4455+
33...64 => imm_ra.x(),
4456+
};
4457+
try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = imm_reg }));
4458+
try isel.movImmediate(imm_reg, @bitCast(delta_int));
44264459
}
4460+
}
44274461

4428-
switch (low_int) {
4429-
0 => {},
4430-
else => {
4431-
if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4432-
adjusted_reg,
4433-
cond_reg,
4434-
.{ .immediate = pos_imm },
4435-
)) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4436-
adjusted_reg,
4437-
cond_reg,
4438-
.{ .immediate = neg_imm },
4439-
)) else if (if (@as(i12, @truncate(low_int)) == 0)
4440-
std.math.cast(u12, low_int >> 12)
4441-
else
4442-
null) |pos_imm_lsr_12| try isel.emit(.sub(
4443-
adjusted_reg,
4444-
cond_reg,
4445-
.{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4446-
)) else if (if (@as(i12, @truncate(-low_int)) == 0)
4447-
std.math.cast(u12, -low_int >> 12)
4448-
else
4449-
null) |neg_imm_lsr_12| try isel.emit(.add(
4450-
adjusted_reg,
4451-
cond_reg,
4452-
.{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4453-
)) else {
4454-
try isel.movImmediate(temp_reg, @bitCast(low_int));
4455-
try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg }));
4456-
}
4457-
},
4458-
}
4462+
switch (low_int) {
4463+
0 => {},
4464+
else => {
4465+
if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4466+
adjusted_reg,
4467+
cond_reg,
4468+
.{ .immediate = pos_imm },
4469+
)) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4470+
adjusted_reg,
4471+
cond_reg,
4472+
.{ .immediate = neg_imm },
4473+
)) else if (if (@as(i12, @truncate(low_int)) == 0)
4474+
std.math.cast(u12, low_int >> 12)
4475+
else
4476+
null) |pos_imm_lsr_12| try isel.emit(.sub(
4477+
adjusted_reg,
4478+
cond_reg,
4479+
.{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4480+
)) else if (if (@as(i12, @truncate(-low_int)) == 0)
4481+
std.math.cast(u12, -low_int >> 12)
4482+
else
4483+
null) |neg_imm_lsr_12| try isel.emit(.add(
4484+
adjusted_reg,
4485+
cond_reg,
4486+
.{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4487+
)) else {
4488+
const imm_ra = try isel.allocIntReg();
4489+
defer isel.freeReg(imm_ra);
4490+
const imm_reg = switch (cond_int_info.bits) {
4491+
else => unreachable,
4492+
1...32 => imm_ra.w(),
4493+
33...64 => imm_ra.x(),
4494+
};
4495+
try isel.emit(.sub(adjusted_reg, cond_reg, .{ .register = imm_reg }));
4496+
try isel.movImmediate(imm_reg, @bitCast(low_int));
4497+
}
4498+
},
44594499
}
44604500
}
44614501
var case_item_index = case.items.len;
@@ -4483,13 +4523,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
44834523
.{ .n = false, .z = true, .c = false, .v = false },
44844524
.ne,
44854525
)) else {
4486-
try isel.movImmediate(temp_reg, @bitCast(item_int));
4526+
const imm_ra = try isel.allocIntReg();
4527+
defer isel.freeReg(imm_ra);
4528+
const imm_reg = switch (cond_int_info.bits) {
4529+
else => unreachable,
4530+
1...32 => imm_ra.w(),
4531+
33...64 => imm_ra.x(),
4532+
};
44874533
try isel.emit(.ccmp(
44884534
cond_reg,
4489-
.{ .register = temp_reg },
4535+
.{ .register = imm_reg },
44904536
.{ .n = false, .z = true, .c = false, .v = false },
44914537
.ne,
44924538
));
4539+
try isel.movImmediate(imm_reg, @bitCast(item_int));
44934540
}
44944541
} else {
44954542
if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs(
@@ -4515,16 +4562,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
45154562
cond_reg,
45164563
.{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
45174564
)) else {
4518-
try isel.movImmediate(temp_reg, @bitCast(item_int));
4519-
try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg }));
4565+
const imm_ra = try isel.allocIntReg();
4566+
defer isel.freeReg(imm_ra);
4567+
const imm_reg = switch (cond_int_info.bits) {
4568+
else => unreachable,
4569+
1...32 => imm_ra.w(),
4570+
33...64 => imm_ra.x(),
4571+
};
4572+
try isel.emit(.subs(zero_reg, cond_reg, .{ .register = imm_reg }));
4573+
try isel.movImmediate(imm_reg, @bitCast(item_int));
45204574
}
45214575
}
45224576
}
45234577
}
4524-
if (cond_mat) |mat| {
4525-
try mat.finish(isel);
4526-
isel.freeReg(temp_reg.alias);
4527-
}
4578+
if (cond_mat) |mat| try mat.finish(isel);
45284579
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
45294580
},
45304581
.@"try", .try_cold => {

test/behavior/inline_switch.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ test "inline else enum" {
105105
}
106106

107107
test "inline else int with gaps" {
108-
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109108
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110109
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
111110

test/behavior/switch.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const minInt = std.math.minInt;
88
const maxInt = std.math.maxInt;
99

1010
test "switch with numbers" {
11-
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1211
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1413

0 commit comments

Comments
 (0)