mirror of
https://github.com/open-goal/jak-project
synced 2026-09-09 20:21:28 -04:00
goalc/arm: another batch of instructions
This commit is contained in:
@@ -712,15 +712,18 @@ void IR_IntegerMath::do_codegen_x86(emitter::ObjectGenerator* gen,
|
||||
ASSERT(!m_arg);
|
||||
break;
|
||||
case IntegerMathKind::SHLV_64:
|
||||
gen->add_instr(IGen::shl_gpr64_cl(*gen, get_reg(m_dest, allocs, irec)), irec);
|
||||
gen->add_instr(IGen::shl_gpr64_reg(*gen, get_reg(m_dest, allocs, irec)), irec);
|
||||
// TODO ARM - x86 forces you to use CL, which is dumb, but the register allocator
|
||||
// has that logic baked in somewhere
|
||||
// ARM has no such constraint, so we should be able to use any register for the shift amount
|
||||
ASSERT(get_reg(m_arg, allocs, irec) == emitter::RCX);
|
||||
break;
|
||||
case IntegerMathKind::SHRV_64:
|
||||
gen->add_instr(IGen::shr_gpr64_cl(*gen, get_reg(m_dest, allocs, irec)), irec);
|
||||
gen->add_instr(IGen::shr_gpr64_reg(*gen, get_reg(m_dest, allocs, irec)), irec);
|
||||
ASSERT(get_reg(m_arg, allocs, irec) == emitter::RCX);
|
||||
break;
|
||||
case IntegerMathKind::SARV_64:
|
||||
gen->add_instr(IGen::sar_gpr64_cl(*gen, get_reg(m_dest, allocs, irec)), irec);
|
||||
gen->add_instr(IGen::sar_gpr64_reg(*gen, get_reg(m_dest, allocs, irec)), irec);
|
||||
ASSERT(get_reg(m_arg, allocs, irec) == emitter::RCX);
|
||||
break;
|
||||
case IntegerMathKind::SHL_64:
|
||||
|
||||
@@ -693,12 +693,12 @@ Instruction not_gpr64(const ObjectGenerator& gen, Register reg) {
|
||||
IGEN_DISPATCH(not_gpr64, reg);
|
||||
}
|
||||
|
||||
Instruction shl_gpr64_cl(const ObjectGenerator& gen, Register reg) {
|
||||
IGEN_DISPATCH(shl_gpr64_cl, reg);
|
||||
Instruction shl_gpr64_reg(const ObjectGenerator& gen, Register reg) {
|
||||
IGEN_DISPATCH(shl_gpr64_reg, reg);
|
||||
}
|
||||
|
||||
Instruction shr_gpr64_cl(const ObjectGenerator& gen, Register reg) {
|
||||
IGEN_DISPATCH(shr_gpr64_cl, reg);
|
||||
Instruction shr_gpr64_reg(const ObjectGenerator& gen, Register reg) {
|
||||
IGEN_DISPATCH(shr_gpr64_reg, reg);
|
||||
}
|
||||
|
||||
Instruction sar_gpr64_cl(const ObjectGenerator& gen, Register reg) {
|
||||
|
||||
@@ -618,19 +618,21 @@ Instruction not_gpr64(const ObjectGenerator& gen, Register reg);
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr left by CL register
|
||||
* Shift 64-bit gpr left by a shift amount in a register (ie. forced to be CL register on x86)
|
||||
*/
|
||||
Instruction shl_gpr64_cl(const ObjectGenerator& gen, Register reg);
|
||||
Instruction shl_gpr64_reg(const ObjectGenerator& gen, Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (logical) by CL register
|
||||
* Shift 64-bit gpr right (logical) by a shift amount in a register (ie. forced to be CL register on
|
||||
* x86)
|
||||
*/
|
||||
Instruction shr_gpr64_cl(const ObjectGenerator& gen, Register reg);
|
||||
Instruction shr_gpr64_reg(const ObjectGenerator& gen, Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (arithmetic) by CL register
|
||||
* Shift 64-bit gpr right (arithmetic) a shift amount in a register (ie. forced to be CL register on
|
||||
* x86)
|
||||
*/
|
||||
Instruction sar_gpr64_cl(const ObjectGenerator& gen, Register reg);
|
||||
Instruction sar_gpr64_reg(const ObjectGenerator& gen, Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-ptr left (logical) by the constant shift amount "sa".
|
||||
|
||||
+78
-31
@@ -757,57 +757,93 @@ InstructionARM64 cmp_gpr64_gpr64(Register a, Register b) {
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
InstructionARM64 or_gpr64_gpr64(Register dst, Register src) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/orr_log_shift.html
|
||||
// ORR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
|
||||
ASSERT(dst.is_gpr(instr_set));
|
||||
ASSERT(src.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b10101010000, 11), Rd(dst.id()), Rn(dst.id()), Rm(src.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 and_gpr64_gpr64(Register dst, Register src) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/add_addsub_shift.html
|
||||
// ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
|
||||
ASSERT(dst.is_gpr(instr_set));
|
||||
ASSERT(src.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b10001011000, 11), Rd(dst.id()), Rn(dst.id()), Rm(src.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 xor_gpr64_gpr64(Register dst, Register src) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/eor_log_shift.html
|
||||
// EOR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
|
||||
ASSERT(dst.is_gpr(instr_set));
|
||||
ASSERT(src.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b11001010000, 11), Rd(dst.id()), Rn(dst.id()), Rm(src.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 not_gpr64(Register reg) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/mvn_orn_log_shift.html
|
||||
// MVN <Xd>, <Xm>{, <shift> #<amount>}
|
||||
// ==
|
||||
// ORN <Xd>, XZR, <Xm>{, <shift> #<amount>}
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b101010100010000000000011111, 27), Rd(reg.id()), Rm(reg.id()));
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// SHIFTS
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
InstructionARM64 shl_gpr64_cl(Register reg) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
InstructionARM64 shl_gpr64_reg(Register reg, Register shift_reg) {
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/lsl_lslv.html
|
||||
// LSL <Xd>, <Xn>, <Xm>
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
ASSERT(shift_reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b1001101011000000001000, 22), Rd(reg.id()), Rn(reg.id()),
|
||||
Rm(shift_reg.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 shr_gpr64_cl(Register reg) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
InstructionARM64 shr_gpr64_reg(Register reg, Register shift_reg) {
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/lsr_lsrv.html
|
||||
// LSR <Xd>, <Xn>, <Xm>
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
ASSERT(shift_reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b1001101011000000001001, 22), Rd(reg.id()), Rn(reg.id()),
|
||||
Rm(shift_reg.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 sar_gpr64_cl(Register reg) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
InstructionARM64 sar_gpr64_reg(Register reg, Register shift_reg) {
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/asr_asrv.html
|
||||
// ASR <Xd>, <Xn>, <Xm>
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
ASSERT(shift_reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b1001101011000000001010, 22), Rd(reg.id()), Rn(reg.id()),
|
||||
Rm(shift_reg.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 shl_gpr64_u8(Register reg, uint8_t sa) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/lsl_ubfm.html
|
||||
// LSL <Xd>, <Xn>, #<shift>
|
||||
ASSERT(sa < 63);
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b1101001101, 10), Rd(reg.id()), Rn(reg.id()), Immr((64 - sa) & 63),
|
||||
Imms(63 - sa));
|
||||
}
|
||||
|
||||
InstructionARM64 shr_gpr64_u8(Register reg, uint8_t sa) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/lsr_ubfm.html
|
||||
// LSR <Xd>, <Xn>, #<shift>
|
||||
// sf 1 0 1 0 0 1 1 0 N
|
||||
ASSERT(sa < 63);
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b1101001101000000111111, 22), Rd(reg.id()), Rn(reg.id()), Immr(sa));
|
||||
}
|
||||
|
||||
InstructionARM64 sar_gpr64_u8(Register reg, uint8_t sa) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/asr_sbfm.html
|
||||
// ASR <Xd>, <Xn>, #<shift>
|
||||
ASSERT(sa < 63);
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
return InstructionARM64(Base(0b1001001101000000111111, 22), Rd(reg.id()), Rn(reg.id()), Immr(sa));
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -946,21 +982,30 @@ InstructionARM64 null() {
|
||||
/////////////////////////////
|
||||
|
||||
InstructionARM64 nop_vf() {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// Not sure if this one was even needed for x86, but it does not really exist on ARM64
|
||||
// just use a normal nop
|
||||
return nop();
|
||||
}
|
||||
|
||||
InstructionARM64 wait_vf() {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// Another instruction that doesnt really map to arm64 because there is no annoying
|
||||
// x87 FPU behaviour
|
||||
return nop();
|
||||
}
|
||||
|
||||
InstructionARM64 mov_vf_vf(Register dst, Register src) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/mov_orr_advsimd_reg.html
|
||||
// MOV <Vd>.<T>, <Vn>.<T>
|
||||
// Q <T>
|
||||
// 0 8B
|
||||
// 1 16B
|
||||
ASSERT(dst.is_128bit_simd(instr_set));
|
||||
ASSERT(src.is_128bit_simd(instr_set));
|
||||
return InstructionARM64(Base(0b0100111010100000000111, 22), Rd(dst.id()), Rn(src.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 loadvf_gpr64_plus_gpr64(Register dst, Register addr1, Register addr2) {
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_reg_fpsimd.html
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
}
|
||||
@@ -1030,8 +1075,10 @@ InstructionARM64 splat_vf(Register dst, Register src, Register::VF_ELEMENT eleme
|
||||
}
|
||||
|
||||
InstructionARM64 xor_vf(Register dst, Register src1, Register src2) {
|
||||
ASSERT_MSG(false, "not yet implemented");
|
||||
return InstructionARM64(0b0);
|
||||
// https://www.scs.stanford.edu/~zyedidia/arm64/eor_advsimd.html
|
||||
// EOR <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
return InstructionARM64(Base(0b0110111000100000000111, 22), Rn(src1.id()), Rm(src2.id()),
|
||||
Rd(dst.id()));
|
||||
}
|
||||
|
||||
InstructionARM64 sub_vf(Register dst, Register src1, Register src2) {
|
||||
|
||||
@@ -477,19 +477,21 @@ InstructionARM64 not_gpr64(Register reg);
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr left by CL register
|
||||
* Shift 64-bit gpr left by a shift amount in a register (ie. forced to be CL register on x86)
|
||||
*/
|
||||
InstructionARM64 shl_gpr64_cl(Register reg);
|
||||
InstructionARM64 shl_gpr64_reg(Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (logical) by CL register
|
||||
* Shift 64-bit gpr right (logical) by a shift amount in a register (ie. forced to be CL register on
|
||||
* x86)
|
||||
*/
|
||||
InstructionARM64 shr_gpr64_cl(Register reg);
|
||||
InstructionARM64 shr_gpr64_reg(Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (arithmetic) by CL register
|
||||
* Shift 64-bit gpr right (arithmetic) a shift amount in a register (ie. forced to be CL register on
|
||||
* x86)
|
||||
*/
|
||||
InstructionARM64 sar_gpr64_cl(Register reg);
|
||||
InstructionARM64 sar_gpr64_reg(Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-ptr left (logical) by the constant shift amount "sa".
|
||||
@@ -800,4 +802,4 @@ InstructionARM64 vpshufhw(Register dst, Register src, u8 imm);
|
||||
InstructionARM64 vpackuswb(Register dst, Register src0, Register src1);
|
||||
} // namespace ARM64
|
||||
} // namespace IGen
|
||||
} // namespace emitter
|
||||
} // namespace emitter
|
||||
|
||||
@@ -1569,21 +1569,24 @@ InstructionX86 not_gpr64(Register reg) {
|
||||
return instr;
|
||||
}
|
||||
|
||||
InstructionX86 shl_gpr64_cl(Register reg) {
|
||||
InstructionX86 shl_gpr64_reg(Register reg, Register _) {
|
||||
// x86 is forced to use CL
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
InstructionX86 instr(0xd3);
|
||||
instr.set_modrm_and_rex(4, reg.hw_id(instr_set), 3, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
InstructionX86 shr_gpr64_cl(Register reg) {
|
||||
InstructionX86 shr_gpr64_reg(Register reg, Register _) {
|
||||
// x86 is forced to use CL
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
InstructionX86 instr(0xd3);
|
||||
instr.set_modrm_and_rex(5, reg.hw_id(instr_set), 3, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
InstructionX86 sar_gpr64_cl(Register reg) {
|
||||
InstructionX86 sar_gpr64_reg(Register reg, Register _) {
|
||||
// x86 is forced to use CL
|
||||
ASSERT(reg.is_gpr(instr_set));
|
||||
InstructionX86 instr(0xd3);
|
||||
instr.set_modrm_and_rex(7, reg.hw_id(instr_set), 3, true);
|
||||
@@ -2447,4 +2450,4 @@ InstructionX86 vpackuswb(Register dst, Register src0, Register src1) {
|
||||
}
|
||||
} // namespace X86
|
||||
} // namespace IGen
|
||||
} // namespace emitter
|
||||
} // namespace emitter
|
||||
|
||||
@@ -477,19 +477,21 @@ InstructionX86 not_gpr64(Register reg);
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr left by CL register
|
||||
* Shift 64-bit gpr left by a shift amount in a register (ie. forced to be CL register on x86)
|
||||
*/
|
||||
InstructionX86 shl_gpr64_cl(Register reg);
|
||||
InstructionX86 shl_gpr64_reg(Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (logical) by CL register
|
||||
* Shift 64-bit gpr right (logical) by a shift amount in a register (ie. forced to be CL register on
|
||||
* x86)
|
||||
*/
|
||||
InstructionX86 shr_gpr64_cl(Register reg);
|
||||
InstructionX86 shr_gpr64_reg(Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (arithmetic) by CL register
|
||||
* Shift 64-bit gpr right (arithmetic) a shift amount in a register (ie. forced to be CL register on
|
||||
* x86)
|
||||
*/
|
||||
InstructionX86 sar_gpr64_cl(Register reg);
|
||||
InstructionX86 sar_gpr64_reg(Register reg, Register shift_reg);
|
||||
|
||||
/*!
|
||||
* Shift 64-ptr left (logical) by the constant shift amount "sa".
|
||||
@@ -800,4 +802,4 @@ InstructionX86 vpshufhw(Register dst, Register src, u8 imm);
|
||||
InstructionX86 vpackuswb(Register dst, Register src0, Register src1);
|
||||
} // namespace X86
|
||||
} // namespace IGen
|
||||
} // namespace emitter
|
||||
} // namespace emitter
|
||||
|
||||
+57
-15
@@ -61,45 +61,87 @@ constexpr Field Rm(u32 x) {
|
||||
}
|
||||
|
||||
constexpr Field Imm6(u32 x) {
|
||||
ASSERT(x >= 0 && x <= ((2 ^ 6) - 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};
|
||||
}
|
||||
|
||||
constexpr Field Imm12(u32 x) {
|
||||
ASSERT(x >= 0 && x <= 4095);
|
||||
ASSERT(x >= 0 && x <= ((2 ^ 12) - 1));
|
||||
return Field{(static_cast<uint32_t>(x) & 0b111111111111) << 10};
|
||||
}
|
||||
|
||||
constexpr Field Imms(u32 x) {
|
||||
ASSERT(x >= 0 && x <= ((2 ^ 6) - 1));
|
||||
return Field{(static_cast<uint32_t>(x) & 0b111111) << 10};
|
||||
}
|
||||
|
||||
constexpr Field Immr(u32 x) {
|
||||
ASSERT(x >= 0 && x <= ((2 ^ 6) - 1));
|
||||
return Field{(static_cast<uint32_t>(x) & 0b111111) << 16};
|
||||
}
|
||||
} // namespace ARM64
|
||||
|
||||
struct InstructionARM64 : InstructionImpl<InstructionARM64> {
|
||||
// The ARM instruction stream is a sequence of word-aligned words. Each ARM instruction is a
|
||||
// single 32-bit word in that stream.
|
||||
// Info:
|
||||
// - https://yurichev.com/mirrors/ARMv8-A_Architecture_Reference_Manual_(Issue_A.a).pdf
|
||||
// - https://www.scs.stanford.edu/~zyedidia/arm64/
|
||||
// - https://armconverter.com/?lock=arm64&code=STR+X0,+[SP,+%23-8]!
|
||||
u32 encoding;
|
||||
// The ARM instruction stream is a sequence of word-aligned words.
|
||||
// Each ARM instruction is a single 32-bit word in that stream.
|
||||
//
|
||||
// Some x86 instructions are not possible to represent in ARM in a single instruction
|
||||
// however, in order to not have to overhaul things at the IR level,
|
||||
// it feels preferably to instead allow an instruction to emit multiple instructions if needed
|
||||
//
|
||||
// To do so, the instruction can optionally include multiple encodings
|
||||
// all of which are emitted at once.
|
||||
static constexpr int kMaxInstrs = 4;
|
||||
|
||||
u32 encodings[kMaxInstrs]{};
|
||||
uint8_t count = 0;
|
||||
|
||||
InstructionARM64() = delete;
|
||||
|
||||
// --- single instruction ---
|
||||
template <typename... Fs>
|
||||
constexpr InstructionARM64(uint32_t base, Fs... fields) : encoding((base | ... | fields.bits)) {
|
||||
static_assert((std::is_same_v<Fs, emitter::ARM64::Field> && ...),
|
||||
"All operands must be Field types");
|
||||
constexpr InstructionARM64(uint32_t base, Fs... fields) {
|
||||
static_assert((std::is_same_v<Fs, emitter::ARM64::Field> && ...));
|
||||
encodings[0] = (base | ... | fields.bits);
|
||||
count = 1;
|
||||
}
|
||||
|
||||
// --- multi instruction (variadic) ---
|
||||
template <typename... Instrs>
|
||||
constexpr InstructionARM64(const Instrs&... instrs)
|
||||
requires(std::is_same_v<Instrs, InstructionARM64> && ...)
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
auto append = [&](const InstructionARM64& i) {
|
||||
for (uint8_t j = 0; j < i.count; ++j) {
|
||||
encodings[idx++] = i.encodings[j];
|
||||
}
|
||||
};
|
||||
(append(instrs), ...);
|
||||
count = idx;
|
||||
}
|
||||
|
||||
uint8_t emit(uint8_t* buffer) const {
|
||||
if (encoding == 0) {
|
||||
if (count == 1 && encodings[0] == 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer, &encoding, 4);
|
||||
return 4;
|
||||
memcpy(buffer, encodings, count * 4);
|
||||
return count * 4;
|
||||
}
|
||||
|
||||
uint8_t length() const { return 4; }
|
||||
uint8_t length() const {
|
||||
if (count == 1 && encodings[0] == 0) {
|
||||
return 0;
|
||||
}
|
||||
return count * 4;
|
||||
}
|
||||
|
||||
// TODO ARM - all placeholders, no idea if this is even relevant, if not, get rid of it all
|
||||
int get_imm_size() const { return 0; }
|
||||
|
||||
int offset_of_imm() const { return 0; }
|
||||
|
||||
+41
-21
@@ -85,10 +85,10 @@ enum ARM64_REG : s8 {
|
||||
X17, // temp, not-saved
|
||||
X18, // temp, not-saved
|
||||
|
||||
x19, // saved TODO purpose?, R12
|
||||
x20, // pp, R13
|
||||
x21, // st, R14
|
||||
x22, // offset, TODO purpose?, R15
|
||||
X19, // saved TODO purpose?, R12
|
||||
X20, // pp, R13
|
||||
X21, // st, R14
|
||||
X22, // offset, TODO purpose?, R15
|
||||
X23, // unused, callee saved
|
||||
X24, // unused, callee saved
|
||||
X25, // unused, callee saved
|
||||
@@ -103,22 +103,39 @@ enum ARM64_REG : s8 {
|
||||
// quadword registers, equivalent to XMMs
|
||||
// the convention in arm64 is the callee preserves all Q values
|
||||
// at the same time though, the caller should not depend on this convention!
|
||||
Q0 = 0,
|
||||
Q1,
|
||||
Q2,
|
||||
Q3,
|
||||
Q4,
|
||||
Q5,
|
||||
Q6,
|
||||
Q7,
|
||||
Q8,
|
||||
Q9,
|
||||
Q10,
|
||||
Q11,
|
||||
Q12,
|
||||
Q13,
|
||||
Q14,
|
||||
Q15
|
||||
V0 = 0,
|
||||
V1,
|
||||
V2,
|
||||
V3,
|
||||
V4,
|
||||
V5,
|
||||
V6,
|
||||
V7,
|
||||
V8,
|
||||
V9,
|
||||
V10,
|
||||
V11,
|
||||
V12,
|
||||
V13,
|
||||
V14,
|
||||
V15,
|
||||
// TODO ARM - we'll want to check at runtime if the platform has 16 V registers, or 32
|
||||
V16,
|
||||
V17,
|
||||
V18,
|
||||
V19,
|
||||
V20,
|
||||
V21,
|
||||
V22,
|
||||
V23,
|
||||
V24,
|
||||
V25,
|
||||
V26,
|
||||
V27,
|
||||
V28,
|
||||
V29,
|
||||
V30,
|
||||
V31,
|
||||
};
|
||||
|
||||
class Register {
|
||||
@@ -128,11 +145,14 @@ class Register {
|
||||
// intentionally not explicit so we can use X86_REGs in place of Registers
|
||||
Register(int id) : m_id(id) {}
|
||||
|
||||
// TODO ARM64 - this assertion isn't as useful for ARM
|
||||
// since Q/V registers are not unique in terms of their id
|
||||
// instead it is the instruction itself that deduces what set of registers to use
|
||||
bool is_128bit_simd(emitter::InstructionSet instr_set) const {
|
||||
if (instr_set == emitter::InstructionSet::X86) {
|
||||
return m_id >= XMM0 && m_id <= XMM15;
|
||||
} else if (instr_set == emitter::InstructionSet::ARM64) {
|
||||
return m_id >= Q0 && m_id <= Q15;
|
||||
return m_id >= V0 && m_id <= V31;
|
||||
} else {
|
||||
ASSERT_MSG(false, "is_128bit_simd: instruction set not supported");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user