more loads and stores

This commit is contained in:
water
2020-08-30 10:56:42 -04:00
parent 5100aa6a30
commit 92e1c0b496
7 changed files with 1067 additions and 337 deletions
+9
View File
@@ -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
View File
@@ -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
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+1 -1
View File
@@ -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;
-262
View File
@@ -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
View File
@@ -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++;
}
}
+391
View File
@@ -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++;
}
}
}
}