mirror of
https://github.com/ziglang/zig.git
synced 2025-12-28 17:13:19 +00:00
Merge pull request #13236 from joachimschmidt557/stage2-aarch64
stage2 AArch64: move to new allocRegs mechanism
This commit is contained in:
commit
41575b1f55
File diff suppressed because it is too large
Load Diff
@ -150,6 +150,7 @@ pub fn emitMir(
|
||||
.ldp => try emit.mirLoadStoreRegisterPair(inst),
|
||||
.stp => try emit.mirLoadStoreRegisterPair(inst),
|
||||
|
||||
.ldr_ptr_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldr_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldrb_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldrh_stack => try emit.mirLoadStoreStack(inst),
|
||||
@ -159,8 +160,8 @@ pub fn emitMir(
|
||||
.strb_stack => try emit.mirLoadStoreStack(inst),
|
||||
.strh_stack => try emit.mirLoadStoreStack(inst),
|
||||
|
||||
.ldr_stack_argument => try emit.mirLoadStackArgument(inst),
|
||||
.ldr_ptr_stack_argument => try emit.mirLoadStackArgument(inst),
|
||||
.ldr_stack_argument => try emit.mirLoadStackArgument(inst),
|
||||
.ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
|
||||
.ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
|
||||
.ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
|
||||
@ -842,14 +843,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 +864,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),
|
||||
));
|
||||
},
|
||||
@ -1003,23 +1004,43 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const rt = load_store_stack.rt;
|
||||
|
||||
const raw_offset = emit.stack_size - load_store_stack.offset;
|
||||
const offset = switch (tag) {
|
||||
.ldrb_stack, .ldrsb_stack, .strb_stack => blk: {
|
||||
if (math.cast(u12, raw_offset)) |imm| {
|
||||
break :blk Instruction.LoadStoreOffset.imm(imm);
|
||||
} else {
|
||||
switch (tag) {
|
||||
.ldr_ptr_stack => {
|
||||
const offset = if (math.cast(u12, raw_offset)) |imm| imm else {
|
||||
return emit.fail("TODO load stack argument ptr with larger offset", .{});
|
||||
};
|
||||
|
||||
switch (tag) {
|
||||
.ldr_ptr_stack => try emit.writeInstruction(Instruction.add(rt, .sp, offset, false)),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.ldrb_stack, .ldrsb_stack, .strb_stack => {
|
||||
const offset = if (math.cast(u12, raw_offset)) |imm| Instruction.LoadStoreOffset.imm(imm) else {
|
||||
return emit.fail("TODO load/store stack byte with larger offset", .{});
|
||||
};
|
||||
|
||||
switch (tag) {
|
||||
.ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
|
||||
.ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
|
||||
.strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.ldrh_stack, .ldrsh_stack, .strh_stack => blk: {
|
||||
.ldrh_stack, .ldrsh_stack, .strh_stack => {
|
||||
assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry
|
||||
if (math.cast(u12, @divExact(raw_offset, 2))) |imm| {
|
||||
break :blk Instruction.LoadStoreOffset.imm(imm);
|
||||
} else {
|
||||
const offset = if (math.cast(u12, @divExact(raw_offset, 2))) |imm| Instruction.LoadStoreOffset.imm(imm) else {
|
||||
return emit.fail("TODO load/store stack halfword with larger offset", .{});
|
||||
};
|
||||
|
||||
switch (tag) {
|
||||
.ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
|
||||
.ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
|
||||
.strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.ldr_stack, .str_stack => blk: {
|
||||
.ldr_stack, .str_stack => {
|
||||
const alignment: u32 = switch (rt.size()) {
|
||||
32 => 4,
|
||||
64 => 8,
|
||||
@ -1027,25 +1048,17 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
};
|
||||
|
||||
assert(std.mem.isAlignedGeneric(u32, raw_offset, alignment)); // misaligned stack entry
|
||||
if (math.cast(u12, @divExact(raw_offset, alignment))) |imm| {
|
||||
break :blk Instruction.LoadStoreOffset.imm(imm);
|
||||
} else {
|
||||
const offset = if (math.cast(u12, @divExact(raw_offset, alignment))) |imm| Instruction.LoadStoreOffset.imm(imm) else {
|
||||
return emit.fail("TODO load/store stack with larger offset", .{});
|
||||
};
|
||||
|
||||
switch (tag) {
|
||||
.ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
|
||||
.str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
switch (tag) {
|
||||
.ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
|
||||
.ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
|
||||
.ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
|
||||
.ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
|
||||
.ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
|
||||
.str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)),
|
||||
.strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)),
|
||||
.strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -92,6 +92,8 @@ pub const Inst = struct {
|
||||
load_memory_ptr_direct,
|
||||
/// Load Pair of Registers
|
||||
ldp,
|
||||
/// Pseudo-instruction: Load pointer to stack item
|
||||
ldr_ptr_stack,
|
||||
/// Pseudo-instruction: Load pointer to stack argument
|
||||
ldr_ptr_stack_argument,
|
||||
/// Pseudo-instruction: Load from stack
|
||||
@ -432,7 +434,7 @@ pub const Inst = struct {
|
||||
rn: Register,
|
||||
offset: bits.Instruction.LoadStoreOffsetRegister,
|
||||
},
|
||||
/// A registers and a stack offset
|
||||
/// A register and a stack offset
|
||||
///
|
||||
/// Used by e.g. str_stack
|
||||
load_store_stack: struct {
|
||||
@ -464,10 +466,6 @@ pub const Inst = struct {
|
||||
line: u32,
|
||||
column: u32,
|
||||
},
|
||||
load_memory: struct {
|
||||
register: u32,
|
||||
addr: u32,
|
||||
},
|
||||
};
|
||||
|
||||
// Make sure we don't accidentally make instructions bigger than expected.
|
||||
|
||||
@ -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,51 +28,267 @@ pub const Register = enum(u7) {
|
||||
// Stack pointer
|
||||
sp, wsp,
|
||||
|
||||
// 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 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 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 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 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 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)) {
|
||||
0...63 => return @as(u6, @truncate(u5, @enumToInt(self))),
|
||||
64...65 => 32,
|
||||
@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)) {
|
||||
0...63 => return @truncate(u5, @enumToInt(self)),
|
||||
64...65 => 31,
|
||||
@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: Register) u7 {
|
||||
pub fn size(self: Register) u8 {
|
||||
return switch (@enumToInt(self)) {
|
||||
0...31 => 64,
|
||||
32...63 => 32,
|
||||
64 => 64,
|
||||
65 => 32,
|
||||
@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 any register to its 64 bit alias.
|
||||
pub fn to64(self: Register) Register {
|
||||
/// Convert from a general-purpose register to its 64 bit alias.
|
||||
pub fn toX(self: Register) Register {
|
||||
return switch (@enumToInt(self)) {
|
||||
0...31 => self,
|
||||
32...63 => @intToEnum(Register, @enumToInt(self) - 32),
|
||||
64 => .sp,
|
||||
65 => .sp,
|
||||
@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 any register to its 32 bit alias.
|
||||
pub fn to32(self: Register) Register {
|
||||
/// Convert from a general-purpose register to its 32 bit alias.
|
||||
pub fn toW(self: Register) Register {
|
||||
return switch (@enumToInt(self)) {
|
||||
0...31 => @intToEnum(Register, @enumToInt(self) + 32),
|
||||
32...63 => self,
|
||||
64 => .wsp,
|
||||
65 => .wsp,
|
||||
@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 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 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 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 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,
|
||||
};
|
||||
}
|
||||
@ -77,8 +298,6 @@ pub const Register = enum(u7) {
|
||||
}
|
||||
};
|
||||
|
||||
// zig fmt: on
|
||||
|
||||
test "Register.enc" {
|
||||
try testing.expectEqual(@as(u5, 0), Register.x0.enc());
|
||||
try testing.expectEqual(@as(u5, 0), Register.w0.enc());
|
||||
@ -91,124 +310,16 @@ test "Register.enc" {
|
||||
}
|
||||
|
||||
test "Register.size" {
|
||||
try testing.expectEqual(@as(u7, 64), Register.x19.size());
|
||||
try testing.expectEqual(@as(u7, 32), Register.w3.size());
|
||||
try testing.expectEqual(@as(u8, 64), Register.x19.size());
|
||||
try testing.expectEqual(@as(u8, 32), Register.w3.size());
|
||||
}
|
||||
|
||||
test "Register.to64/to32" {
|
||||
try testing.expectEqual(Register.x0, Register.w0.to64());
|
||||
try testing.expectEqual(Register.x0, Register.x0.to64());
|
||||
test "Register.toX/toW" {
|
||||
try testing.expectEqual(Register.x0, Register.w0.toX());
|
||||
try testing.expectEqual(Register.x0, Register.x0.toX());
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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,
|
||||
|
||||
pub fn id(self: FloatingPointRegister) u5 {
|
||||
return @truncate(u5, @enumToInt(self));
|
||||
}
|
||||
|
||||
/// Returns the bit-width of the register.
|
||||
pub fn size(self: FloatingPointRegister) u8 {
|
||||
return switch (@enumToInt(self)) {
|
||||
0...31 => 128,
|
||||
32...63 => 64,
|
||||
64...95 => 32,
|
||||
96...127 => 16,
|
||||
128...159 => 8,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Convert from any register to its 128 bit alias.
|
||||
pub fn to128(self: FloatingPointRegister) FloatingPointRegister {
|
||||
return @intToEnum(FloatingPointRegister, self.id());
|
||||
}
|
||||
|
||||
/// 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 any register to its 32 bit alias.
|
||||
pub fn to32(self: FloatingPointRegister) FloatingPointRegister {
|
||||
return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 64);
|
||||
}
|
||||
|
||||
/// 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 any register to its 8 bit alias.
|
||||
pub fn to8(self: FloatingPointRegister) FloatingPointRegister {
|
||||
return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 128);
|
||||
}
|
||||
};
|
||||
|
||||
// zig fmt: on
|
||||
|
||||
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, 2), FloatingPointRegister.q2.id());
|
||||
try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d31.id());
|
||||
}
|
||||
|
||||
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 "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());
|
||||
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user