diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2025-07-25 15:41:43 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2025-07-26 16:08:40 -0400 |
| commit | 7c349da49c73817139444570d3082ac1f0c93078 (patch) | |
| tree | 79a4ec215c3896b3c06fab359a6fd4432e9d1ebf /src/codegen | |
| parent | a51cdf3b24c25959ee55a38428dc0da42a8be81c (diff) | |
| download | zig-7c349da49c73817139444570d3082ac1f0c93078.tar.gz zig-7c349da49c73817139444570d3082ac1f0c93078.zip | |
aarch64: implement complex switch prongs
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/aarch64/Select.zig | 161 |
1 files changed, 106 insertions, 55 deletions
diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index f7da48d847..0a50cb6c9d 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -4328,7 +4328,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { }; var cond_mat: ?Value.Materialize = null; var cond_reg: Register = undefined; - var temp_reg: Register = undefined; var cases_it = switch_br.iterateCases(); while (cases_it.next()) |case| { const next_label = isel.instructions.items.len; @@ -4342,11 +4341,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { if (cond_mat == null) { var cond_vi = try isel.use(switch_br.operand); cond_mat = try cond_vi.matReg(isel); - const temp_ra = try isel.allocIntReg(); - cond_reg, temp_reg = switch (cond_int_info.bits) { + cond_reg = switch (cond_int_info.bits) { else => unreachable, - 1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() }, - 33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() }, + 1...32 => cond_mat.?.ra.w(), + 33...64 => cond_mat.?.ra.x(), }; } 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 { ) else high_bigint.toInt(i64) catch return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}); + const adjusted_ra = switch (low_int) { + 0 => cond_mat.?.ra, + else => try isel.allocIntReg(), + }; + defer if (adjusted_ra != cond_mat.?.ra) isel.freeReg(adjusted_ra); + const adjusted_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => adjusted_ra.w(), + 33...64 => adjusted_ra.x(), + }; const delta_int = high_int -% low_int; - if (case_range_index > 0) { - return isel.fail("case range", .{}); - } else if (case.items.len > 0) { - return isel.fail("case range", .{}); + if (case_range_index | case.items.len > 0) { + if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp( + adjusted_reg, + .{ .immediate = pos_imm }, + .{ .n = false, .z = true, .c = false, .v = false }, + if (case_range_index > 0) .hi else .ne, + )) else if (std.math.cast(u5, -delta_int)) |neg_imm| try isel.emit(.ccmn( + adjusted_reg, + .{ .immediate = neg_imm }, + .{ .n = false, .z = true, .c = false, .v = false }, + if (case_range_index > 0) .hi else .ne, + )) else { + const imm_ra = try isel.allocIntReg(); + defer isel.freeReg(imm_ra); + const imm_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => imm_ra.w(), + 33...64 => imm_ra.x(), + }; + try isel.emit(.ccmp( + cond_reg, + .{ .register = imm_reg }, + .{ .n = false, .z = true, .c = false, .v = false }, + if (case_range_index > 0) .hi else .ne, + )); + try isel.movImmediate(imm_reg, @bitCast(delta_int)); + } } else { - const adjusted_reg = switch (low_int) { - 0 => cond_reg, - else => temp_reg, - }; - if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs( zero_reg, adjusted_reg, @@ -4421,41 +4447,55 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { adjusted_reg, .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, )) else { - try isel.movImmediate(temp_reg, @bitCast(delta_int)); - try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg })); + const imm_ra = try isel.allocIntReg(); + defer isel.freeReg(imm_ra); + const imm_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => imm_ra.w(), + 33...64 => imm_ra.x(), + }; + try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = imm_reg })); + try isel.movImmediate(imm_reg, @bitCast(delta_int)); } + } - switch (low_int) { - 0 => {}, - else => { - if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub( - adjusted_reg, - cond_reg, - .{ .immediate = pos_imm }, - )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add( - adjusted_reg, - cond_reg, - .{ .immediate = neg_imm }, - )) else if (if (@as(i12, @truncate(low_int)) == 0) - std.math.cast(u12, low_int >> 12) - else - null) |pos_imm_lsr_12| try isel.emit(.sub( - adjusted_reg, - cond_reg, - .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, - )) else if (if (@as(i12, @truncate(-low_int)) == 0) - std.math.cast(u12, -low_int >> 12) - else - null) |neg_imm_lsr_12| try isel.emit(.add( - adjusted_reg, - cond_reg, - .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, - )) else { - try isel.movImmediate(temp_reg, @bitCast(low_int)); - try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg })); - } - }, - } + switch (low_int) { + 0 => {}, + else => { + if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub( + adjusted_reg, + cond_reg, + .{ .immediate = pos_imm }, + )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add( + adjusted_reg, + cond_reg, + .{ .immediate = neg_imm }, + )) else if (if (@as(i12, @truncate(low_int)) == 0) + std.math.cast(u12, low_int >> 12) + else + null) |pos_imm_lsr_12| try isel.emit(.sub( + adjusted_reg, + cond_reg, + .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, + )) else if (if (@as(i12, @truncate(-low_int)) == 0) + std.math.cast(u12, -low_int >> 12) + else + null) |neg_imm_lsr_12| try isel.emit(.add( + adjusted_reg, + cond_reg, + .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, + )) else { + const imm_ra = try isel.allocIntReg(); + defer isel.freeReg(imm_ra); + const imm_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => imm_ra.w(), + 33...64 => imm_ra.x(), + }; + try isel.emit(.sub(adjusted_reg, cond_reg, .{ .register = imm_reg })); + try isel.movImmediate(imm_reg, @bitCast(low_int)); + } + }, } } var case_item_index = case.items.len; @@ -4483,13 +4523,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { .{ .n = false, .z = true, .c = false, .v = false }, .ne, )) else { - try isel.movImmediate(temp_reg, @bitCast(item_int)); + const imm_ra = try isel.allocIntReg(); + defer isel.freeReg(imm_ra); + const imm_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => imm_ra.w(), + 33...64 => imm_ra.x(), + }; try isel.emit(.ccmp( cond_reg, - .{ .register = temp_reg }, + .{ .register = imm_reg }, .{ .n = false, .z = true, .c = false, .v = false }, .ne, )); + try isel.movImmediate(imm_reg, @bitCast(item_int)); } } else { 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 { cond_reg, .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, )) else { - try isel.movImmediate(temp_reg, @bitCast(item_int)); - try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg })); + const imm_ra = try isel.allocIntReg(); + defer isel.freeReg(imm_ra); + const imm_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => imm_ra.w(), + 33...64 => imm_ra.x(), + }; + try isel.emit(.subs(zero_reg, cond_reg, .{ .register = imm_reg })); + try isel.movImmediate(imm_reg, @bitCast(item_int)); } } } } - if (cond_mat) |mat| { - try mat.finish(isel); - isel.freeReg(temp_reg.alias); - } + if (cond_mat) |mat| try mat.finish(isel); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, .@"try", .try_cold => { |
