authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-07-25 15:41:43-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-07-26 16:08:40-04:00
log7c349da49c73817139444570d3082ac1f0c93078
tree79a4ec215c3896b3c06fab359a6fd4432e9d1ebf
parenta51cdf3b24c25959ee55a38428dc0da42a8be81c

aarch64: implement complex switch prongs


3 files changed, 106 insertions(+), 57 deletions(-)

src/codegen/aarch64/Select.zig+106-55
......@@ -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-1
......@@ -105,7 +105,6 @@ test "inline else enum" {
105105}
106106
107107test "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-1
......@@ -8,7 +8,6 @@ const minInt = std.math.minInt;
88const maxInt = std.math.maxInt;
99
1010test "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