mirror of
https://github.com/open-goal/jak-project
synced 2026-07-07 06:05:15 -04:00
all basic integer and floating point instructions are implemented
This commit is contained in:
+273
-13
@@ -1451,35 +1451,295 @@ class IGen {
|
||||
// SHIFTS
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
// sllv reg, imm
|
||||
// srlv reg, imm
|
||||
// srav reg, imm
|
||||
/*!
|
||||
* Shift 64-bit gpr left by CL register
|
||||
*/
|
||||
static Instruction shl_gpr64_cl(uint8_t reg) {
|
||||
Instruction instr(0xd3);
|
||||
instr.set_modrm_and_rex(4, reg, 3, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (logical) by CL register
|
||||
*/
|
||||
static Instruction shr_gpr64_cl(uint8_t reg) {
|
||||
Instruction instr(0xd3);
|
||||
instr.set_modrm_and_rex(5, reg, 3, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Shift 64-bit gpr right (arithmetic) by CL register
|
||||
*/
|
||||
static Instruction sar_gpr64_cl(uint8_t reg) {
|
||||
Instruction instr(0xd3);
|
||||
instr.set_modrm_and_rex(7, reg, 3, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Shift 64-ptr left (logical) by the constant shift amount "sa".
|
||||
*/
|
||||
static Instruction shl_gpr64_u8(uint8_t reg, uint8_t sa) {
|
||||
Instruction instr(0xc1);
|
||||
instr.set_modrm_and_rex(4, reg, 3, true);
|
||||
instr.set(Imm(1, sa));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Shift 64-ptr right (logical) by the constant shift amount "sa".
|
||||
*/
|
||||
static Instruction shr_gpr64_u8(uint8_t reg, uint8_t sa) {
|
||||
Instruction instr(0xc1);
|
||||
instr.set_modrm_and_rex(5, reg, 3, true);
|
||||
instr.set(Imm(1, sa));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Shift 64-ptr right (arithmetic) by the constant shift amount "sa".
|
||||
*/
|
||||
static Instruction sar_gpr64_u8(uint8_t reg, uint8_t sa) {
|
||||
Instruction instr(0xc1);
|
||||
instr.set_modrm_and_rex(7, reg, 3, true);
|
||||
instr.set(Imm(1, sa));
|
||||
return instr;
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// CONTROL FLOW
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
// call, jump reg
|
||||
/*!
|
||||
* Jump, 32-bit constant offset. The offset is by default 0 and must be patched later.
|
||||
*/
|
||||
static Instruction jmp_32() {
|
||||
Instruction instr(0xe9);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
// jump imm8, imm32 ?? (is there an imm16?)
|
||||
/*!
|
||||
* Jump if equal.
|
||||
*/
|
||||
static Instruction je_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x84);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
// je, jne, jle, jge, jl, jg, jbe, jae, jb, ja
|
||||
/*!
|
||||
* Jump not equal.
|
||||
*/
|
||||
static Instruction jne_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x85);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump less than or equal.
|
||||
*/
|
||||
static Instruction jle_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x8e);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump greater than or equal.
|
||||
*/
|
||||
static Instruction jge_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x8d);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump less than
|
||||
*/
|
||||
static Instruction jl_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x8c);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump greater than
|
||||
*/
|
||||
static Instruction jg_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x8f);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump below or equal
|
||||
*/
|
||||
static Instruction jbe_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x86);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump above or equal
|
||||
*/
|
||||
static Instruction jae_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x83);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump below
|
||||
*/
|
||||
static Instruction jb_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x82);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Jump above
|
||||
*/
|
||||
static Instruction ja_32() {
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x87);
|
||||
instr.set(Imm(4, 0));
|
||||
return instr;
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// FLOAT MATH
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
// cmp_flt
|
||||
// mulss
|
||||
// divss
|
||||
// subss
|
||||
// addss
|
||||
// float to int
|
||||
// int to float
|
||||
/*!
|
||||
* Compare two floats and set flag register for jump (ucomiss)
|
||||
*/
|
||||
static Instruction cmp_flt_flt(Register a, Register b) {
|
||||
assert(a.is_xmm());
|
||||
assert(b.is_xmm());
|
||||
Instruction instr(0x0f);
|
||||
instr.set_op2(0x2e);
|
||||
instr.set_modrm_and_rex(a.hw_id(), b.hw_id(), 3, false);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Multiply two floats in xmm's
|
||||
*/
|
||||
static Instruction mulss_xmm_xmm(Register dst, Register src) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src.is_xmm());
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x59);
|
||||
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Divide two floats in xmm's
|
||||
*/
|
||||
static Instruction divss_xmm_xmm(Register dst, Register src) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src.is_xmm());
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x5e);
|
||||
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Subtract two floats in xmm's
|
||||
*/
|
||||
static Instruction subss_xmm_xmm(Register dst, Register src) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src.is_xmm());
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x5c);
|
||||
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add two floats in xmm's
|
||||
*/
|
||||
static Instruction addss_xmm_xmm(Register dst, Register src) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src.is_xmm());
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x58);
|
||||
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert GPR int32 to XMM float (single precision)
|
||||
*/
|
||||
static Instruction int32_to_float(Register dst, Register src) {
|
||||
assert(dst.is_xmm());
|
||||
assert(src.is_gpr());
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x2a);
|
||||
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert XMM float to GPR int32(single precision) (truncate)
|
||||
*/
|
||||
static Instruction float_to_int32(Register dst, Register src) {
|
||||
assert(dst.is_gpr());
|
||||
assert(src.is_xmm());
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x2c);
|
||||
instr.set_modrm_and_rex(dst.hw_id(), src.hw_id(), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
// eventually...
|
||||
// sqrt
|
||||
// rsqrt
|
||||
// abs
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// UTILITIES
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
* A "null" instruction. This instruction does not generate any bytes
|
||||
* but can be referred to by a label. Useful to insert in place of a real instruction
|
||||
* if the real instruction has been optimized out.
|
||||
*/
|
||||
static Instruction null() {
|
||||
Instruction i(0);
|
||||
i.is_null = true;
|
||||
return i;
|
||||
}
|
||||
};
|
||||
} // namespace emitter
|
||||
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
#ifndef JAK1_IGEN_H
|
||||
#define JAK1_IGEN_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include "Instruction.h"
|
||||
#include "registers.h"
|
||||
|
||||
namespace goal {
|
||||
class IGen {
|
||||
public:
|
||||
//
|
||||
// /*!
|
||||
// * Shift 64-bit gpr left by CL register
|
||||
// */
|
||||
// static Instruction shl_gpr64_cl(uint8_t reg) {
|
||||
// Instruction instr(0xd3);
|
||||
// instr.set_modrm_and_rex(4, reg, 3, true);
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Shift 64-bit gpr right (logical) by CL register
|
||||
// */
|
||||
// static Instruction shr_gpr64_cl(uint8_t reg) {
|
||||
// Instruction instr(0xd3);
|
||||
// instr.set_modrm_and_rex(5, reg, 3, true);
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Shift 64-bit gpr right (arithmetic) by CL register
|
||||
// */
|
||||
// static Instruction sar_gpr64_cl(uint8_t reg) {
|
||||
// Instruction instr(0xd3);
|
||||
// instr.set_modrm_and_rex(7, reg, 3, true);
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Shift 64-ptr left (logical) by the constant shift amount "sa".
|
||||
// */
|
||||
// static Instruction shl_gpr64_u8(uint8_t reg, uint8_t sa) {
|
||||
// Instruction instr(0xc1);
|
||||
// instr.set_modrm_and_rex(4, reg, 3, true);
|
||||
// instr.set(Imm(1, sa));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Shift 64-ptr right (logical) by the constant shift amount "sa".
|
||||
// */
|
||||
// static Instruction shr_gpr64_u8(uint8_t reg, uint8_t sa) {
|
||||
// Instruction instr(0xc1);
|
||||
// instr.set_modrm_and_rex(5, reg, 3, true);
|
||||
// instr.set(Imm(1, sa));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Shift 64-ptr right (arithmetic) by the constant shift amount "sa".
|
||||
// */
|
||||
// static Instruction sar_gpr64_u8(uint8_t reg, uint8_t sa) {
|
||||
// Instruction instr(0xc1);
|
||||
// instr.set_modrm_and_rex(7, reg, 3, true);
|
||||
// instr.set(Imm(1, sa));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// // CONTROL FLOW
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
//
|
||||
// /*!
|
||||
// * Jump, 32-bit constant offset. The offset is by default 0 and must be patched later.
|
||||
// */
|
||||
// static Instruction jmp_32() {
|
||||
// Instruction instr(0xe9);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump if equal.
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction je_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x84);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump not equal.
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jne_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x85);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump less than or equal.
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jle_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x8e);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump greater than or equal.
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jge_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x8d);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump less than
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jl_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x8c);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump greater than
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jg_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x8f);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump below or equal
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jbe_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x86);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump above or equal
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jae_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x83);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump below
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction jb_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x82);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Jump above
|
||||
// * TODO - can we get away with 16 bits?
|
||||
// */
|
||||
// static Instruction ja_32() {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x87);
|
||||
// instr.set(Imm(4, 0));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// // FLOAT MATH
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
//
|
||||
// /*!
|
||||
// * Compare two floats and set flag register for jump
|
||||
// */
|
||||
// static Instruction cmp_flt_flt(uint8_t a, uint8_t b) {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0x2e);
|
||||
// instr.set_modrm_and_rex(a, b, 3, false);
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Multiply two floats in xmm's
|
||||
// */
|
||||
// static Instruction mulss_xmm_xmm(uint8_t dst, uint8_t src) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x59);
|
||||
// instr.set_modrm_and_rex(dst, src, 3, false);
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Divide two floats in xmm's
|
||||
// */
|
||||
// static Instruction divss_xmm_xmm(uint8_t dst, uint8_t src) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x5e);
|
||||
// instr.set_modrm_and_rex(dst, src, 3, false);
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Subtract two floats in xmm's
|
||||
// */
|
||||
// static Instruction subss_xmm_xmm(uint8_t dst, uint8_t src) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x5c);
|
||||
// instr.set_modrm_and_rex(dst, src, 3, false);
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Add two floats in xmm's
|
||||
// */
|
||||
// static Instruction addss_xmm_xmm(uint8_t dst, uint8_t src) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x58);
|
||||
// instr.set_modrm_and_rex(dst, src, 3, false);
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Convert GPR int32 to XMM float (single precision)
|
||||
// */
|
||||
// static Instruction int32_to_float(uint8_t dst, uint8_t src) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x2a);
|
||||
// instr.set_modrm_and_rex(dst, src, 3, false);
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Convert XMM float to GPR int32(single precision) (truncate)
|
||||
// */
|
||||
// static Instruction float_to_int64(uint8_t dst, uint8_t src) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x2c);
|
||||
// instr.set_modrm_and_rex(dst, src, 3, true);
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// // UTILITIES
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
//
|
||||
// /*!
|
||||
// * A "null" instruction. This instruction does not generate any bytes
|
||||
// * but can be referred to by a label. Useful to insert in place of a real instruction
|
||||
// * if the real instruction has been optimized out.
|
||||
// */
|
||||
// static Instruction null() {
|
||||
// Instruction i(0);
|
||||
// i.is_null = true;
|
||||
// return i;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * A "function start" instruction. This emits no opcodes, but is used
|
||||
// * to determine where to insert the function type tag and how to align a function.
|
||||
// */
|
||||
// static Instruction function_start() {
|
||||
// Instruction i(0);
|
||||
// i.is_null = true;
|
||||
// i.is_function_start = true;
|
||||
// return i;
|
||||
// }
|
||||
};
|
||||
} // namespace goal
|
||||
|
||||
#endif // JAK1_IGEN_H
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "registers.h"
|
||||
|
||||
namespace goal {
|
||||
bool is_gpr(u8 reg) {
|
||||
return reg <= R15;
|
||||
}
|
||||
|
||||
u8 get_nth_xmm(u8 id) {
|
||||
return id + XMM0;
|
||||
}
|
||||
|
||||
bool is_xmm(u8 reg) {
|
||||
return reg >= XMM0 && reg <= XMM15;
|
||||
}
|
||||
|
||||
u8 xmm_to_id(u8 reg) {
|
||||
return reg - 16;
|
||||
}
|
||||
|
||||
} // namespace goal
|
||||
@@ -1,111 +0,0 @@
|
||||
/*!
|
||||
* @file registers.h
|
||||
* Definitions and conventions for x86-64 registers.
|
||||
*/
|
||||
|
||||
#ifndef JAK1_REGISTERS_H
|
||||
#define JAK1_REGISTERS_H
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace goal {
|
||||
enum X86R : u8 {
|
||||
RAX, // return, temp
|
||||
RCX, // arg 3
|
||||
RDX, // arg 2
|
||||
RBX, // X saved
|
||||
|
||||
RSP, // stack pointer
|
||||
RBP, // X base pointer (like fp)
|
||||
RSI, // arg 1
|
||||
RDI, // arg 0
|
||||
|
||||
R8, // arg 4
|
||||
R9, // arg 5, saved
|
||||
R10, // arg 6, saved (arg in GOAL only)
|
||||
R11, // arg 7, saved (arg in GOAL only)
|
||||
R12, // X saved - pp register (like s6)
|
||||
R13, // X saved - function call register (like t9)
|
||||
R14, // X saved - offset (added in GOAL x86)
|
||||
R15, // X saved - st (like s7)
|
||||
XMM0,
|
||||
XMM1,
|
||||
XMM2,
|
||||
XMM3,
|
||||
XMM4,
|
||||
XMM5,
|
||||
XMM6,
|
||||
XMM7,
|
||||
XMM8,
|
||||
XMM9,
|
||||
XMM10,
|
||||
XMM11,
|
||||
XMM12,
|
||||
XMM13,
|
||||
XMM14,
|
||||
XMM15
|
||||
};
|
||||
|
||||
// the argument registers of GOAL.
|
||||
// We must have 8 to be compatible with GOAL's 8-argument function calls.
|
||||
constexpr int ARG_REG_COUNT = 8;
|
||||
|
||||
// the first 6 are shared with Linux, and the last two are unique to GOAL.
|
||||
constexpr X86R ARG_REGS[ARG_REG_COUNT] = {
|
||||
X86R::RDI, X86R::RSI, X86R::RDX, X86R::RCX, X86R::R8, X86R::R9, X86R::R10, X86R::R11,
|
||||
};
|
||||
|
||||
// The saved registers of GOAL. Note that RSP, RBP, R12, R13, R14, R15 shouldn't be changed by the
|
||||
// caller, but these are special registers and won't be allocated to hold variables.
|
||||
constexpr int SAVED_REG_COUNT = 4;
|
||||
constexpr X86R SAVED_REGS[SAVED_REG_COUNT] = {X86R::RBX, X86R::R9, X86R::R10, X86R::R11};
|
||||
|
||||
// special registers
|
||||
constexpr X86R PP_REG = X86R::R12;
|
||||
constexpr X86R FUNC_REG = X86R::R13;
|
||||
constexpr X86R OFF_REG = X86R::R14;
|
||||
constexpr X86R ST_REG = X86R::R15;
|
||||
constexpr X86R FP_REG = X86R::RBP;
|
||||
constexpr X86R RET_REG = X86R::RAX;
|
||||
|
||||
// size in bytes of a pointer
|
||||
constexpr int PTR_SIZE = 4;
|
||||
|
||||
// size in bytes of a general purpose register
|
||||
constexpr int GPR_SIZE = 8;
|
||||
|
||||
constexpr const char* x86_gpr_names[] = {
|
||||
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10",
|
||||
"r11", "r12", "r13", "r14", "r15", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
|
||||
"xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"};
|
||||
|
||||
/*
|
||||
Name Arg ID Clobber? Special
|
||||
RAX - y return
|
||||
RCX 3 y arg
|
||||
RDX 2 y arg
|
||||
RBX - n
|
||||
|
||||
RSP - n stack pointer
|
||||
RBP - n base pointer
|
||||
RSI 1 y arg
|
||||
RDI 0 y arg
|
||||
|
||||
R8 4 y arg
|
||||
R9 5 n arg
|
||||
R10 6 n arg
|
||||
R11 7 n arg
|
||||
R12 - n pp
|
||||
R13 - n func
|
||||
R14 - n
|
||||
R15
|
||||
*/
|
||||
|
||||
bool is_gpr(u8 reg);
|
||||
u8 get_nth_xmm(u8 id);
|
||||
bool is_xmm(u8 reg);
|
||||
u8 xmm_to_id(u8 reg);
|
||||
|
||||
} // namespace goal
|
||||
|
||||
#endif // JAK1_REGISTERS_H
|
||||
@@ -390,4 +390,239 @@ TEST(EmitterIntegerMath, not_gpr64) {
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, shl_gpr64_cl) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
std::vector<s64> vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN,
|
||||
INT64_MAX, 117, 32, -348473, 83747382};
|
||||
std::vector<u8> sas = {0, 1, 23, 53, 64};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP || i == RCX) {
|
||||
continue;
|
||||
}
|
||||
for (auto v : vals) {
|
||||
for (auto sa : sas) {
|
||||
auto expected = v << sa;
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(i, v));
|
||||
tester.emit(IGen::mov_gpr64_u64(RCX, sa));
|
||||
tester.emit(IGen::shl_gpr64_cl(i));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s64>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, shr_gpr64_cl) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
std::vector<u64> vals = {0, 1, u64(-2), u64(INT32_MIN), INT32_MAX, u64(INT64_MIN),
|
||||
INT64_MAX, 117, 32, u64(-348473), 83747382};
|
||||
std::vector<u8> sas = {0, 1, 23, 53, 64};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP || i == RCX) {
|
||||
continue;
|
||||
}
|
||||
for (auto v : vals) {
|
||||
for (auto sa : sas) {
|
||||
auto expected = v >> sa;
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(i, v));
|
||||
tester.emit(IGen::mov_gpr64_u64(RCX, sa));
|
||||
tester.emit(IGen::shr_gpr64_cl(i));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s64>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, sar_gpr64_cl) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
std::vector<s64> vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN,
|
||||
INT64_MAX, 117, 32, -348473, 83747382};
|
||||
std::vector<u8> sas = {0, 1, 23, 53, 64};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP || i == RCX) {
|
||||
continue;
|
||||
}
|
||||
for (auto v : vals) {
|
||||
for (auto sa : sas) {
|
||||
auto expected = v >> sa;
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(i, v));
|
||||
tester.emit(IGen::mov_gpr64_u64(RCX, sa));
|
||||
tester.emit(IGen::sar_gpr64_cl(i));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s64>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, shl_gpr64_u8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
std::vector<s64> vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN,
|
||||
INT64_MAX, 117, 32, -348473, 83747382};
|
||||
std::vector<u8> sas = {0, 1, 23, 53, 64};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (auto v : vals) {
|
||||
for (auto sa : sas) {
|
||||
auto expected = v << sa;
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(i, v));
|
||||
tester.emit(IGen::shl_gpr64_u8(i, sa));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s64>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, shr_gpr64_u8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
std::vector<u64> vals = {0, 1, u64(-2), u64(INT32_MIN), INT32_MAX, u64(INT64_MIN),
|
||||
INT64_MAX, 117, 32, u64(-348473), 83747382};
|
||||
std::vector<u8> sas = {0, 1, 23, 53, 64};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (auto v : vals) {
|
||||
for (auto sa : sas) {
|
||||
auto expected = v >> sa;
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(i, v));
|
||||
tester.emit(IGen::shr_gpr64_u8(i, sa));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s64>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, sar_gpr64_u8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
std::vector<s64> vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN,
|
||||
INT64_MAX, 117, 32, -348473, 83747382};
|
||||
std::vector<u8> sas = {0, 1, 23, 53, 64};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (auto v : vals) {
|
||||
for (auto sa : sas) {
|
||||
auto expected = v >> sa;
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(i, v));
|
||||
tester.emit(IGen::sar_gpr64_u8(i, sa));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s64>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, jumps) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
|
||||
std::vector<int> reads;
|
||||
|
||||
auto x = IGen::jmp_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::je_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jne_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jle_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jge_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jl_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jg_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jbe_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jae_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::jb_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
x = IGen::ja_32();
|
||||
reads.push_back(tester.size() + x.offset_of_imm());
|
||||
tester.emit(x);
|
||||
|
||||
for (auto off : reads) {
|
||||
EXPECT_EQ(0, tester.read<s32>(off));
|
||||
}
|
||||
|
||||
EXPECT_EQ(tester.dump_to_hex_string(true),
|
||||
"E9000000000F84000000000F85000000000F8E000000000F8D000000000F8C000000000F8F000000000F86"
|
||||
"000000000F83000000000F82000000000F8700000000");
|
||||
}
|
||||
|
||||
TEST(EmitterIntegerMath, null) {
|
||||
auto instr = IGen::null();
|
||||
EXPECT_EQ(0, instr.emit(nullptr));
|
||||
}
|
||||
@@ -440,4 +440,220 @@ TEST(EmitterXmm32, static_store_xmm32) {
|
||||
tester.execute(as_u32(-44.567f), 0, 0, 0);
|
||||
EXPECT_EQ(-44.567f, tester.read<float>(loc_of_float));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, ucomiss) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::cmp_flt_flt(XMM13, XMM14));
|
||||
EXPECT_EQ("45 0f 2e ee", tester.dump_to_hex_string());
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, mul) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
std::vector<float> vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f};
|
||||
|
||||
for (auto f : vals) {
|
||||
for (auto g : vals) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
auto expected = f * g;
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
u64 val = 0;
|
||||
memcpy(&val, &f, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX));
|
||||
memcpy(&val, &g, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX));
|
||||
tester.emit(IGen::mulss_xmm_xmm(XMM0 + j, XMM0 + i));
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<float>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, div) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
std::vector<float> vals = {1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f};
|
||||
|
||||
for (auto f : vals) {
|
||||
for (auto g : vals) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
auto expected = g / f;
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
u64 val = 0;
|
||||
memcpy(&val, &f, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX));
|
||||
memcpy(&val, &g, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX));
|
||||
tester.emit(IGen::divss_xmm_xmm(XMM0 + j, XMM0 + i));
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<float>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, add) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
std::vector<float> vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f};
|
||||
for (auto f : vals) {
|
||||
for (auto g : vals) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
auto expected = g + f;
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
u64 val = 0;
|
||||
memcpy(&val, &f, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX));
|
||||
memcpy(&val, &g, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX));
|
||||
tester.emit(IGen::addss_xmm_xmm(XMM0 + j, XMM0 + i));
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<float>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, sub) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
std::vector<float> vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f};
|
||||
|
||||
for (auto f : vals) {
|
||||
for (auto g : vals) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
auto expected = g - f;
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
u64 val = 0;
|
||||
memcpy(&val, &f, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX));
|
||||
memcpy(&val, &g, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX));
|
||||
tester.emit(IGen::subss_xmm_xmm(XMM0 + j, XMM0 + i));
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<float>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, float_to_int) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
std::vector<float> vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f,
|
||||
7.545f, 0.1f, 0.9f, -0.1f, -0.9f};
|
||||
|
||||
for (auto g : vals) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP) {
|
||||
continue;
|
||||
}
|
||||
s32 expected = g;
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
u64 val = 0;
|
||||
memcpy(&val, &g, sizeof(float));
|
||||
tester.emit(IGen::mov_gpr64_u64(RAX, val));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX));
|
||||
tester.emit(IGen::float_to_int32(j, XMM0 + i));
|
||||
tester.emit(IGen::mov_gpr64_gpr64(RAX, j));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<s32>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, int_to_float) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
std::vector<s64> vals = {0, 1, -1, INT32_MAX, -3457343, 7, INT32_MIN};
|
||||
|
||||
for (auto g : vals) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP) {
|
||||
continue;
|
||||
}
|
||||
float expected = g;
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
tester.emit(IGen::mov_gpr64_u64(j, g));
|
||||
tester.emit(IGen::int32_to_float(XMM0 + i, j));
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + i));
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
auto result = tester.execute_ret<float>(0, 0, 0, 0);
|
||||
EXPECT_EQ(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user