aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arch/aarch64/CodeGen.zig355
-rw-r--r--src/arch/aarch64/Emit.zig4
-rw-r--r--src/arch/aarch64/bits.zig130
3 files changed, 322 insertions, 167 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index 2267a156f9..8c7d0a67b4 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -372,7 +372,7 @@ fn gen(self: *Self) !void {
.data = .{ .load_store_register_pair = .{
.rt = .x29,
.rt2 = .x30,
- .rn = Register.sp,
+ .rn = .sp,
.offset = Instruction.LoadStorePairOffset.pre_index(-16),
} },
});
@@ -407,7 +407,7 @@ fn gen(self: *Self) !void {
self.saved_regs_stack_space = 16;
inline for (callee_preserved_regs) |reg| {
if (self.register_manager.isRegAllocated(reg)) {
- saved_regs |= @as(u32, 1) << reg.id();
+ saved_regs |= @as(u32, 1) << @intCast(u5, reg.id());
self.saved_regs_stack_space += 8;
}
}
@@ -449,7 +449,7 @@ fn gen(self: *Self) !void {
// the code. Therefore, we can just delete
// the space initially reserved for the
// jump
- self.mir_instructions.len -= 1;
+ self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.items[0]);
} else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
self.mir_instructions.set(jmp_reloc, .{
.tag = .b,
@@ -475,7 +475,7 @@ fn gen(self: *Self) !void {
.data = .{ .load_store_register_pair = .{
.rt = .x29,
.rt2 = .x30,
- .rn = Register.sp,
+ .rn = .sp,
.offset = Instruction.LoadStorePairOffset.post_index(16),
} },
});
@@ -1041,6 +1041,7 @@ fn binOpRegister(
const mir_tag: Mir.Inst.Tag = switch (tag) {
.add, .ptr_add => .add_shifted_register,
.sub, .ptr_sub => .sub_shifted_register,
+ .mul => .mul,
.xor => .eor_shifted_register,
else => unreachable,
};
@@ -1056,6 +1057,11 @@ fn binOpRegister(
.imm6 = 0,
.shift = .lsl,
} },
+ .mul => .{ .rrr = .{
+ .rd = dest_reg,
+ .rn = lhs_reg,
+ .rm = rhs_reg,
+ } },
.xor => .{ .rrr_imm6_logical_shift = .{
.rd = dest_reg,
.rn = lhs_reg,
@@ -1222,6 +1228,24 @@ fn binOp(
else => unreachable,
}
},
+ .mul => {
+ switch (lhs_ty.zigTypeTag()) {
+ .Vector => return self.fail("TODO binary operations on vectors", .{}),
+ .Int => {
+ assert(lhs_ty.eql(rhs_ty));
+ const int_info = lhs_ty.intInfo(self.target.*);
+ if (int_info.bits <= 64) {
+ // TODO add optimisations for multiplication
+ // with immediates, for example a * 2 can be
+ // lowered to a << 1
+ return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+ } else {
+ return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
+ }
+ },
+ else => unreachable,
+ }
+ },
// Bitwise operations on integers
.xor => {
switch (lhs_ty.zigTypeTag()) {
@@ -1551,88 +1575,37 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
};
self.register_manager.freezeRegs(&.{base_mcv.register});
- // TODO implement optimized ldr for airSliceElemVal
- const dst_mcv = try self.allocRegOrMem(inst, true);
-
- const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size));
- assert(offset_mcv == .register); // result of multiplication should always be register
- self.register_manager.freezeRegs(&.{offset_mcv.register});
+ switch (elem_size) {
+ else => {
+ const dst_mcv = try self.allocRegOrMem(inst, true);
- const addr_reg = try self.register_manager.allocReg(null);
- self.register_manager.freezeRegs(&.{addr_reg});
- defer self.register_manager.unfreezeRegs(&.{addr_reg});
+ const offset_mcv = try self.binOp(
+ .mul,
+ null,
+ index_mcv,
+ .{ .immediate = elem_size },
+ Type.usize,
+ Type.usize,
+ );
+ assert(offset_mcv == .register); // result of multiplication should always be register
+ self.register_manager.freezeRegs(&.{offset_mcv.register});
- _ = try self.addInst(.{
- .tag = .add_shifted_register,
- .data = .{ .rrr_imm6_shift = .{
- .rd = addr_reg,
- .rn = base_mcv.register,
- .rm = offset_mcv.register,
- .imm6 = 0,
- .shift = .lsl,
- } },
- });
+ const addr_mcv = try self.binOp(.add, null, base_mcv, offset_mcv, Type.usize, Type.usize);
- // At this point in time, neither the base register
- // nor the offset register contains any valuable data
- // anymore.
- self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
+ // At this point in time, neither the base register
+ // nor the offset register contains any valuable data
+ // anymore.
+ self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
- try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
+ try self.load(dst_mcv, addr_mcv, slice_ptr_field_type);
- break :result dst_mcv;
+ break :result dst_mcv;
+ },
+ }
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
-fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue {
- const lhs = try self.resolveInst(op);
- const rhs = MCValue{ .immediate = imm };
-
- const lhs_is_register = lhs == .register;
-
- if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
- defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});
-
- // Destination must be a register
- // LHS must be a register
- // RHS must be a register
- var dst_mcv: MCValue = undefined;
- var lhs_mcv: MCValue = lhs;
- var rhs_mcv: MCValue = rhs;
-
- // Allocate registers for operands and/or destination
- // Allocate 1 or 2 registers
- if (lhs_is_register) {
- // Move RHS to register
- dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
- rhs_mcv = dst_mcv;
- } else {
- // Move LHS and RHS to register
- const regs = try self.register_manager.allocRegs(2, .{ null, null });
- lhs_mcv = MCValue{ .register = regs[0] };
- rhs_mcv = MCValue{ .register = regs[1] };
- dst_mcv = lhs_mcv;
- }
-
- // Move the operands to the newly allocated registers
- if (!lhs_is_register) {
- try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs);
- }
- try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs);
-
- _ = try self.addInst(.{
- .tag = .mul,
- .data = .{ .rrr = .{
- .rd = dst_mcv.register,
- .rn = lhs_mcv.register,
- .rm = rhs_mcv.register,
- } },
- });
-
- return dst_mcv;
-}
-
fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -1763,23 +1736,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
self.register_manager.freezeRegs(&.{addr_reg});
defer self.register_manager.unfreezeRegs(&.{addr_reg});
+ const abi_size = elem_ty.abiSize(self.target.*);
switch (dst_mcv) {
.dead => unreachable,
.undef => unreachable,
.compare_flags_signed, .compare_flags_unsigned => unreachable,
.embedded_in_code => unreachable,
.register => |dst_reg| {
- _ = try self.addInst(.{
- .tag = .ldr_immediate,
- .data = .{ .load_store_register_immediate = .{
- .rt = dst_reg,
- .rn = addr_reg,
- .offset = Instruction.LoadStoreOffset.none.immediate,
- } },
- });
+ try self.genLdrRegister(dst_reg, addr_reg, abi_size);
},
.stack_offset => |off| {
- if (elem_ty.abiSize(self.target.*) <= 8) {
+ if (abi_size <= 8) {
const tmp_reg = try self.register_manager.allocReg(null);
self.register_manager.freezeRegs(&.{tmp_reg});
defer self.register_manager.unfreezeRegs(&.{tmp_reg});
@@ -1940,6 +1907,100 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
+fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
+ switch (abi_size) {
+ 1 => {
+ _ = try self.addInst(.{
+ .tag = .ldrb_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to32(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 2 => {
+ _ = try self.addInst(.{
+ .tag = .ldrh_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to32(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 4 => {
+ _ = try self.addInst(.{
+ .tag = .ldr_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to32(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 8 => {
+ _ = try self.addInst(.{
+ .tag = .ldr_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to64(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}),
+ else => unreachable,
+ }
+}
+
+fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
+ switch (abi_size) {
+ 1 => {
+ _ = try self.addInst(.{
+ .tag = .strb_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to32(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 2 => {
+ _ = try self.addInst(.{
+ .tag = .strh_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to32(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 4 => {
+ _ = try self.addInst(.{
+ .tag = .str_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to32(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 8 => {
+ _ = try self.addInst(.{
+ .tag = .str_immediate,
+ .data = .{ .load_store_register_immediate = .{
+ .rt = value_reg.to64(),
+ .rn = addr_reg,
+ .offset = Instruction.LoadStoreOffset.none.immediate,
+ } },
+ });
+ },
+ 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}),
+ else => unreachable,
+ }
+}
+
fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
switch (ptr) {
.none => unreachable,
@@ -1960,8 +2021,28 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.embedded_in_code => {
return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
},
- .register => {
- return self.fail("TODO implement storing to MCValue.register", .{});
+ .register => |addr_reg| {
+ self.register_manager.freezeRegs(&.{addr_reg});
+ defer self.register_manager.unfreezeRegs(&.{addr_reg});
+
+ const abi_size = value_ty.abiSize(self.target.*);
+ switch (value) {
+ .register => |value_reg| {
+ try self.genStrRegister(value_reg, addr_reg, abi_size);
+ },
+ else => {
+ if (abi_size <= 8) {
+ const tmp_reg = try self.register_manager.allocReg(null);
+ self.register_manager.freezeRegs(&.{tmp_reg});
+ defer self.register_manager.unfreezeRegs(&.{tmp_reg});
+
+ try self.genSetReg(value_ty, tmp_reg, value);
+ try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
+ } else {
+ return self.fail("TODO implement memcpy", .{});
+ }
+ },
+ }
},
.memory,
.stack_offset,
@@ -2005,7 +2086,8 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
return if (self.liveness.isUnused(inst)) .dead else result: {
const mcv = try self.resolveInst(operand);
- const struct_ty = self.air.typeOf(operand).childType();
+ const ptr_ty = self.air.typeOf(operand);
+ const struct_ty = ptr_ty.childType();
const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
const struct_field_ty = struct_ty.structFieldType(index);
@@ -2014,7 +2096,28 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
.ptr_stack_offset => |off| {
break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size };
},
- else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
+ else => {
+ const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
+ .immediate = struct_field_offset,
+ });
+ self.register_manager.freezeRegs(&.{offset_reg});
+ defer self.register_manager.unfreezeRegs(&.{offset_reg});
+
+ const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv);
+ self.register_manager.freezeRegs(&.{addr_reg});
+ defer self.register_manager.unfreezeRegs(&.{addr_reg});
+
+ const dest = try self.binOp(
+ .add,
+ null,
+ .{ .register = addr_reg },
+ .{ .register = offset_reg },
+ Type.usize,
+ Type.usize,
+ );
+
+ break :result dest;
+ },
}
};
}
@@ -2983,8 +3086,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
const abi_size = ty.abiSize(self.target.*);
switch (mcv) {
.dead => unreachable,
- .ptr_stack_offset => unreachable,
- .ptr_embedded_in_code => unreachable,
.unreach, .none => return, // Nothing to do.
.undef => {
if (!self.wantSafety())
@@ -3001,6 +3102,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.compare_flags_unsigned,
.compare_flags_signed,
.immediate,
+ .ptr_stack_offset,
+ .ptr_embedded_in_code,
=> {
const reg = try self.copyToTmpRegister(ty, mcv);
return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
@@ -3043,17 +3146,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
_ = sym_index;
return self.fail("TODO implement set stack variable from {}", .{mcv});
},
- .memory => |vaddr| {
- _ = vaddr;
- return self.fail("TODO implement set stack variable from memory vaddr", .{});
- },
- .stack_offset => |off| {
- if (stack_offset == off)
- return; // Copy stack variable to itself; nothing to do.
+ .memory,
+ .stack_offset,
+ => {
+ switch (mcv) {
+ .stack_offset => |off| {
+ if (stack_offset == off)
+ return; // Copy stack variable to itself; nothing to do.
+ },
+ else => {},
+ }
- const ptr_bits = self.target.cpu.arch.ptrBitWidth();
- const ptr_bytes: u64 = @divExact(ptr_bits, 8);
- if (abi_size <= ptr_bytes) {
+ if (abi_size <= 8) {
const reg = try self.copyToTmpRegister(ty, mcv);
return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
} else {
@@ -3068,17 +3172,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
const count_reg = regs[3];
const tmp_reg = regs[4];
- // sub src_reg, fp, #off
- const adj_src_offset = off + abi_size;
- const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
- _ = try self.addInst(.{
- .tag = .sub_immediate,
- .data = .{ .rr_imm12_sh = .{
- .rd = src_reg,
- .rn = .x29,
- .imm12 = src_offset,
- } },
- });
+ switch (mcv) {
+ .stack_offset => |off| {
+ // sub src_reg, fp, #off
+ const adj_src_offset = off + abi_size;
+ const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
+ _ = try self.addInst(.{
+ .tag = .sub_immediate,
+ .data = .{ .rr_imm12_sh = .{
+ .rd = src_reg,
+ .rn = .x29,
+ .imm12 = src_offset,
+ } },
+ });
+ },
+ .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
+ else => unreachable,
+ }
// sub dst_reg, fp, #stack_offset
const adj_dst_off = stack_offset + abi_size;
@@ -3105,7 +3215,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
switch (mcv) {
.dead => unreachable,
- .ptr_stack_offset => unreachable,
.ptr_embedded_in_code => unreachable,
.unreach, .none => return, // Nothing to do.
.undef => {
@@ -3118,6 +3227,24 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
else => unreachable, // unexpected register size
}
},
+ .ptr_stack_offset => |unadjusted_off| {
+ // TODO: maybe addressing from sp instead of fp
+ const elem_ty = ty.childType();
+ const abi_size = elem_ty.abiSize(self.target.*);
+ const adj_off = unadjusted_off + abi_size;
+
+ const imm12 = math.cast(u12, adj_off) catch
+ return self.fail("TODO larger stack offsets", .{});
+
+ _ = try self.addInst(.{
+ .tag = .sub_immediate,
+ .data = .{ .rr_imm12_sh = .{
+ .rd = reg,
+ .rn = .x29,
+ .imm12 = imm12,
+ } },
+ });
+ },
.compare_flags_unsigned,
.compare_flags_signed,
=> |op| {
diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig
index 77f400ea78..dd297d048d 100644
--- a/src/arch/aarch64/Emit.zig
+++ b/src/arch/aarch64/Emit.zig
@@ -909,7 +909,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
var other_reg: Register = undefined;
while (i > 0) : (i -= 1) {
const reg = @intToEnum(Register, i - 1);
- if (reg_list & @as(u32, 1) << reg.id() != 0) {
+ if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) {
if (count % 2 == 0) {
if (count == number_of_regs - 1) {
try emit.writeInstruction(Instruction.ldr(
@@ -939,7 +939,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
var other_reg: Register = undefined;
while (i < 32) : (i += 1) {
const reg = @intToEnum(Register, i);
- if (reg_list & @as(u32, 1) << reg.id() != 0) {
+ if (reg_list & @as(u32, 1) << @intCast(u5, reg.id()) != 0) {
if (count % 2 == 0) {
if (count == number_of_regs - 1) {
try emit.writeInstruction(Instruction.str(
diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig
index a5d56cfcc7..1670f88c76 100644
--- a/src/arch/aarch64/bits.zig
+++ b/src/arch/aarch64/bits.zig
@@ -7,7 +7,7 @@ const testing = std.testing;
// zig fmt: off
/// General purpose registers in the AArch64 instruction set
-pub const Register = enum(u6) {
+pub const Register = enum(u7) {
// 64-bit registers
x0, x1, x2, x3, x4, x5, x6, x7,
x8, x9, x10, x11, x12, x13, x14, x15,
@@ -20,10 +20,23 @@ pub const Register = enum(u6) {
w16, w17, w18, w19, w20, w21, w22, w23,
w24, w25, w26, w27, w28, w29, w30, wzr,
- pub const sp = Register.xzr;
+ // Stack pointer
+ sp, wsp,
- pub fn id(self: Register) u5 {
- return @truncate(u5, @enumToInt(self));
+ 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.
@@ -31,17 +44,32 @@ pub const Register = enum(u6) {
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 @intToEnum(Register, self.id());
+ 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 @intToEnum(Register, @as(u6, self.id()) + 32);
+ return switch (@enumToInt(self)) {
+ 0...31 => @intToEnum(Register, @enumToInt(self) + 32),
+ 32...63 => self,
+ 64 => .wsp,
+ 65 => .wsp,
+ else => unreachable,
+ };
}
/// Returns the index into `callee_preserved_regs`.
@@ -53,7 +81,7 @@ pub const Register = enum(u6) {
}
pub fn dwarfLocOp(self: Register) u8 {
- return @as(u8, self.id()) + DW.OP.reg0;
+ return @as(u8, self.enc()) + DW.OP.reg0;
}
};
@@ -76,15 +104,15 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re
pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
-test "Register.id" {
- try testing.expectEqual(@as(u5, 0), Register.x0.id());
- try testing.expectEqual(@as(u5, 0), Register.w0.id());
+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.id());
- try testing.expectEqual(@as(u5, 31), Register.wzr.id());
+ 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.id());
- try testing.expectEqual(@as(u5, 31), Register.sp.id());
+ try testing.expectEqual(@as(u5, 31), Register.sp.enc());
+ try testing.expectEqual(@as(u5, 31), Register.sp.enc());
}
test "Register.size" {
@@ -479,7 +507,7 @@ pub const Instruction = union(enum) {
assert(shift % 16 == 0 and shift <= 16);
return Instruction{
.move_wide_immediate = .{
- .rd = rd.id(),
+ .rd = rd.enc(),
.imm16 = imm16,
.hw = @intCast(u2, shift / 16),
.opc = opc,
@@ -491,7 +519,7 @@ pub const Instruction = union(enum) {
assert(shift % 16 == 0 and shift <= 48);
return Instruction{
.move_wide_immediate = .{
- .rd = rd.id(),
+ .rd = rd.enc(),
.imm16 = imm16,
.hw = @intCast(u2, shift / 16),
.opc = opc,
@@ -508,7 +536,7 @@ pub const Instruction = union(enum) {
const imm21_u = @bitCast(u21, imm21);
return Instruction{
.pc_relative_address = .{
- .rd = rd.id(),
+ .rd = rd.enc(),
.immlo = @truncate(u2, imm21_u),
.immhi = @truncate(u19, imm21_u >> 2),
.op = op,
@@ -580,7 +608,7 @@ pub const Instruction = union(enum) {
pub fn reg(rm: Register) LoadStoreOffset {
return .{
.register = .{
- .rm = rm.id(),
+ .rm = rm.enc(),
.shift = .{
.lsl = 0,
},
@@ -592,7 +620,7 @@ pub const Instruction = union(enum) {
assert(rm.size() == 32 and (shift == 0 or shift == 2));
return .{
.register = .{
- .rm = rm.id(),
+ .rm = rm.enc(),
.shift = .{
.uxtw = shift,
},
@@ -604,7 +632,7 @@ pub const Instruction = union(enum) {
assert(rm.size() == 64 and (shift == 0 or shift == 3));
return .{
.register = .{
- .rm = rm.id(),
+ .rm = rm.enc(),
.shift = .{
.lsl = shift,
},
@@ -616,7 +644,7 @@ pub const Instruction = union(enum) {
assert(rm.size() == 32 and (shift == 0 or shift == 2));
return .{
.register = .{
- .rm = rm.id(),
+ .rm = rm.enc(),
.shift = .{
.sxtw = shift,
},
@@ -628,7 +656,7 @@ pub const Instruction = union(enum) {
assert(rm.size() == 64 and (shift == 0 or shift == 3));
return .{
.register = .{
- .rm = rm.id(),
+ .rm = rm.enc(),
.shift = .{
.sxtx = shift,
},
@@ -676,8 +704,8 @@ pub const Instruction = union(enum) {
};
return Instruction{
.load_store_register = .{
- .rt = rt.id(),
- .rn = rn.id(),
+ .rt = rt.enc(),
+ .rn = rn.enc(),
.offset = off,
.opc = opc,
.op1 = op1,
@@ -711,9 +739,9 @@ pub const Instruction = union(enum) {
const imm7 = @truncate(u7, @bitCast(u9, offset >> 2));
return Instruction{
.load_store_register_pair = .{
- .rt1 = rt1.id(),
- .rn = rn.id(),
- .rt2 = rt2.id(),
+ .rt1 = rt1.enc(),
+ .rn = rn.enc(),
+ .rt2 = rt2.enc(),
.imm7 = imm7,
.load = @boolToInt(load),
.encoding = encoding,
@@ -726,9 +754,9 @@ pub const Instruction = union(enum) {
const imm7 = @truncate(u7, @bitCast(u9, offset >> 3));
return Instruction{
.load_store_register_pair = .{
- .rt1 = rt1.id(),
- .rn = rn.id(),
- .rt2 = rt2.id(),
+ .rt1 = rt1.enc(),
+ .rn = rn.enc(),
+ .rt2 = rt2.enc(),
.imm7 = imm7,
.load = @boolToInt(load),
.encoding = encoding,
@@ -743,7 +771,7 @@ pub const Instruction = union(enum) {
fn loadLiteral(rt: Register, imm19: u19) Instruction {
return Instruction{
.load_literal = .{
- .rt = rt.id(),
+ .rt = rt.enc(),
.imm19 = imm19,
.opc = switch (rt.size()) {
32 => 0b00,
@@ -782,7 +810,7 @@ pub const Instruction = union(enum) {
return Instruction{
.unconditional_branch_register = .{
.op4 = op4,
- .rn = rn.id(),
+ .rn = rn.enc(),
.op3 = op3,
.op2 = op2,
.opc = opc,
@@ -818,10 +846,10 @@ pub const Instruction = union(enum) {
assert(amount < 32);
return Instruction{
.logical_shifted_register = .{
- .rd = rd.id(),
- .rn = rn.id(),
+ .rd = rd.enc(),
+ .rn = rn.enc(),
.imm6 = amount,
- .rm = rm.id(),
+ .rm = rm.enc(),
.n = n,
.shift = @enumToInt(shift),
.opc = opc,
@@ -832,10 +860,10 @@ pub const Instruction = union(enum) {
64 => {
return Instruction{
.logical_shifted_register = .{
- .rd = rd.id(),
- .rn = rn.id(),
+ .rd = rd.enc(),
+ .rn = rn.enc(),
.imm6 = amount,
- .rm = rm.id(),
+ .rm = rm.enc(),
.n = n,
.shift = @enumToInt(shift),
.opc = opc,
@@ -857,8 +885,8 @@ pub const Instruction = union(enum) {
) Instruction {
return Instruction{
.add_subtract_immediate = .{
- .rd = rd.id(),
- .rn = rn.id(),
+ .rd = rd.enc(),
+ .rn = rn.enc(),
.imm12 = imm12,
.sh = @boolToInt(shift),
.s = s,
@@ -885,10 +913,10 @@ pub const Instruction = union(enum) {
) Instruction {
return Instruction{
.add_subtract_shifted_register = .{
- .rd = rd.id(),
- .rn = rn.id(),
+ .rd = rd.enc(),
+ .rn = rn.enc(),
.imm6 = imm6,
- .rm = rm.id(),
+ .rm = rm.enc(),
.shift = @enumToInt(shift),
.s = s,
.op = op,
@@ -926,7 +954,7 @@ pub const Instruction = union(enum) {
assert(offset & 0b11 == 0b00);
return Instruction{
.compare_and_branch = .{
- .rt = rt.id(),
+ .rt = rt.enc(),
.imm19 = @bitCast(u19, @intCast(i19, offset >> 2)),
.op = op,
.sf = switch (rt.size()) {
@@ -949,11 +977,11 @@ pub const Instruction = union(enum) {
) Instruction {
return Instruction{
.conditional_select = .{
- .rd = rd.id(),
- .rn = rn.id(),
+ .rd = rd.enc(),
+ .rn = rn.enc(),
.op2 = op2,
.cond = @enumToInt(cond),
- .rm = rm.id(),
+ .rm = rm.enc(),
.s = s,
.op = op,
.sf = switch (rd.size()) {
@@ -976,11 +1004,11 @@ pub const Instruction = union(enum) {
) Instruction {
return Instruction{
.data_processing_3_source = .{
- .rd = rd.id(),
- .rn = rn.id(),
- .ra = ra.id(),
+ .rd = rd.enc(),
+ .rn = rn.enc(),
+ .ra = ra.enc(),
.o0 = o0,
- .rm = rm.id(),
+ .rm = rm.enc(),
.op31 = op31,
.op54 = op54,
.sf = switch (rd.size()) {