Commit 151e15e444
Changed files (3)
src
arch
aarch64
src/arch/aarch64/bits.zig
@@ -4,17 +4,22 @@ const DW = std.dwarf;
const assert = std.debug.assert;
const testing = std.testing;
-// zig fmt: off
+pub const RegisterClass = enum {
+ general_purpose,
+ stack_pointer,
+ floating_point,
+};
/// General purpose registers in the AArch64 instruction set
-pub const Register = enum(u7) {
- // 64-bit registers
+pub const Register = enum(u8) {
+ // zig fmt: off
+ // 64-bit general-purpose registers
x0, x1, x2, x3, x4, x5, x6, x7,
x8, x9, x10, x11, x12, x13, x14, x15,
x16, x17, x18, x19, x20, x21, x22, x23,
x24, x25, x26, x27, x28, x29, x30, xzr,
- // 32-bit registers
+ // 32-bit general-purpose registers
w0, w1, w2, w3, w4, w5, w6, w7,
w8, w9, w10, w11, w12, w13, w14, w15,
w16, w17, w18, w19, w20, w21, w22, w23,
@@ -23,192 +28,298 @@ pub const Register = enum(u7) {
// Stack pointer
sp, wsp,
- pub fn id(self: Register) u6 {
- return switch (@enumToInt(self)) {
- 0...63 => return @as(u6, @truncate(u5, @enumToInt(self))),
- 64...65 => 32,
- else => unreachable,
- };
- }
-
- pub fn enc(self: Register) u5 {
- return switch (@enumToInt(self)) {
- 0...63 => return @truncate(u5, @enumToInt(self)),
- 64...65 => 31,
- else => unreachable,
- };
- }
-
- /// Returns the bit-width of the register.
- pub fn size(self: Register) u7 {
- return switch (@enumToInt(self)) {
- 0...31 => 64,
- 32...63 => 32,
- 64 => 64,
- 65 => 32,
- else => unreachable,
- };
- }
-
- /// Convert from any register to its 64 bit alias.
- pub fn to64(self: Register) Register {
- return switch (@enumToInt(self)) {
- 0...31 => self,
- 32...63 => @intToEnum(Register, @enumToInt(self) - 32),
- 64 => .sp,
- 65 => .sp,
- else => unreachable,
- };
- }
-
- /// Convert from any register to its 32 bit alias.
- pub fn to32(self: Register) Register {
- return switch (@enumToInt(self)) {
- 0...31 => @intToEnum(Register, @enumToInt(self) + 32),
- 32...63 => self,
- 64 => .wsp,
- 65 => .wsp,
- else => unreachable,
- };
- }
-
- pub fn dwarfLocOp(self: Register) u8 {
- return @as(u8, self.enc()) + DW.OP.reg0;
- }
-};
-
-// zig fmt: on
-
-test "Register.enc" {
- try testing.expectEqual(@as(u5, 0), Register.x0.enc());
- try testing.expectEqual(@as(u5, 0), Register.w0.enc());
-
- try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
- try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
-
- try testing.expectEqual(@as(u5, 31), Register.sp.enc());
- try testing.expectEqual(@as(u5, 31), Register.sp.enc());
-}
-
-test "Register.size" {
- try testing.expectEqual(@as(u7, 64), Register.x19.size());
- try testing.expectEqual(@as(u7, 32), Register.w3.size());
-}
-
-test "Register.to64/to32" {
- try testing.expectEqual(Register.x0, Register.w0.to64());
- try testing.expectEqual(Register.x0, Register.x0.to64());
-
- try testing.expectEqual(Register.w3, Register.w3.to32());
- try testing.expectEqual(Register.w3, Register.x3.to32());
-}
-
-// zig fmt: off
-
-/// Scalar floating point registers in the aarch64 instruction set
-pub const FloatingPointRegister = enum(u8) {
- // 128-bit registers
+ // 128-bit floating-point registers
q0, q1, q2, q3, q4, q5, q6, q7,
q8, q9, q10, q11, q12, q13, q14, q15,
q16, q17, q18, q19, q20, q21, q22, q23,
q24, q25, q26, q27, q28, q29, q30, q31,
- // 64-bit registers
+ // 64-bit floating-point registers
d0, d1, d2, d3, d4, d5, d6, d7,
d8, d9, d10, d11, d12, d13, d14, d15,
d16, d17, d18, d19, d20, d21, d22, d23,
d24, d25, d26, d27, d28, d29, d30, d31,
- // 32-bit registers
+ // 32-bit floating-point registers
s0, s1, s2, s3, s4, s5, s6, s7,
s8, s9, s10, s11, s12, s13, s14, s15,
s16, s17, s18, s19, s20, s21, s22, s23,
s24, s25, s26, s27, s28, s29, s30, s31,
- // 16-bit registers
+ // 16-bit floating-point registers
h0, h1, h2, h3, h4, h5, h6, h7,
h8, h9, h10, h11, h12, h13, h14, h15,
h16, h17, h18, h19, h20, h21, h22, h23,
h24, h25, h26, h27, h28, h29, h30, h31,
- // 8-bit registers
+ // 8-bit floating-point registers
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
+ // zig fmt: on
- pub fn id(self: FloatingPointRegister) u5 {
- return @truncate(u5, @enumToInt(self));
+ pub fn class(self: Register) RegisterClass {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.x0)...@enumToInt(Register.xzr) => .general_purpose,
+ @enumToInt(Register.w0)...@enumToInt(Register.wzr) => .general_purpose,
+
+ @enumToInt(Register.sp) => .stack_pointer,
+ @enumToInt(Register.wsp) => .stack_pointer,
+
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => .floating_point,
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => .floating_point,
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => .floating_point,
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => .floating_point,
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => .floating_point,
+ else => unreachable,
+ };
+ }
+
+ pub fn id(self: Register) u6 {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.x0)),
+ @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.w0)),
+
+ @enumToInt(Register.sp) => 32,
+ @enumToInt(Register.wsp) => 32,
+
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.q0) + 33),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.d0) + 33),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.s0) + 33),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.h0) + 33),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.b0) + 33),
+ else => unreachable,
+ };
+ }
+
+ pub fn enc(self: Register) u5 {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.x0)),
+ @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.w0)),
+
+ @enumToInt(Register.sp) => 31,
+ @enumToInt(Register.wsp) => 31,
+
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.q0)),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.d0)),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.s0)),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.h0)),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.b0)),
+ else => unreachable,
+ };
}
/// Returns the bit-width of the register.
- pub fn size(self: FloatingPointRegister) u8 {
+ pub fn size(self: Register) u8 {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.x0)...@enumToInt(Register.xzr) => 64,
+ @enumToInt(Register.w0)...@enumToInt(Register.wzr) => 32,
+
+ @enumToInt(Register.sp) => 64,
+ @enumToInt(Register.wsp) => 32,
+
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => 128,
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => 64,
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => 32,
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => 16,
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => 8,
+ else => unreachable,
+ };
+ }
+
+ /// Convert from a general-purpose register to its 64 bit alias.
+ pub fn toX(self: Register) Register {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.x0) + @enumToInt(Register.x0),
+ ),
+ @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.w0) + @enumToInt(Register.x0),
+ ),
+ else => unreachable,
+ };
+ }
+
+ /// Convert from a general-purpose register to its 32 bit alias.
+ pub fn toW(self: Register) Register {
return switch (@enumToInt(self)) {
- 0...31 => 128,
- 32...63 => 64,
- 64...95 => 32,
- 96...127 => 16,
- 128...159 => 8,
+ @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.x0) + @enumToInt(Register.w0),
+ ),
+ @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.w0) + @enumToInt(Register.w0),
+ ),
else => unreachable,
};
}
- /// Convert from any register to its 128 bit alias.
- pub fn to128(self: FloatingPointRegister) FloatingPointRegister {
- return @intToEnum(FloatingPointRegister, self.id());
+ /// Convert from a floating-point register to its 128 bit alias.
+ pub fn toQ(self: Register) Register {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.q0),
+ ),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.q0),
+ ),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.q0),
+ ),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.q0),
+ ),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.q0),
+ ),
+ else => unreachable,
+ };
+ }
+
+ /// Convert from a floating-point register to its 64 bit alias.
+ pub fn toD(self: Register) Register {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.d0),
+ ),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.d0),
+ ),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.d0),
+ ),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.d0),
+ ),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.d0),
+ ),
+ else => unreachable,
+ };
}
- /// Convert from any register to its 64 bit alias.
- pub fn to64(self: FloatingPointRegister) FloatingPointRegister {
- return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 32);
+ /// Convert from a floating-point register to its 32 bit alias.
+ pub fn toS(self: Register) Register {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.s0),
+ ),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.s0),
+ ),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.s0),
+ ),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.s0),
+ ),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.s0),
+ ),
+ else => unreachable,
+ };
}
- /// Convert from any register to its 32 bit alias.
- pub fn to32(self: FloatingPointRegister) FloatingPointRegister {
- return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 64);
+ /// Convert from a floating-point register to its 16 bit alias.
+ pub fn toH(self: Register) Register {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.h0),
+ ),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.h0),
+ ),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.h0),
+ ),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.h0),
+ ),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.h0),
+ ),
+ else => unreachable,
+ };
}
- /// Convert from any register to its 16 bit alias.
- pub fn to16(self: FloatingPointRegister) FloatingPointRegister {
- return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 96);
+ /// Convert from a floating-point register to its 8 bit alias.
+ pub fn toB(self: Register) Register {
+ return switch (@enumToInt(self)) {
+ @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.b0),
+ ),
+ @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.b0),
+ ),
+ @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.b0),
+ ),
+ @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.b0),
+ ),
+ @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
+ Register,
+ @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.b0),
+ ),
+ else => unreachable,
+ };
}
- /// Convert from any register to its 8 bit alias.
- pub fn to8(self: FloatingPointRegister) FloatingPointRegister {
- return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 128);
+ pub fn dwarfLocOp(self: Register) u8 {
+ return @as(u8, self.enc()) + DW.OP.reg0;
}
};
-// zig fmt: on
+test "Register.enc" {
+ try testing.expectEqual(@as(u5, 0), Register.x0.enc());
+ try testing.expectEqual(@as(u5, 0), Register.w0.enc());
-test "FloatingPointRegister.id" {
- try testing.expectEqual(@as(u5, 0), FloatingPointRegister.b0.id());
- try testing.expectEqual(@as(u5, 0), FloatingPointRegister.h0.id());
- try testing.expectEqual(@as(u5, 0), FloatingPointRegister.s0.id());
- try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.id());
- try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.id());
+ try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
+ try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
- try testing.expectEqual(@as(u5, 2), FloatingPointRegister.q2.id());
- try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d31.id());
+ try testing.expectEqual(@as(u5, 31), Register.sp.enc());
+ try testing.expectEqual(@as(u5, 31), Register.sp.enc());
}
-test "FloatingPointRegister.size" {
- try testing.expectEqual(@as(u8, 128), FloatingPointRegister.q1.size());
- try testing.expectEqual(@as(u8, 64), FloatingPointRegister.d2.size());
- try testing.expectEqual(@as(u8, 32), FloatingPointRegister.s3.size());
- try testing.expectEqual(@as(u8, 16), FloatingPointRegister.h4.size());
- try testing.expectEqual(@as(u8, 8), FloatingPointRegister.b5.size());
+test "Register.size" {
+ try testing.expectEqual(@as(u8, 64), Register.x19.size());
+ try testing.expectEqual(@as(u8, 32), Register.w3.size());
}
-test "FloatingPointRegister.toX" {
- try testing.expectEqual(FloatingPointRegister.q1, FloatingPointRegister.q1.to128());
- try testing.expectEqual(FloatingPointRegister.q2, FloatingPointRegister.b2.to128());
- try testing.expectEqual(FloatingPointRegister.q3, FloatingPointRegister.h3.to128());
+test "Register.toX/toW" {
+ try testing.expectEqual(Register.x0, Register.w0.toX());
+ try testing.expectEqual(Register.x0, Register.x0.toX());
- try testing.expectEqual(FloatingPointRegister.d0, FloatingPointRegister.q0.to64());
- try testing.expectEqual(FloatingPointRegister.s1, FloatingPointRegister.d1.to32());
- try testing.expectEqual(FloatingPointRegister.h2, FloatingPointRegister.s2.to16());
- try testing.expectEqual(FloatingPointRegister.b3, FloatingPointRegister.h3.to8());
+ try testing.expectEqual(Register.w3, Register.w3.toW());
+ try testing.expectEqual(Register.w3, Register.x3.toW());
}
/// Represents an instruction in the AArch64 instruction set
src/arch/aarch64/CodeGen.zig
@@ -414,7 +414,7 @@ fn gen(self: *Self) !void {
// to the stack.
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes = @divExact(ptr_bits, 8);
- const ret_ptr_reg = registerAlias(.x0, ptr_bytes);
+ const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;
self.next_stack_offset = stack_offset;
@@ -927,7 +927,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
// Make sure the type can fit in a register before we try to allocate one.
if (abi_size <= 8) {
if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
- return MCValue{ .register = registerAlias(reg, abi_size) };
+ return MCValue{ .register = self.registerAlias(reg, elem_ty) };
}
}
}
@@ -982,7 +982,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
/// This can have a side effect of spilling instructions to the stack to free up a register.
fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
const raw_reg = try self.register_manager.allocReg(null, gp);
- const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, ty);
try self.genSetReg(ty, reg, mcv);
return reg;
}
@@ -993,7 +993,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
const raw_reg = try self.register_manager.allocReg(reg_owner, gp);
const ty = self.air.typeOfIndex(reg_owner);
- const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, ty);
try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
return MCValue{ .register = reg };
}
@@ -1031,7 +1031,6 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
const operand_info = operand_ty.intInfo(self.target.*);
const dest_ty = self.air.typeOfIndex(inst);
- const dest_abi_size = dest_ty.abiSize(self.target.*);
const dest_info = dest_ty.intInfo(self.target.*);
const result: MCValue = result: {
@@ -1042,7 +1041,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
const truncated: MCValue = switch (operand_mcv) {
- .register => |r| MCValue{ .register = registerAlias(r, dest_abi_size) },
+ .register => |r| MCValue{ .register = self.registerAlias(r, dest_ty) },
else => operand_mcv,
};
@@ -1117,7 +1116,7 @@ fn trunc(
else => operand_reg: {
if (info_a.bits <= 64) {
const raw_reg = try self.copyToTmpRegister(operand_ty, operand);
- break :operand_reg registerAlias(raw_reg, operand_ty.abiSize(self.target.*));
+ break :operand_reg self.registerAlias(raw_reg, operand_ty);
} else {
return self.fail("TODO load least significant word into register", .{});
}
@@ -1130,14 +1129,14 @@ fn trunc(
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
- break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(operand_reg, dest_ty);
} else {
const raw_reg = try self.register_manager.allocReg(inst, gp);
- break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, dest_ty);
}
} else blk: {
const raw_reg = try self.register_manager.allocReg(null, gp);
- break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, dest_ty);
};
try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
@@ -1194,7 +1193,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
}
const raw_reg = try self.register_manager.allocReg(null, gp);
- break :blk raw_reg.to32();
+ break :blk self.registerAlias(raw_reg, operand_ty);
};
_ = try self.addInst(.{
@@ -1227,7 +1226,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
}
const raw_reg = try self.register_manager.allocReg(null, gp);
- break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, operand_ty);
};
_ = try self.addInst(.{
@@ -1307,8 +1306,8 @@ fn binOpRegister(
const lhs_is_register = lhs == .register;
const rhs_is_register = rhs == .register;
- if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));
- if (rhs_is_register) assert(rhs.register == registerAlias(rhs.register, rhs_ty.abiSize(self.target.*)));
+ if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty));
+ if (rhs_is_register) assert(rhs.register == self.registerAlias(rhs.register, rhs_ty));
const lhs_lock: ?RegisterLock = if (lhs_is_register)
self.register_manager.lockReg(lhs.register)
@@ -1330,7 +1329,7 @@ fn binOpRegister(
} else null;
const raw_reg = try self.register_manager.allocReg(track_inst, gp);
- const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, lhs_ty);
if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
@@ -1344,7 +1343,7 @@ fn binOpRegister(
// order to guarantee that registers will have equal sizes, we
// use the register alias of rhs corresponding to the size of
// lhs.
- registerAlias(rhs.register, lhs_ty.abiSize(self.target.*))
+ self.registerAlias(rhs.register, lhs_ty)
else blk: {
const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
break :inst Air.refToIndex(md.rhs).?;
@@ -1354,7 +1353,7 @@ fn binOpRegister(
// Here, we deliberately use lhs as lhs and rhs may differ in
// the case of shifts. See comment above.
- const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, lhs_ty);
if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
@@ -1372,11 +1371,11 @@ fn binOpRegister(
break :blk rhs_reg;
} else {
const raw_reg = try self.register_manager.allocReg(md.inst, gp);
- break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, lhs_ty);
}
} else blk: {
const raw_reg = try self.register_manager.allocReg(null, gp);
- break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, lhs_ty);
},
};
@@ -1415,7 +1414,7 @@ fn binOpRegister(
.smull,
.umull,
=> .{ .rrr = .{
- .rd = dest_reg.to64(),
+ .rd = dest_reg.toX(),
.rn = lhs_reg,
.rm = rhs_reg,
} },
@@ -1463,7 +1462,7 @@ fn binOpImmediate(
) !MCValue {
const lhs_is_register = lhs == .register;
- if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));
+ if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty));
const lhs_lock: ?RegisterLock = if (lhs_is_register)
self.register_manager.lockReg(lhs.register)
@@ -1481,7 +1480,7 @@ fn binOpImmediate(
} else null;
const raw_reg = try self.register_manager.allocReg(track_inst, gp);
- const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, lhs_ty);
if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
@@ -1502,11 +1501,11 @@ fn binOpImmediate(
break :blk lhs_reg;
} else {
const raw_reg = try self.register_manager.allocReg(md.inst, gp);
- break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, lhs_ty);
}
} else blk: {
const raw_reg = try self.register_manager.allocReg(null, gp);
- break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ break :blk self.registerAlias(raw_reg, lhs_ty);
},
};
@@ -1719,7 +1718,7 @@ fn binOp(
} else null;
const raw_reg = try self.register_manager.allocReg(track_inst, gp);
- const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, lhs_ty);
if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
@@ -1734,7 +1733,7 @@ fn binOp(
} else null;
const raw_reg = try self.register_manager.allocReg(track_inst, gp);
- const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
+ const reg = self.registerAlias(raw_reg, rhs_ty);
if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
@@ -1745,10 +1744,9 @@ fn binOp(
const dest_regs: [2]Register = blk: {
const raw_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
- const abi_size = lhs_ty.abiSize(self.target.*);
break :blk .{
- registerAlias(raw_regs[0], abi_size),
- registerAlias(raw_regs[1], abi_size),
+ self.registerAlias(raw_regs[0], lhs_ty),
+ self.registerAlias(raw_regs[1], lhs_ty),
};
};
const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
@@ -2067,7 +2065,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
defer self.register_manager.unlockReg(dest_reg_lock);
const raw_truncated_reg = try self.register_manager.allocReg(null, gp);
- const truncated_reg = registerAlias(raw_truncated_reg, lhs_ty.abiSize(self.target.*));
+ const truncated_reg = self.registerAlias(raw_truncated_reg, lhs_ty);
const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
defer self.register_manager.unlockReg(truncated_reg_lock);
@@ -2186,8 +2184,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
defer self.register_manager.unlockReg(truncated_reg_lock);
try self.truncRegister(
- dest_reg.to32(),
- truncated_reg.to32(),
+ dest_reg.toW(),
+ truncated_reg.toW(),
int_info.signedness,
int_info.bits,
);
@@ -2197,8 +2195,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
_ = try self.addInst(.{
.tag = .cmp_extended_register,
.data = .{ .rr_extend_shift = .{
- .rn = dest_reg.to64(),
- .rm = truncated_reg.to32(),
+ .rn = dest_reg.toX(),
+ .rm = truncated_reg.toW(),
.ext_type = .sxtw,
.imm3 = 0,
} },
@@ -2208,8 +2206,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
_ = try self.addInst(.{
.tag = .cmp_extended_register,
.data = .{ .rr_extend_shift = .{
- .rn = dest_reg.to64(),
- .rm = truncated_reg.to32(),
+ .rn = dest_reg.toX(),
+ .rm = truncated_reg.toW(),
.ext_type = .uxtw,
.imm3 = 0,
} },
@@ -2245,7 +2243,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const lhs_reg = if (lhs_is_register) lhs.register else blk: {
const raw_reg = try self.register_manager.allocReg(null, gp);
- const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, lhs_ty);
break :blk reg;
};
const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
@@ -2253,7 +2251,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const rhs_reg = if (rhs_is_register) rhs.register else blk: {
const raw_reg = try self.register_manager.allocReg(null, gp);
- const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
+ const reg = self.registerAlias(raw_reg, rhs_ty);
break :blk reg;
};
const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
@@ -2264,7 +2262,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const dest_reg = blk: {
const raw_reg = try self.register_manager.allocReg(null, gp);
- const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
+ const reg = self.registerAlias(raw_reg, lhs_ty);
break :blk reg;
};
const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
@@ -2853,7 +2851,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
-fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
+fn reuseOperand(
+ self: *Self,
+ inst: Air.Inst.Index,
+ operand: Air.Inst.Ref,
+ op_index: Liveness.OperandInt,
+ mcv: MCValue,
+) bool {
if (!self.liveness.operandDies(inst, op_index))
return false;
@@ -2912,7 +2916,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
.stack_offset => |off| {
if (elem_size <= 8) {
const raw_tmp_reg = try self.register_manager.allocReg(null, gp);
- const tmp_reg = registerAlias(raw_tmp_reg, elem_size);
+ const tmp_reg = self.registerAlias(raw_tmp_reg, elem_ty);
const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
defer self.register_manager.unlockReg(tmp_reg_lock);
@@ -3050,7 +3054,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
// The MCValue that holds the pointer can be re-used as the value.
break :blk switch (ptr) {
- .register => |r| MCValue{ .register = registerAlias(r, elem_size) },
+ .register => |reg| MCValue{ .register = self.registerAlias(reg, elem_ty) },
else => ptr,
};
} else {
@@ -3136,7 +3140,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
else => {
if (abi_size <= 8) {
const raw_tmp_reg = try self.register_manager.allocReg(null, gp);
- const tmp_reg = registerAlias(raw_tmp_reg, abi_size);
+ const tmp_reg = self.registerAlias(raw_tmp_reg, value_ty);
const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
defer self.register_manager.unlockReg(tmp_reg_lock);
@@ -3295,7 +3299,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
} else {
// Copy to new register
const raw_dest_reg = try self.register_manager.allocReg(null, gp);
- const dest_reg = registerAlias(raw_dest_reg, struct_field_ty.abiSize(self.target.*));
+ const dest_reg = self.registerAlias(raw_dest_reg, struct_field_ty);
try self.genSetReg(struct_field_ty, dest_reg, field);
break :result MCValue{ .register = dest_reg };
@@ -3410,9 +3414,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
- const ptr_bits = self.target.cpu.arch.ptrBitWidth();
- const ptr_bytes = @divExact(ptr_bits, 8);
- const ret_ptr_reg = registerAlias(.x0, ptr_bytes);
+ const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
var ptr_ty_payload: Type.Payload.ElemType = .{
.base = .{ .tag = .single_mut_pointer },
@@ -4376,7 +4378,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4, 8 => .str_stack,
else => unreachable, // unexpected abi size
};
- const rt = registerAlias(reg, abi_size);
+ const rt = self.registerAlias(reg, ty);
_ = try self.addInst(.{
.tag = tag,
@@ -4399,10 +4401,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
const overflow_bit_ty = ty.structFieldType(1);
const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
const raw_cond_reg = try self.register_manager.allocReg(null, gp);
- const cond_reg = registerAlias(
- raw_cond_reg,
- @intCast(u32, overflow_bit_ty.abiSize(self.target.*)),
- );
+ const cond_reg = self.registerAlias(raw_cond_reg, overflow_bit_ty);
_ = try self.addInst(.{
.tag = .cset,
@@ -4599,8 +4598,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.memory => |addr| {
// The value is in memory at a hard-coded address.
// If the type is a pointer, it means the pointer address is at this memory location.
- try self.genSetReg(ty, reg.to64(), .{ .immediate = addr });
- try self.genLdrRegister(reg, reg.to64(), ty);
+ try self.genSetReg(ty, reg.toX(), .{ .immediate = addr });
+ try self.genLdrRegister(reg, reg.toX(), ty);
},
.stack_offset => |off| {
const abi_size = ty.abiSize(self.target.*);
@@ -4679,7 +4678,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4, 8 => .str_immediate,
else => unreachable, // unexpected abi size
};
- const rt = registerAlias(reg, abi_size);
+ const rt = self.registerAlias(reg, ty);
const offset = switch (abi_size) {
1 => blk: {
if (math.cast(u12, stack_offset)) |imm| {
@@ -5300,7 +5299,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
assert(ret_ty.isError());
result.return_value = .{ .immediate = 0 };
} else if (ret_ty_size <= 8) {
- result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };
+ result.return_value = .{ .register = self.registerAlias(c_abi_int_return_regs[0], ret_ty) };
} else {
return self.fail("TODO support more return types for ARM backend", .{});
}
@@ -5322,7 +5321,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) {
if (param_size <= 8) {
- result.args[i] = .{ .register = registerAlias(c_abi_int_param_regs[ncrn], param_size) };
+ result.args[i] = .{ .register = self.registerAlias(c_abi_int_param_regs[ncrn], ty) };
ncrn += 1;
} else {
return self.fail("TODO MCValues with multiple registers", .{});
@@ -5358,7 +5357,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
assert(ret_ty.isError());
result.return_value = .{ .immediate = 0 };
} else if (ret_ty_size <= 8) {
- result.return_value = .{ .register = registerAlias(.x0, ret_ty_size) };
+ result.return_value = .{ .register = self.registerAlias(.x0, ret_ty) };
} else {
// The result is returned by reference, not by
// value. This means that x0 (or w0 when pointer
@@ -5424,14 +5423,30 @@ fn parseRegName(name: []const u8) ?Register {
return std.meta.stringToEnum(Register, name);
}
-fn registerAlias(reg: Register, size_bytes: u64) Register {
- if (size_bytes == 0) {
- unreachable; // should be comptime-known
- } else if (size_bytes <= 4) {
- return reg.to32();
- } else if (size_bytes <= 8) {
- return reg.to64();
- } else {
- unreachable; // TODO handle floating-point registers
+fn registerAlias(self: *Self, reg: Register, ty: Type) Register {
+ const abi_size = ty.abiSize(self.target.*);
+
+ switch (reg.class()) {
+ .general_purpose => {
+ if (abi_size == 0) {
+ unreachable; // should be comptime-known
+ } else if (abi_size <= 4) {
+ return reg.toW();
+ } else if (abi_size <= 8) {
+ return reg.toX();
+ } else unreachable;
+ },
+ .stack_pointer => unreachable, // we can't store/load the sp
+ .floating_point => {
+ return switch (ty.floatBits(self.target.*)) {
+ 16 => reg.toH(),
+ 32 => reg.toS(),
+ 64 => reg.toD(),
+ 128 => reg.toQ(),
+
+ 80 => unreachable, // f80 registers don't exist
+ else => unreachable,
+ };
+ },
}
}
src/arch/aarch64/Emit.zig
@@ -842,14 +842,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
// PC-relative displacement to the entry in memory.
// adrp
const offset = @intCast(u32, emit.code.items.len);
- try emit.writeInstruction(Instruction.adrp(reg.to64(), 0));
+ try emit.writeInstruction(Instruction.adrp(reg.toX(), 0));
switch (tag) {
.load_memory_got => {
// ldr reg, reg, offset
try emit.writeInstruction(Instruction.ldr(
reg,
- reg.to64(),
+ reg.toX(),
Instruction.LoadStoreOffset.imm(0),
));
},
@@ -863,11 +863,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
// Note that this can potentially be optimised out by the codegen/linker if the
// target address is appropriately aligned.
// add reg, reg, offset
- try emit.writeInstruction(Instruction.add(reg.to64(), reg.to64(), 0, false));
+ try emit.writeInstruction(Instruction.add(reg.toX(), reg.toX(), 0, false));
// ldr reg, reg, offset
try emit.writeInstruction(Instruction.ldr(
reg,
- reg.to64(),
+ reg.toX(),
Instruction.LoadStoreOffset.imm(0),
));
},