mirror of
https://github.com/open-goal/jak-project
synced 2026-07-09 23:01:56 -04:00
goalc/arm: PC relative loads/stores, and simple moves
This commit is contained in:
+17
-17
@@ -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
@@ -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
@@ -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
@@ -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};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user