goalc/arm: PC relative loads/stores, and simple moves

This commit is contained in:
Tyler Wilding
2026-04-14 20:05:36 -04:00
parent 5ce86d50a1
commit f738e96df6
5 changed files with 257 additions and 115 deletions
+17 -17
View File
@@ -32,23 +32,23 @@ Instruction mov_gpr64_s32(const ObjectGenerator& gen, Register dst, int64_t val)
}
Instruction movd_gpr32_xmm32(const ObjectGenerator& gen, Register dst, Register src) {
IGEN_DISPATCH(movd_gpr32_xmm32, dst, src);
IGEN_DISPATCH(movd_gpr32_f32, dst, src);
}
Instruction movd_xmm32_gpr32(const ObjectGenerator& gen, Register dst, Register src) {
IGEN_DISPATCH(movd_xmm32_gpr32, dst, src);
IGEN_DISPATCH(movd_f32_gpr32, dst, src);
}
Instruction movq_gpr64_xmm64(const ObjectGenerator& gen, Register dst, Register src) {
IGEN_DISPATCH(movq_gpr64_xmm64, dst, src);
IGEN_DISPATCH(movq_gpr64_f64, dst, src);
}
Instruction movq_xmm64_gpr64(const ObjectGenerator& gen, Register dst, Register src) {
IGEN_DISPATCH(movq_xmm64_gpr64, dst, src);
IGEN_DISPATCH(movq_f64_gpr64, dst, src);
}
Instruction mov_xmm32_xmm32(const ObjectGenerator& gen, Register dst, Register src) {
IGEN_DISPATCH(mov_xmm32_xmm32, dst, src);
IGEN_DISPATCH(mov_f32_f32, dst, src);
}
Instruction load8s_gpr64_gpr64_plus_gpr64(const ObjectGenerator& gen,
@@ -516,31 +516,31 @@ Instruction store128_xmm128_reg_offset(const ObjectGenerator& gen,
}
Instruction load64_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load64_rip_s32, dest, offset);
IGEN_DISPATCH(load64_pcRel_s32, dest, offset);
}
Instruction load32s_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load32s_rip_s32, dest, offset);
IGEN_DISPATCH(load32s_pcRel_s32, dest, offset);
}
Instruction load32u_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load32u_rip_s32, dest, offset);
IGEN_DISPATCH(load32u_pcRel_s32, dest, offset);
}
Instruction load16u_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load16u_rip_s32, dest, offset);
IGEN_DISPATCH(load16u_pcRel_s32, dest, offset);
}
Instruction load16s_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load16s_rip_s32, dest, offset);
IGEN_DISPATCH(load16s_pcRel_s32, dest, offset);
}
Instruction load8u_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load8u_rip_s32, dest, offset);
IGEN_DISPATCH(load8u_pcRel_s32, dest, offset);
}
Instruction load8s_rip_s32(const ObjectGenerator& gen, Register dest, s64 offset) {
IGEN_DISPATCH(load8s_rip_s32, dest, offset);
IGEN_DISPATCH(load8s_pcRel_s32, dest, offset);
}
Instruction static_load(const ObjectGenerator& gen,
@@ -552,19 +552,19 @@ Instruction static_load(const ObjectGenerator& gen,
}
Instruction store64_rip_s32(const ObjectGenerator& gen, Register src, s64 offset) {
IGEN_DISPATCH(store64_rip_s32, src, offset);
IGEN_DISPATCH(store64_pcRel_s32, src, offset);
}
Instruction store32_rip_s32(const ObjectGenerator& gen, Register src, s64 offset) {
IGEN_DISPATCH(store32_rip_s32, src, offset);
IGEN_DISPATCH(store32_pcRel_s32, src, offset);
}
Instruction store16_rip_s32(const ObjectGenerator& gen, Register src, s64 offset) {
IGEN_DISPATCH(store16_rip_s32, src, offset);
IGEN_DISPATCH(store16_pcRel_s32, src, offset);
}
Instruction store8_rip_s32(const ObjectGenerator& gen, Register src, s64 offset) {
IGEN_DISPATCH(store8_rip_s32, src, offset);
IGEN_DISPATCH(store8_pcRel_s32, src, offset);
}
Instruction static_store(const ObjectGenerator& gen, Register value, s64 offset, int size) {
@@ -576,7 +576,7 @@ Instruction static_addr(const ObjectGenerator& gen, Register dst, s64 offset) {
}
Instruction static_load_xmm32(const ObjectGenerator& gen, Register simd_dest, s64 offset) {
IGEN_DISPATCH(static_load_xmm32, simd_dest, offset);
IGEN_DISPATCH(static_load_fp32, simd_dest, offset);
}
Instruction static_store_xmm32(const ObjectGenerator& gen, Register xmm_value, s64 offset) {
+190 -66
View File
@@ -23,8 +23,7 @@ using namespace emitter::ARM64;
InstructionARM64 mov_gpr64_gpr64(Register dst, Register src) {
// https://www.scs.stanford.edu/~zyedidia/arm64/mov_orr_log_shift.html
// sf 0 1 0 1 0 1 0 0 0 0 Rm 0
// 0 0 0 0 0 1 1 1 1 1 Rd MOV <Xd>, <Xm>
// MOV <Xd>, <Xm>
ASSERT(dst.is_gpr(instr_set));
ASSERT(src.is_gpr(instr_set));
return InstructionARM64(Base(0b10101010000, 11), Rm(src.id()), Rn(0b11111), Rd(dst.id()),
@@ -32,50 +31,79 @@ InstructionARM64 mov_gpr64_gpr64(Register dst, Register src) {
}
InstructionARM64 mov_gpr64_u64(Register dst, uint64_t val) {
// TODO - cannot be done in a single arm64 instruction
// multiple https://www.scs.stanford.edu/~zyedidia/arm64/movk.html are needed
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
// Cannot be done in a single instruction, must combine multiple MOVZ/MOVKs
std::vector<InstructionARM64> instrs;
bool emitted_movz = false;
for (int i = 0; i < 4; i++) {
u16 chunk = (val >> (i * 16)) & 0xFFFF;
if (!emitted_movz && chunk != 0) {
// https://www.scs.stanford.edu/~zyedidia/arm64/movz.html
// MOVZ <Xd>, #<imm>{, LSL #<shift>/16}
instrs.emplace_back(
InstructionARM64(Base(0b110100101, 9), Hw(i), Imm16(chunk), Rd(dst.id())));
emitted_movz = true;
} else if (emitted_movz && chunk != 0) {
// https://www.scs.stanford.edu/~zyedidia/arm64/movk.html
// MOVK <Xd>, #<imm>{, LSL #<shift>/16}
instrs.emplace_back(
InstructionARM64(Base(0b111100101, 9), Hw(i), Imm16(chunk), Rd(dst.id())));
}
}
if (!emitted_movz) {
// https://www.scs.stanford.edu/~zyedidia/arm64/movz.html
// MOVZ <Xd>, #<imm>{, LSL #0}
instrs.emplace_back(InstructionARM64(Base(0b110100101, 9), Hw(0), Imm16(0), Rd(dst.id())));
}
return InstructionARM64(instrs);
}
InstructionARM64 mov_gpr64_u32(Register dst, uint64_t val) {
// TODO - cannot be done in a single arm64 instruction
// multiple https://www.scs.stanford.edu/~zyedidia/arm64/movk.html are needed
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
return mov_gpr64_u64(dst, val);
}
InstructionARM64 mov_gpr64_s32(Register dst, int64_t val) {
// TODO - cannot be done in a single arm64 instruction
// multiple https://www.scs.stanford.edu/~zyedidia/arm64/movk.html are needed
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
// preserve sign -- but we are are simply moving the bits
u64 raw_val = static_cast<u64>(val); // via int64_t → sign already there
return mov_gpr64_u64(dst, raw_val);
}
// TODO - should these be make generic to simdX?
InstructionARM64 movd_gpr32_xmm32(Register dst, Register src) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 movd_gpr32_f32(Register dst, Register src) {
// https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_gen.html
// Single-precision to 32-bit (sf == 0 && ftype == 00 && rmode == 00 && opcode == 110)
// FMOV <Wd>, <Sn>
ASSERT(dst.is_gpr(instr_set));
return InstructionARM64(Base(0b0001111000100110000000, 22), Rn(src.id()), Rd(dst.id()));
}
InstructionARM64 movd_xmm32_gpr32(Register dst, Register src) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 movd_f32_gpr32(Register dst, Register src) {
// https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_gen.html
// 32-bit to single-precision (sf == 0 && ftype == 00 && rmode == 00 && opcode == 111)
// FMOV <Sd>, <Wn>
ASSERT(src.is_gpr(instr_set));
return InstructionARM64(Base(0b0001111000100111000000, 22), Rn(src.id()), Rd(dst.id()));
}
InstructionARM64 movq_gpr64_xmm64(Register dst, Register src) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 movq_gpr64_f64(Register dst, Register src) {
// https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_gen.html
// Double-precision to 64-bit (sf == 1 && ftype == 01 && rmode == 00 && opcode == 110)
// FMOV <Xd>, <Dn>
ASSERT(dst.is_gpr(instr_set));
return InstructionARM64(Base(0b1001111001100110000000, 22), Rn(src.id()), Rd(dst.id()));
}
InstructionARM64 movq_xmm64_gpr64(Register dst, Register src) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 movq_f64_gpr64(Register dst, Register src) {
// https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_gen.html
// 64-bit to double-precision (sf == 1 && ftype == 01 && rmode == 00 && opcode == 111)
// FMOV <Xd>, <Dn>
ASSERT(src.is_gpr(instr_set));
return InstructionARM64(Base(0b1001111001100111000000, 22), Rn(src.id()), Rd(dst.id()));
}
InstructionARM64 mov_xmm32_xmm32(Register dst, Register src) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 mov_f32_f32(Register dst, Register src) {
// https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float.html
// Single-precision (ftype == 00)
// FMOV <Sd>, <Sn>
return InstructionARM64(Base(0b0001111000100000010000, 22), Rn(src.id()), Rd(dst.id()));
}
// todo - GPR64 -> XMM64 (zext)
@@ -505,84 +533,180 @@ InstructionARM64 store128_xmm128_reg_offset(Register base, Register xmm_val, s64
}
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// RIP loads and stores
// PC relative loads and stores
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InstructionARM64 load64_rip_s32(Register dest, s64 offset) {
// Implement with LDR but that has a 1MB range limit on ARM (not 2GB like on x86)
// Hopefully this is fine, however it could potentially not be if this is loading static data, which
// may not within 1MB of the current instruction -- that all depends on the linker layout.
//
// TODO ARM - But keep it simple at first, add good assertions and we'll see what happens when we
// compile for real.
const int ARM64_LDR_MIN = -(1 << 18) * 4;
const int ARM64_LDR_MAX = ((1 << 18) - 1) * 4;
InstructionARM64 load64_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_lit_gen.html
// LDR <Xt>, <label>
return InstructionARM64(Base(0b01011000, 8), Imm19(offset / 4), Rt(dest.id()));
}
InstructionARM64 load32s_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
// https://www.scs.stanford.edu/~zyedidia/arm64/ldrsw_lit.html
// LDRSW <Xt>, <label>
return InstructionARM64(Base(0b10011000, 8), Imm19(offset / 4), Rt(dest.id()));
}
InstructionARM64 load32u_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_lit_gen.html
// LDR <Wt>, <label>
return InstructionARM64(Base(0b00011000, 8), Imm19(offset / 4), Rt(dest.id()));
}
// TODO ARM - 8/16 bit loads don't have a literal version, that means these
// MUST use a temporary register.
InstructionARM64 load16u_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 load32s_rip_s32(Register dest, s64 offset) {
InstructionARM64 load16s_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 load32u_rip_s32(Register dest, s64 offset) {
InstructionARM64 load8u_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 load16u_rip_s32(Register dest, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 load16s_rip_s32(Register dest, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 load8u_rip_s32(Register dest, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 load8s_rip_s32(Register dest, s64 offset) {
InstructionARM64 load8s_pcRel_s32(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 static_load(Register dest, s64 offset, int size, bool sign_extend) {
switch (size) {
case 1:
if (sign_extend) {
return load8s_pcRel_s32(dest, offset);
} else {
return load8u_pcRel_s32(dest, offset);
}
break;
case 2:
if (sign_extend) {
return load16s_pcRel_s32(dest, offset);
} else {
return load16u_pcRel_s32(dest, offset);
}
break;
case 4:
if (sign_extend) {
return load8s_pcRel_s32(dest, offset);
} else {
return load8u_pcRel_s32(dest, offset);
}
break;
case 8:
return load8s_pcRel_s32(dest, offset);
default:
ASSERT(false);
}
}
// TODO ARM - no direct store instructions, gotta be two and involve a register
InstructionARM64 store64_pcRel_s32(Register src, s64 offset) {
ASSERT(src.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 store64_rip_s32(Register src, s64 offset) {
InstructionARM64 store32_pcRel_s32(Register src, s64 offset) {
ASSERT(src.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 store32_rip_s32(Register src, s64 offset) {
InstructionARM64 store16_pcRel_s32(Register src, s64 offset) {
ASSERT(src.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 store16_rip_s32(Register src, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 store8_rip_s32(Register src, s64 offset) {
InstructionARM64 store8_pcRel_s32(Register src, s64 offset) {
ASSERT(src.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
}
InstructionARM64 static_store(Register value, s64 offset, int size) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
switch (size) {
case 1:
return store8_pcRel_s32(value, offset);
case 2:
return store16_pcRel_s32(value, offset);
case 4:
return store32_pcRel_s32(value, offset);
case 8:
return store64_pcRel_s32(value, offset);
default:
ASSERT(false);
}
}
InstructionARM64 static_addr(Register dst, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 static_addr(Register dest, s64 offset) {
ASSERT(dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_lit_gen.html
// LDR <Xt>, <label>
return InstructionARM64(Base(0b01011000, 8), Imm19(offset / 4), Rt(dest.id()));
}
InstructionARM64 static_load_xmm32(Register simd_dest, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
InstructionARM64 static_load_fp32(Register simd_dest, s64 offset) {
ASSERT(simd_dest.is_gpr(instr_set));
ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX,
"PC Relative offset is too large for ARM64, fix it.");
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_lit_fpsimd.html
// LDR <St>, <label>
return InstructionARM64(Base(0b00011100, 8), Imm19(offset / 4), Rt(simd_dest.id()));
}
// TODO ARM - no direct store instructions, gotta be two and involve a register
InstructionARM64 static_store_xmm32(Register xmm_value, s64 offset) {
ASSERT_MSG(false, "not yet implemented");
return InstructionARM64(0b0);
+17 -17
View File
@@ -34,27 +34,27 @@ InstructionARM64 mov_gpr64_s32(Register dst, int64_t val);
/*!
* Move 32-bits of xmm to 32 bits of gpr (no sign extension).
*/
InstructionARM64 movd_gpr32_xmm32(Register dst, Register src);
InstructionARM64 movd_gpr32_f32(Register dst, Register src);
/*!
* Move 32-bits of gpr to 32-bits of xmm (no sign extension)
*/
InstructionARM64 movd_xmm32_gpr32(Register dst, Register src);
InstructionARM64 movd_f32_gpr32(Register dst, Register src);
/*!
* Move 64-bits of xmm to 64 bits of gpr (no sign extension).
*/
InstructionARM64 movq_gpr64_xmm64(Register dst, Register src);
InstructionARM64 movq_gpr64_f64(Register dst, Register src);
/*!
* Move 64-bits of gpr to 64-bits of xmm (no sign extension)
*/
InstructionARM64 movq_xmm64_gpr64(Register dst, Register src);
InstructionARM64 movq_f64_gpr64(Register dst, Register src);
/*!
* Move 32-bits between xmm's
*/
InstructionARM64 mov_xmm32_xmm32(Register dst, Register src);
InstructionARM64 mov_f32_f32(Register dst, Register src);
// todo - GPR64 -> XMM64 (zext)
// todo - XMM -> GPR64
@@ -323,35 +323,35 @@ InstructionARM64 store128_xmm128_reg_offset(Register base, Register xmm_val, s64
// RIP loads and stores
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InstructionARM64 load64_rip_s32(Register dest, s64 offset);
InstructionARM64 load64_pcRel_s32(Register dest, s64 offset);
InstructionARM64 load32s_rip_s32(Register dest, s64 offset);
InstructionARM64 load32s_pcRel_s32(Register dest, s64 offset);
InstructionARM64 load32u_rip_s32(Register dest, s64 offset);
InstructionARM64 load32u_pcRel_s32(Register dest, s64 offset);
InstructionARM64 load16u_rip_s32(Register dest, s64 offset);
InstructionARM64 load16u_pcRel_s32(Register dest, s64 offset);
InstructionARM64 load16s_rip_s32(Register dest, s64 offset);
InstructionARM64 load16s_pcRel_s32(Register dest, s64 offset);
InstructionARM64 load8u_rip_s32(Register dest, s64 offset);
InstructionARM64 load8u_pcRel_s32(Register dest, s64 offset);
InstructionARM64 load8s_rip_s32(Register dest, s64 offset);
InstructionARM64 load8s_pcRel_s32(Register dest, s64 offset);
InstructionARM64 static_load(Register dest, s64 offset, int size, bool sign_extend);
InstructionARM64 store64_rip_s32(Register src, s64 offset);
InstructionARM64 store64_pcRel_s32(Register src, s64 offset);
InstructionARM64 store32_rip_s32(Register src, s64 offset);
InstructionARM64 store32_pcRel_s32(Register src, s64 offset);
InstructionARM64 store16_rip_s32(Register src, s64 offset);
InstructionARM64 store16_pcRel_s32(Register src, s64 offset);
InstructionARM64 store8_rip_s32(Register src, s64 offset);
InstructionARM64 store8_pcRel_s32(Register src, s64 offset);
InstructionARM64 static_store(Register value, s64 offset, int size);
InstructionARM64 static_addr(Register dst, s64 offset);
InstructionARM64 static_load_xmm32(Register simd_dest, s64 offset);
InstructionARM64 static_load_fp32(Register simd_dest, s64 offset);
InstructionARM64 static_store_xmm32(Register xmm_value, s64 offset);
+28 -13
View File
@@ -45,53 +45,68 @@ constexpr u32 Base(u32 value, u32 width) {
return value << (32 - width);
}
// TODO NOW - fix below
constexpr u64 pow2(u64 n) {
return 1ull << n;
}
constexpr Field Hw(u32 x) {
ASSERT(x >= 0 && x <= (4 - 1));
return Field{(x & 4) << 21};
}
constexpr Field Sh(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 1) - 1));
ASSERT(x >= 0 && x <= (2 - 1));
return Field{(x & 1) << 22};
}
constexpr Field Shift(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 2) - 1));
return Field{(x & 1) << 22};
ASSERT(x >= 0 && x <= (4 - 1));
return Field{(x & 2) << 22};
}
constexpr Field Rd(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 5) - 1));
ASSERT(x >= 0 && x <= (32 - 1));
return Field{(x & 31) << 0};
}
constexpr Field Rt(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 5) - 1));
ASSERT(x >= 0 && x <= (32 - 1));
return Field{(x & 31) << 0};
}
constexpr Field Rn(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 5) - 1));
ASSERT(x >= 0 && x <= (32 - 1));
return Field{(x & 31) << 5};
}
constexpr Field Rm(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 5) - 1));
ASSERT(x >= 0 && x <= (32 - 1));
return Field{(x & 31) << 16};
}
constexpr Field Imm6(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 6) - 1));
ASSERT(x >= 0 && x <= (64 - 1));
return Field{(x & 0b111111) << 10};
}
constexpr Field Imm9(s32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 9) - 1));
return Field{(static_cast<uint32_t>(x) & 0b111111111) << 12};
ASSERT(x >= 0 && x <= (512 - 1));
return Field{(static_cast<u32>(x) & 0b111111111) << 12};
}
constexpr Field Imm12(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 12) - 1));
return Field{(static_cast<uint32_t>(x) & 0b111111111111) << 10};
ASSERT(x >= 0 && x <= (4096 - 1));
return Field{(static_cast<u32>(x) & 0b111111111111) << 10};
}
constexpr Field Imm16(u32 x) {
ASSERT(x >= 0 && x <= (pow2(16) - 1));
return Field{static_cast<u32>((x & (pow2(16) - 1)) << 16)};
}
constexpr Field Imm26(u32 x) {
ASSERT(x >= 0 && x <= ((2 ^ 26) - 1));
ASSERT(x >= 0 && x <= (67108864 - 1));
return Field{(static_cast<uint32_t>(x) & 0b11111111111111111111111111) << 0};
}
+5 -2
View File
@@ -81,8 +81,11 @@ enum ARM64_REG : s8 {
X13, // temp, not-saved
X14, // temp, not-saved
X15, // temp, not-saved
X16, // temp, not-saved
X17, // temp, not-saved
// temp, not-saved - Conventionally used for linker/veneer/temporary values (we will reserve this
// one atleast)
X16,
// temp, not-saved - Conventionally used for linker/veneer/temporary values
X17,
X18, // temp, not-saved
X19, // saved TODO purpose?, R12