mirror of
https://github.com/open-goal/jak-project
synced 2026-07-27 23:00:42 -04:00
more loads and stores
This commit is contained in:
@@ -21,6 +21,15 @@ class CodeTester {
|
||||
void emit(const Instruction& instr);
|
||||
u64 execute();
|
||||
u64 execute(u64 in0, u64 in1, u64 in2, u64 in3);
|
||||
|
||||
template <typename T>
|
||||
T execute_ret(u64 in0, u64 in1, u64 in2, u64 in3) {
|
||||
u64 result_u64 = ((u64(*)(u64, u64, u64, u64))code_buffer)(in0, in1, in2, in3);
|
||||
T result_T;
|
||||
memcpy(&result_T, &result_u64, sizeof(T));
|
||||
return result_T;
|
||||
}
|
||||
|
||||
void clear();
|
||||
~CodeTester();
|
||||
|
||||
|
||||
+239
-1
@@ -120,7 +120,7 @@ class IGen {
|
||||
// todo - XMM128 - XMM128
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// GOAL Loads
|
||||
// GOAL Loads and Stores
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
@@ -469,6 +469,20 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store32_gpr64_gpr64_plus_gpr64(Register addr1,
|
||||
Register addr2,
|
||||
Register value) {
|
||||
assert(value.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_addr(value.hw_id(), addr1.hw_id(), addr2.hw_id());
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32s_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
@@ -486,6 +500,23 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store32_gpr64_gpr64_plus_gpr64_plus_s8(Register addr1,
|
||||
Register addr2,
|
||||
Register value,
|
||||
s64 offset) {
|
||||
assert(value.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(value.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, false);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32s_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
@@ -503,6 +534,23 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store32_gpr64_gpr64_plus_gpr64_plus_s32(Register addr1,
|
||||
Register addr2,
|
||||
Register value,
|
||||
s64 offset) {
|
||||
assert(value.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(value.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, false);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* movzxd dst, DWORD PTR [addr1 + addr2]
|
||||
* addr1 and addr2 have to be different registers.
|
||||
@@ -571,6 +619,21 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store64_gpr64_gpr64_plus_gpr64(Register addr1,
|
||||
Register addr2,
|
||||
Register value) {
|
||||
assert(value.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_addr(value.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load64_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
@@ -588,6 +651,23 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store64_gpr64_gpr64_plus_gpr64_plus_s8(Register addr1,
|
||||
Register addr2,
|
||||
Register value,
|
||||
s64 offset) {
|
||||
assert(value.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(value.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load64_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
@@ -605,6 +685,23 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store64_gpr64_gpr64_plus_gpr64_plus_s32(Register addr1,
|
||||
Register addr2,
|
||||
Register value,
|
||||
s64 offset) {
|
||||
assert(value.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(value.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store_goal_gpr(Register addr,
|
||||
Register value,
|
||||
Register off,
|
||||
@@ -631,6 +728,26 @@ class IGen {
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
case 4:
|
||||
if (offset == 0) {
|
||||
return store32_gpr64_gpr64_plus_gpr64(addr, off, value);
|
||||
} else if (offset >= INT8_MIN && offset <= INT8_MAX) {
|
||||
return store32_gpr64_gpr64_plus_gpr64_plus_s8(addr, off, value, offset);
|
||||
} else if (offset >= INT32_MIN && offset <= INT32_MAX) {
|
||||
return store32_gpr64_gpr64_plus_gpr64_plus_s32(addr, off, value, offset);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
case 8:
|
||||
if (offset == 0) {
|
||||
return store64_gpr64_gpr64_plus_gpr64(addr, off, value);
|
||||
} else if (offset >= INT8_MIN && offset <= INT8_MAX) {
|
||||
return store64_gpr64_gpr64_plus_gpr64_plus_s8(addr, off, value, offset);
|
||||
} else if (offset >= INT32_MIN && offset <= INT32_MAX) {
|
||||
return store64_gpr64_gpr64_plus_gpr64_plus_s32(addr, off, value, offset);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@@ -719,6 +836,117 @@ class IGen {
|
||||
}
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// LOADS n' STORES - XMM32
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
static Instruction store32_xmm32_gpr64_plus_gpr64(Register addr1,
|
||||
Register addr2,
|
||||
Register xmm_value) {
|
||||
assert(xmm_value.is_xmm());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x11);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_addr(xmm_value.hw_id(), addr1.hw_id(), addr2.hw_id());
|
||||
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32_xmm32_gpr64_plus_gpr64(Register xmm_dest,
|
||||
Register addr1,
|
||||
Register addr2) {
|
||||
assert(xmm_dest.is_xmm());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x10);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_addr(xmm_dest.hw_id(), addr1.hw_id(), addr2.hw_id());
|
||||
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store32_xmm32_gpr64_plus_gpr64_plus_s8(Register addr1,
|
||||
Register addr2,
|
||||
Register xmm_value,
|
||||
s64 offset) {
|
||||
assert(xmm_value.is_xmm());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x11);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(xmm_value.hw_id(), addr1.hw_id(),
|
||||
addr2.hw_id(), offset, false);
|
||||
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32_xmm32_gpr64_plus_gpr64_plus_s8(Register xmm_dest,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(xmm_dest.is_xmm());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x10);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(xmm_dest.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, false);
|
||||
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction store32_xmm32_gpr64_plus_gpr64_plus_s32(Register addr1,
|
||||
Register addr2,
|
||||
Register xmm_value,
|
||||
s64 offset) {
|
||||
assert(xmm_value.is_xmm());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x11);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(xmm_value.hw_id(), addr1.hw_id(),
|
||||
addr2.hw_id(), offset, false);
|
||||
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32_xmm32_gpr64_plus_gpr64_plus_s32(Register xmm_dest,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(xmm_dest.is_xmm());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x10);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(xmm_dest.hw_id(), addr1.hw_id(),
|
||||
addr2.hw_id(), offset, false);
|
||||
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// LOADS n' STORES - XMM128
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -748,6 +976,12 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// RIP
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
// TODO
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// FUNCTION STUFF
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -805,6 +1039,10 @@ class IGen {
|
||||
// BIT STUFF
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// SHIFTS
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// CONTROL FLOW
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -230,7 +230,7 @@ struct Instruction {
|
||||
void set_modrm_and_rex_for_reg_plus_reg_plus_s32(uint8_t reg,
|
||||
uint8_t addr1,
|
||||
uint8_t addr2,
|
||||
s8 offset,
|
||||
s32 offset,
|
||||
bool rex_w) {
|
||||
bool rex_b = false, rex_r = false, rex_x = false;
|
||||
bool addr1_ext = false;
|
||||
|
||||
@@ -8,272 +8,10 @@
|
||||
namespace goal {
|
||||
class IGen {
|
||||
public:
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// MOVES
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
/*!
|
||||
* mov gpr, gpr, 64 bits
|
||||
*/
|
||||
static Instruction mov_gpr64_gpr64(uint8_t dst, uint8_t src) {
|
||||
assert(is_gpr(dst));
|
||||
assert(is_gpr(src));
|
||||
Instruction instr(0x89);
|
||||
instr.set_modrm_and_rex(src, dst, 3, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move a 64-bit constant into a register.
|
||||
*/
|
||||
static Instruction mov_gpr64_u64(uint8_t dst, uint64_t val) {
|
||||
assert(is_gpr(dst));
|
||||
bool rex_b = false;
|
||||
if (dst >= 8) {
|
||||
dst -= 8;
|
||||
rex_b = true;
|
||||
}
|
||||
Instruction instr(0xb8 + dst);
|
||||
instr.set(REX(true, false, false, rex_b));
|
||||
instr.set(Imm(8, val));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move a 32-bit constant into a register.
|
||||
*/
|
||||
static Instruction mov_gpr64_u32(uint8_t dst, uint64_t val) {
|
||||
assert(val <= UINT32_MAX);
|
||||
assert(is_gpr(dst));
|
||||
bool rex_b = false;
|
||||
if (dst >= 8) {
|
||||
dst -= 8;
|
||||
rex_b = true;
|
||||
}
|
||||
|
||||
Instruction instr(0xb8 + dst);
|
||||
if (rex_b) {
|
||||
instr.set(REX(false, false, false, rex_b));
|
||||
}
|
||||
instr.set(Imm(4, val));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move a signed 32-bit constant into a register.
|
||||
* When possible prefer mov_gpr64_u32. (use this only for negative values...)
|
||||
* This is always bigger than mov_gpr64_u32, but smaller than a mov_gpr_u64.
|
||||
*/
|
||||
static Instruction mov_gpr64_s32(uint8_t dst, int64_t val) {
|
||||
assert(val >= INT32_MIN && val <= INT32_MAX);
|
||||
assert(is_gpr(dst));
|
||||
Instruction instr(0xc7);
|
||||
instr.set_modrm_and_rex(0, dst, 3, true);
|
||||
instr.set(Imm(4, val));
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move 32-bits of xmm to 32 bits of gpr (no sign extension).
|
||||
*/
|
||||
static Instruction movd_gpr32_xmm32(uint8_t dst, uint8_t src) {
|
||||
assert(is_gpr(dst));
|
||||
assert(is_xmm(src));
|
||||
Instruction instr(0x66);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x7e);
|
||||
instr.set_modrm_and_rex(xmm_to_id(src), dst, 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move 32-bits of gpr to 32-bits of xmm (no sign extenion)
|
||||
*/
|
||||
static Instruction movd_xmm32_gpr32(uint8_t dst, uint8_t src) {
|
||||
assert(is_xmm(dst));
|
||||
assert(is_gpr(src));
|
||||
Instruction instr(0x66);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x6e);
|
||||
instr.set_modrm_and_rex(dst, xmm_to_id(src), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move 32-bits between xmm's
|
||||
*/
|
||||
static Instruction mov_xmm32_xmm32(uint8_t dst, uint8_t src) {
|
||||
assert(is_xmm(dst));
|
||||
assert(is_xmm(src));
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x10);
|
||||
instr.set_modrm_and_rex(xmm_to_id(dst), xmm_to_id(src), 3, false);
|
||||
return instr;
|
||||
}
|
||||
//
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// // LOADS n' STORES
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
//
|
||||
// /*!
|
||||
// * Store 8-bits from register into a memory location that is the sum of a 64-bit register
|
||||
// * and signed 32-bit offset.
|
||||
// */
|
||||
// static Instruction store8_r64off32s_gpr8(uint8_t dst_reg, int32_t offset, uint8_t src_reg) {
|
||||
// Instruction instr(0x88);
|
||||
// instr.set_modrm_and_rex_for_addr(src_reg, dst_reg, 2, false);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// if (src_reg > int(X86R::RBX)) {
|
||||
// instr.add_rex();
|
||||
// }
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Store 16-bits from register into a memory location that is the sum of a 64-bit register
|
||||
// * and signed 32-bit offset.
|
||||
// */
|
||||
// static Instruction store16_r64off32s_gpr16(uint8_t dst_reg, int32_t offset, uint8_t src_reg) {
|
||||
// Instruction instr(0x66);
|
||||
// instr.set_op2(0x89);
|
||||
// instr.set_modrm_and_rex_for_addr(src_reg, dst_reg, 2, false);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Store 32-bits from register into a memory location that is the sum of a 64-bit register
|
||||
// * and signed 32-bit offset.
|
||||
// */
|
||||
// static Instruction store32_r64off32s_gpr32(uint8_t dst_reg, int32_t offset, uint8_t src_reg) {
|
||||
// Instruction instr(0x89);
|
||||
// instr.set_modrm_and_rex_for_addr(src_reg, dst_reg, 2, false);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Store 64-bits from gpr into memory located at 64-bit reg + 32-bit signed offset.
|
||||
// */
|
||||
// static Instruction store64_r64off32s_gpr64(uint8_t dst_reg, int32_t offset, uint8_t src_reg) {
|
||||
// Instruction instr(0x89);
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(src_reg, 2, dst_reg, true);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Load 8-bits from memory (at address of 64-bit reg + 32-bit signed offset) into gpr (zero
|
||||
// * extended)
|
||||
// */
|
||||
// static Instruction load16_gpr8z_r64off32s(uint8_t dst, uint8_t src, int32_t offset) {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0xb6);
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(dst, 2, src, true);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Load 16-bits from memory (at address of 64-bit reg + 32-bit signed offset) into gpr (zero
|
||||
// * extended)
|
||||
// */
|
||||
// static Instruction load16_gpr16z_r64off32s(uint8_t dst, uint8_t src, int32_t offset) {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0xb7);
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(dst, 2, src, true);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Load 16-bits from memory (at address of 64-bit reg + 32-bit signed offset) into gpr (sign
|
||||
// * extended)
|
||||
// */
|
||||
// static Instruction load16_gpr16s_r64off32s(uint8_t dst, uint8_t src, int32_t offset) {
|
||||
// Instruction instr(0x0f);
|
||||
// instr.set_op2(0xbf);
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(dst, 2, src, true);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Load 32-bits from memory (at address of 64-bit reg + 32-bit signed offset) into gpr.
|
||||
// * Use the sext flag to enable sign extension.
|
||||
// */
|
||||
// static Instruction load32_gpr32sz_r64off32s(uint8_t dst_reg,
|
||||
// int32_t offset,
|
||||
// uint8_t src_reg,
|
||||
// bool sext = false) {
|
||||
// Instruction instr(0x8b);
|
||||
// if (sext) {
|
||||
// instr.op = 0x63;
|
||||
// }
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(dst_reg, 2, src_reg, sext);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Load 64-bits from memory located at 64-bit reg + 32-bit signed offset into gpr
|
||||
// */
|
||||
// static Instruction load64_gpr64_r64off32s(uint8_t dst_reg, int32_t offset, uint8_t src_reg) {
|
||||
// Instruction instr(0x8b);
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(dst_reg, 2, src_reg, true);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// return instr;
|
||||
// }
|
||||
//
|
||||
// /*!
|
||||
// * Load 32-bits form memory located at 64-bit reg + 32-bit signed offset into xmm (32-bits)
|
||||
// * movss
|
||||
// */
|
||||
// static Instruction load32_xmm32_r64off32s(uint8_t dst, uint8_t src, int32_t offset) {
|
||||
// Instruction instr(0xf3);
|
||||
// instr.set_op2(0x0f);
|
||||
// instr.set_op3(0x10);
|
||||
// instr.set_modrm_rex_sib_for_reg_reg_disp32(dst, 2, src, false);
|
||||
// instr.set_disp(Imm(4, offset));
|
||||
// instr.swap_op0_rex();
|
||||
// return instr;
|
||||
// }
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// FUNCTION STUFF
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
* Return instruction
|
||||
*/
|
||||
static Instruction ret() { return Instruction(0xc3); }
|
||||
|
||||
/*!
|
||||
* Instruction to push gpr (64-bits) onto the stack
|
||||
*/
|
||||
static Instruction push_gpr64(uint8_t reg) {
|
||||
if (reg >= 8) {
|
||||
auto i = Instruction(0x50 + reg - 8);
|
||||
i.set(REX(false, false, false, true));
|
||||
return i;
|
||||
}
|
||||
return Instruction(0x50 + reg);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Instruction to pop 64 bit gpr from the stack
|
||||
*/
|
||||
static Instruction pop_gpr64(uint8_t reg) {
|
||||
if (reg >= 8) {
|
||||
auto i = Instruction(0x58 + reg - 8);
|
||||
i.set(REX(false, false, false, true));
|
||||
return i;
|
||||
}
|
||||
return Instruction(0x58 + reg);
|
||||
}
|
||||
|
||||
// /*!
|
||||
// * Call a function stored in a 64-bit gpr
|
||||
// */
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@ add_executable(goalc-test
|
||||
test_type_system.cpp
|
||||
test_CodeTester.cpp
|
||||
test_emitter_slow.cpp
|
||||
test_emitter_fast.cpp
|
||||
test_emitter_loads_and_store.cpp
|
||||
test_emitter_xmm32.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(goalc-test goos util listener runtime emitter type_system gtest)
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* @file test_emitter_slow.cpp
|
||||
* @file test_emitter_loads_and_stores.cpp
|
||||
* Tests for the emitter which are fast (checking 100's of functions)
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//
|
||||
using namespace emitter;
|
||||
|
||||
TEST(Emitter, load_constant_64_and_move_gpr_gpr_64) {
|
||||
TEST(EmitterLoadsAndStores, load_constant_64_and_move_gpr_gpr_64) {
|
||||
std::vector<u64> u64_constants = {0, UINT64_MAX, INT64_MAX, 7, 12};
|
||||
|
||||
// test we can load a 64-bit constant into all gprs, move it to any other gpr, and return it.
|
||||
@@ -42,7 +42,7 @@ TEST(Emitter, load_constant_64_and_move_gpr_gpr_64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load_constant_32_unsigned) {
|
||||
TEST(EmitterLoadsAndStores, load_constant_32_unsigned) {
|
||||
std::vector<u64> u64_constants = {0, UINT32_MAX, INT32_MAX, 7, 12};
|
||||
|
||||
// test loading 32-bit constants, with all upper 32-bits zero.
|
||||
@@ -68,7 +68,7 @@ TEST(Emitter, load_constant_32_unsigned) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load_constant_32_signed) {
|
||||
TEST(EmitterLoadsAndStores, load_constant_32_signed) {
|
||||
std::vector<s32> s32_constants = {0, 1, INT32_MAX, INT32_MIN, 12, -1};
|
||||
|
||||
// test loading signed 32-bit constants. for values < 0 this will sign extend.
|
||||
@@ -92,7 +92,7 @@ TEST(Emitter, load_constant_32_signed) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load8s_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load8s_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -167,7 +167,7 @@ TEST(Emitter, load8s_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load8s_gpr64_gpr64_gpr64_s8) {
|
||||
TEST(EmitterLoadsAndStores, load8s_gpr64_gpr64_gpr64_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -236,7 +236,7 @@ TEST(Emitter, load8s_gpr64_gpr64_gpr64_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load8s_gpr64_gpr64_gpr64_s32) {
|
||||
TEST(EmitterLoadsAndStores, load8s_gpr64_gpr64_gpr64_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -305,7 +305,7 @@ TEST(Emitter, load8s_gpr64_gpr64_gpr64_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load8u_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load8u_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -380,7 +380,7 @@ TEST(Emitter, load8u_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load8u_gpr64_gpr64_gpr64_s8) {
|
||||
TEST(EmitterLoadsAndStores, load8u_gpr64_gpr64_gpr64_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -449,7 +449,7 @@ TEST(Emitter, load8u_gpr64_gpr64_gpr64_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load8u_gpr64_gpr64_gpr64_s32) {
|
||||
TEST(EmitterLoadsAndStores, load8u_gpr64_gpr64_gpr64_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -518,7 +518,7 @@ TEST(Emitter, load8u_gpr64_gpr64_gpr64_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load16s_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load16s_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -593,7 +593,7 @@ TEST(Emitter, load16s_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load16s_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, load16s_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -662,7 +662,7 @@ TEST(Emitter, load16s_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load16s_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, load16s_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -731,7 +731,7 @@ TEST(Emitter, load16s_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load16u_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load16u_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -806,7 +806,7 @@ TEST(Emitter, load16u_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load16u_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, load16u_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -875,7 +875,7 @@ TEST(Emitter, load16u_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load16u_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, load16u_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -944,7 +944,7 @@ TEST(Emitter, load16u_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load32s_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load32s_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1007,7 +1007,7 @@ TEST(Emitter, load32s_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load32s_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, load32s_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1076,7 +1076,7 @@ TEST(Emitter, load32s_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load32s_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, load32s_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1145,7 +1145,7 @@ TEST(Emitter, load32s_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load32u_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load32u_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1208,7 +1208,7 @@ TEST(Emitter, load32u_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load32u_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, load32u_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1277,7 +1277,7 @@ TEST(Emitter, load32u_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load32u_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, load32u_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1346,7 +1346,7 @@ TEST(Emitter, load32u_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load64_gpr64_goal_ptr_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, load64_gpr64_goal_ptr_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1409,7 +1409,7 @@ TEST(Emitter, load64_gpr64_goal_ptr_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, load64_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1478,7 +1478,7 @@ TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, load64_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1547,7 +1547,7 @@ TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, store8_gpr64_gpr64_plus_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1591,13 +1591,13 @@ TEST(Emitter, store8_gpr64_gpr64_plus_gpr64) {
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s8 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0};
|
||||
s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 3, 7, 0);
|
||||
EXPECT_EQ(memory[2], -3);
|
||||
tester.execute((u64)memory, 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], 7);
|
||||
EXPECT_EQ(memory[4], -1);
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
if (memory[3] != 7) {
|
||||
fmt::print("test {}, {}, {}\n", tester.reg_name(i), tester.reg_name(j),
|
||||
@@ -1610,7 +1610,7 @@ TEST(Emitter, store8_gpr64_gpr64_plus_gpr64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, store8_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1659,13 +1659,13 @@ TEST(Emitter, store8_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s8 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0};
|
||||
s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 6, 7, 0);
|
||||
EXPECT_EQ(memory[2], -3);
|
||||
tester.execute((u64)memory, 6, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], 7);
|
||||
EXPECT_EQ(memory[4], -1);
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
if (memory[3] != 7) {
|
||||
fmt::print("test {}, {}, {}\n", tester.reg_name(i), tester.reg_name(j),
|
||||
@@ -1678,7 +1678,7 @@ TEST(Emitter, store8_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, store8_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1727,13 +1727,13 @@ TEST(Emitter, store8_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s8 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0};
|
||||
s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 6, 7, 0);
|
||||
EXPECT_EQ(memory[2], -3);
|
||||
tester.execute((u64)memory, 6, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], 7);
|
||||
EXPECT_EQ(memory[4], -1);
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
if (memory[3] != 7) {
|
||||
fmt::print("test {}, {}, {}\n", tester.reg_name(i), tester.reg_name(j),
|
||||
@@ -1746,7 +1746,7 @@ TEST(Emitter, store8_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, store16_gpr64_gpr64_plus_gpr64) {
|
||||
TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1790,26 +1790,21 @@ TEST(Emitter, store16_gpr64_gpr64_plus_gpr64) {
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0};
|
||||
s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 6, 7, 0);
|
||||
EXPECT_EQ(memory[2], -3);
|
||||
EXPECT_EQ(memory[3], 7);
|
||||
EXPECT_EQ(memory[4], -1);
|
||||
tester.execute((u64)memory, 6, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s16(0xff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
if (memory[3] != 7) {
|
||||
fmt::print("test {}, {}, {}\n", tester.reg_name(i), tester.reg_name(j),
|
||||
tester.reg_name(k));
|
||||
printf("%s\n", tester.dump_to_hex_string().c_str());
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, store16_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1858,26 +1853,21 @@ TEST(Emitter, store16_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0};
|
||||
s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 6 + 3, 7, 0);
|
||||
EXPECT_EQ(memory[2], -3);
|
||||
EXPECT_EQ(memory[3], 7);
|
||||
EXPECT_EQ(memory[4], -1);
|
||||
tester.execute((u64)memory, 6 + 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s16(0xff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
if (memory[3] != 7) {
|
||||
fmt::print("test {}, {}, {}\n", tester.reg_name(i), tester.reg_name(j),
|
||||
tester.reg_name(k));
|
||||
printf("%s\n", tester.dump_to_hex_string().c_str());
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Emitter, store16_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
@@ -1926,19 +1916,382 @@ TEST(Emitter, store16_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0};
|
||||
s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 6 + 3, 7, 0);
|
||||
EXPECT_EQ(memory[2], -3);
|
||||
EXPECT_EQ(memory[3], 7);
|
||||
EXPECT_EQ(memory[4], -1);
|
||||
tester.execute((u64)memory, 6 + 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s16(0xff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
if (memory[3] != 7) {
|
||||
fmt::print("test {}, {}, {}\n", tester.reg_name(i), tester.reg_name(j),
|
||||
tester.reg_name(k));
|
||||
printf("%s\n", tester.dump_to_hex_string().c_str());
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
tester.clear();
|
||||
tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64(RCX, RAX, R8));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "44 89 04 08");
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
if (k == RSP || k == j || k == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
tester.emit(IGen::pop_gpr64(k)); // k will have the value to store.
|
||||
|
||||
// store!
|
||||
tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64(i, j, k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 12, 0xffffffff12341234, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], 0x12341234);
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
tester.clear();
|
||||
tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, R8, 12));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "44 89 44 01 0c");
|
||||
|
||||
auto instr = IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, -3);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
if (k == RSP || k == j || k == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
tester.emit(IGen::pop_gpr64(k)); // k will have the value to store.
|
||||
|
||||
// store
|
||||
tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 12 + 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s32(0xffffff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
tester.clear();
|
||||
tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, R8, 12));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "44 89 84 01 0c 00 00 00");
|
||||
|
||||
auto instr = IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
if (k == RSP || k == j || k == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
tester.emit(IGen::pop_gpr64(k)); // k will have the value to store.
|
||||
|
||||
// store
|
||||
tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 12 + 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s32(0xffffff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
tester.clear();
|
||||
tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64(RCX, RAX, R8));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 04 08");
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
if (k == RSP || k == j || k == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
tester.emit(IGen::pop_gpr64(k)); // k will have the value to store.
|
||||
|
||||
// store!
|
||||
tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64(i, j, k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 24, 0xffffffff12341234, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], 0xffffffff12341234);
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
tester.clear();
|
||||
tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, R8, 12));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 44 01 0c");
|
||||
|
||||
auto instr = IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, -3);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
if (k == RSP || k == j || k == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
tester.emit(IGen::pop_gpr64(k)); // k will have the value to store.
|
||||
|
||||
// store
|
||||
tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 24 + 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s64(0xffffffffffffff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
|
||||
tester.clear();
|
||||
tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, R8, 12));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 84 01 0c 00 00 00");
|
||||
|
||||
auto instr = IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
if (k == RSP || k == j || k == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
tester.emit(IGen::pop_gpr64(k)); // k will have the value to store.
|
||||
|
||||
// store
|
||||
tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 24 + 3, 0xffffffffffffff07, 0);
|
||||
EXPECT_EQ(memory[2], 3);
|
||||
EXPECT_EQ(memory[3], s64(0xffffffffffffff07));
|
||||
EXPECT_EQ(memory[4], 1);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "goalc/emitter/CodeTester.h"
|
||||
#include "goalc/emitter/IGen.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
using namespace emitter;
|
||||
|
||||
TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64(XMM3, RAX, RBX));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 1c 03");
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
for (int k = 0; k < 16; k++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// fill k with junk
|
||||
tester.emit(IGen::mov_gpr64_u64(i, (iter & 1) ? 0 : UINT64_MAX));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
|
||||
// load into k
|
||||
tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64(XMM0 + k, i, j));
|
||||
// move to return
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 3 * sizeof(float), 0, 0), 3.45f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 2 * sizeof(float), 0, 0), 1.23f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 4 * sizeof(float), 0, 0), 5.67f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 5 * sizeof(float), 0, 0), 0);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(XMM3, RAX, RBX, -1));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 5c 03 ff");
|
||||
|
||||
auto instr = IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(XMM3, RBX, RSI, -3);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
for (int k = 0; k < 16; k++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// fill k with junk
|
||||
tester.emit(IGen::mov_gpr64_u64(i, (iter & 1) ? 0 : UINT64_MAX));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
|
||||
// load into k
|
||||
tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(XMM0 + k, i, j, -3));
|
||||
// move to return
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 3 * sizeof(float) + 3, 0, 0), 3.45f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 2 * sizeof(float) + 3, 0, 0), 1.23f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 4 * sizeof(float) + 3, 0, 0), 5.67f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 5 * sizeof(float) + 3, 0, 0), 0);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(XMM3, RAX, RBX, -1));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 9c 03 ff ff ff ff");
|
||||
|
||||
auto instr = IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(XMM3, RBX, RSI, -1234);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -1234);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
for (int k = 0; k < 16; k++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1)));
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0)));
|
||||
|
||||
// fill k with junk
|
||||
tester.emit(IGen::mov_gpr64_u64(i, (iter & 1) ? 0 : UINT64_MAX));
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i));
|
||||
|
||||
// pop args into appropriate register
|
||||
tester.emit(IGen::pop_gpr64(i)); // i will have offset 0
|
||||
tester.emit(IGen::pop_gpr64(j)); // j will have offset 1
|
||||
|
||||
s64 offset = (iter & 1) ? INT32_MAX : INT32_MIN;
|
||||
|
||||
// load into k
|
||||
tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(XMM0 + k, i, j, offset));
|
||||
// move to return
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 3 * sizeof(float) - offset, 0, 0), 3.45f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 2 * sizeof(float) - offset, 0, 0), 1.23f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 4 * sizeof(float) - offset, 0, 0), 5.67f);
|
||||
EXPECT_EQ(tester.execute_ret<float>((u64)memory, 5 * sizeof(float) - offset, 0, 0), 0);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
float as_float(T x) {
|
||||
float result;
|
||||
memcpy(&result, &x, sizeof(float));
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 as_u32(float x) {
|
||||
u32 result;
|
||||
memcpy(&result, &x, 4);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64(RAX, RBX, XMM7));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 3c 03");
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 16; k++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); // addr2
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); // addr1
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); // value
|
||||
|
||||
// pop value into addr1 GPR
|
||||
tester.emit(IGen::pop_gpr64(i));
|
||||
// move to XMM
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i));
|
||||
|
||||
// pop addrs
|
||||
tester.emit(IGen::pop_gpr64(i));
|
||||
tester.emit(IGen::pop_gpr64(j));
|
||||
|
||||
// store
|
||||
tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64(i, j, XMM0 + k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 12, as_u32(1.234f), 0);
|
||||
EXPECT_EQ(memory[2], 1.23f);
|
||||
EXPECT_EQ(memory[3], 1.234f);
|
||||
EXPECT_EQ(memory[4], 5.67f);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64_plus_s8) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(RAX, RBX, XMM3, -1));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 5c 03 ff");
|
||||
|
||||
auto instr = IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(RBX, RSI, XMM3, -3);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
for (int k = 0; k < 16; k++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); // addr2
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); // addr1
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); // value
|
||||
|
||||
// pop value into addr1 GPR
|
||||
tester.emit(IGen::pop_gpr64(i));
|
||||
// move to XMM
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i));
|
||||
|
||||
// pop addrs
|
||||
tester.emit(IGen::pop_gpr64(i));
|
||||
tester.emit(IGen::pop_gpr64(j));
|
||||
|
||||
s64 offset = (iter & 1) ? INT8_MAX : INT8_MIN;
|
||||
|
||||
// load into k
|
||||
tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(i, j, XMM0 + k, offset));
|
||||
|
||||
// move to return
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 12 - offset, as_u32(1.234f), 0);
|
||||
EXPECT_EQ(memory[2], 1.23f);
|
||||
EXPECT_EQ(memory[3], 1.234f);
|
||||
EXPECT_EQ(memory[4], 5.67f);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64_plus_s32) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(512);
|
||||
tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(RAX, RBX, XMM3, -1));
|
||||
EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 9c 03 ff ff ff ff");
|
||||
|
||||
auto instr = IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(RBX, RSI, XMM3, -1234);
|
||||
u8 buff[256];
|
||||
instr.emit(buff);
|
||||
EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -1234);
|
||||
|
||||
int iter = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == RSP) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 16; j++) {
|
||||
if (j == RSP || j == i) {
|
||||
continue;
|
||||
}
|
||||
for (int k = 0; k < 16; k++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_xmms();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// push args to the stack
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); // addr2
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); // addr1
|
||||
tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); // value
|
||||
|
||||
// pop value into addr1 GPR
|
||||
tester.emit(IGen::pop_gpr64(i));
|
||||
// move to XMM
|
||||
tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i));
|
||||
|
||||
// pop addrs
|
||||
tester.emit(IGen::pop_gpr64(i));
|
||||
tester.emit(IGen::pop_gpr64(j));
|
||||
|
||||
s64 offset = (iter & 1) ? INT32_MAX : INT32_MIN;
|
||||
|
||||
// load into k
|
||||
tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(i, j, XMM0 + k, offset));
|
||||
|
||||
// move to return
|
||||
tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k));
|
||||
|
||||
// return!
|
||||
tester.emit_pop_all_gprs(true);
|
||||
tester.emit_pop_all_xmms();
|
||||
tester.emit_return();
|
||||
|
||||
// prepare the memory:
|
||||
float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0};
|
||||
|
||||
// run!
|
||||
tester.execute((u64)memory, 12 - offset, as_u32(1.234f), 0);
|
||||
EXPECT_EQ(memory[2], 1.23f);
|
||||
EXPECT_EQ(memory[3], 1.234f);
|
||||
EXPECT_EQ(memory[4], 5.67f);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user