From 5100aa6a300dbcd97884e5ecd5d27c994a81a2ca Mon Sep 17 00:00:00 2001 From: water Date: Sat, 29 Aug 2020 22:41:46 -0400 Subject: [PATCH] add some stores --- doc/emitter.md | 0 goalc/emitter/CodeTester.cpp | 12 +- goalc/emitter/CodeTester.h | 8 +- goalc/emitter/IGen.h | 144 +++++++++++ goalc/emitter/Instruction.h | 45 ++-- goalc/emitter/Register.cpp | 15 +- goalc/emitter/Register.h | 38 +-- goalc/goos/Interpreter.cpp | 1 - test/test_CodeTester.cpp | 1 - test/test_emitter_fast.cpp | 486 +++++++++++++++++++++++++++++++---- test/test_emitter_slow.cpp | 2 - 11 files changed, 635 insertions(+), 117 deletions(-) create mode 100644 doc/emitter.md diff --git a/doc/emitter.md b/doc/emitter.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/goalc/emitter/CodeTester.cpp b/goalc/emitter/CodeTester.cpp index f64cb4e60b..6ab824e4e6 100644 --- a/goalc/emitter/CodeTester.cpp +++ b/goalc/emitter/CodeTester.cpp @@ -4,15 +4,13 @@ namespace emitter { -CodeTester::CodeTester() : m_info(RegisterInfo::make_register_info()) { - -} +CodeTester::CodeTester() : m_info(RegisterInfo::make_register_info()) {} std::string CodeTester::dump_to_hex_string(bool nospace) { std::string result; char buff[32]; for (int i = 0; i < code_buffer_size; i++) { - if(nospace) { + if (nospace) { sprintf(buff, "%02X", code_buffer[i]); } else { sprintf(buff, "%02x ", code_buffer[i]); @@ -60,14 +58,14 @@ void CodeTester::emit_push_all_gprs(bool exclude_rax) { void CodeTester::emit_push_all_xmms() { emit(IGen::sub_gpr64_imm8s(RSP, 8)); - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { emit(IGen::sub_gpr64_imm8s(RSP, 16)); emit(IGen::store128_gpr64_xmm128(RSP, XMM0 + i)); } } void CodeTester::emit_pop_all_xmms() { - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { emit(IGen::load128_xmm128_gpr64(XMM0 + i, RSP)); emit(IGen::add_gpr64_imm8s(RSP, 16)); } @@ -103,4 +101,4 @@ CodeTester::~CodeTester() { munmap(code_buffer, code_buffer_capacity); } } -} \ No newline at end of file +} // namespace emitter \ No newline at end of file diff --git a/goalc/emitter/CodeTester.h b/goalc/emitter/CodeTester.h index 626ff8e4e2..a4cfa8497d 100644 --- a/goalc/emitter/CodeTester.h +++ b/goalc/emitter/CodeTester.h @@ -26,7 +26,7 @@ class CodeTester { Register get_c_abi_arg_reg(int i) { // todo - this should be different for windows. - switch(i) { + switch (i) { case 0: return RDI; case 1: @@ -40,9 +40,7 @@ class CodeTester { } } - std::string reg_name(Register x) { - return m_info.get_info(x).name; - } + std::string reg_name(Register x) { return m_info.get_info(x).name; } private: int code_buffer_size = 0; @@ -50,5 +48,5 @@ class CodeTester { u8* code_buffer = nullptr; RegisterInfo m_info; }; -} // namespace goal +} // namespace emitter #endif // JAK_CODETESTER_H diff --git a/goalc/emitter/IGen.h b/goalc/emitter/IGen.h index c8e9404ebd..869ff9f913 100644 --- a/goalc/emitter/IGen.h +++ b/goalc/emitter/IGen.h @@ -142,6 +142,21 @@ class IGen { return instr; } + static Instruction store8_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(0x88); + instr.set_modrm_and_rex_for_reg_plus_reg_addr(value.hw_id(), addr1.hw_id(), addr2.hw_id()); + if (value.id() > RBX) { + instr.add_rex(); + } + return instr; + } + static Instruction load8s_gpr64_gpr64_plus_gpr64_plus_s8(Register dst, Register addr1, Register addr2, @@ -160,6 +175,26 @@ class IGen { return instr; } + static Instruction store8_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(0x88); + instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(value.hw_id(), addr1.hw_id(), addr2.hw_id(), + offset, false); + if (value.id() > RBX) { + instr.add_rex(); + } + return instr; + } + static Instruction load8s_gpr64_gpr64_plus_gpr64_plus_s32(Register dst, Register addr1, Register addr2, @@ -178,6 +213,26 @@ class IGen { return instr; } + static Instruction store8_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(0x88); + instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(value.hw_id(), addr1.hw_id(), addr2.hw_id(), + offset, false); + if (value.id() > RBX) { + instr.add_rex(); + } + return instr; + } + /*! * movzx dst, BYTE PTR [addr1 + addr2] * addr1 and addr2 have to be different registers. @@ -252,6 +307,60 @@ class IGen { return instr; } + static Instruction store16_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(0x66); + instr.set_op2(0x89); + instr.set_modrm_and_rex_for_reg_plus_reg_addr(value.hw_id(), addr1.hw_id(), addr2.hw_id()); + instr.swap_op0_rex(); // why????? + return instr; + } + + static Instruction store16_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(0x66); + instr.set_op2(0x89); + instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(value.hw_id(), addr1.hw_id(), addr2.hw_id(), + offset, false); + instr.swap_op0_rex(); // why????? + return instr; + } + + static Instruction store16_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(0x66); + instr.set_op2(0x89); + instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(value.hw_id(), addr1.hw_id(), addr2.hw_id(), + offset, false); + instr.swap_op0_rex(); // why????? + return instr; + } + static Instruction load16s_gpr64_gpr64_plus_gpr64_plus_s8(Register dst, Register addr1, Register addr2, @@ -496,6 +605,41 @@ class IGen { return instr; } + static Instruction store_goal_gpr(Register addr, + Register value, + Register off, + int offset, + int size) { + switch (size) { + case 1: + if (offset == 0) { + return store8_gpr64_gpr64_plus_gpr64(addr, off, value); + } else if (offset >= INT8_MIN && offset <= INT8_MAX) { + return store8_gpr64_gpr64_plus_gpr64_plus_s8(addr, off, value, offset); + } else if (offset >= INT32_MIN && offset <= INT32_MAX) { + return store8_gpr64_gpr64_plus_gpr64_plus_s32(addr, off, value, offset); + } else { + assert(false); + } + case 2: + if (offset == 0) { + return store16_gpr64_gpr64_plus_gpr64(addr, off, value); + } else if (offset >= INT8_MIN && offset <= INT8_MAX) { + return store16_gpr64_gpr64_plus_gpr64_plus_s8(addr, off, value, offset); + } else if (offset >= INT32_MIN && offset <= INT32_MAX) { + return store16_gpr64_gpr64_plus_gpr64_plus_s32(addr, off, value, offset); + } else { + assert(false); + } + default: + assert(false); + } + } + + /*! + * Load memory at addr + offset, where addr is a GOAL pointer and off is the offset register. + * This will pick the appropriate fancy addressing mode instruction. + */ static Instruction load_goal_gpr(Register dst, Register addr, Register off, diff --git a/goalc/emitter/Instruction.h b/goalc/emitter/Instruction.h index e93b1fdbbd..0ec970e939 100644 --- a/goalc/emitter/Instruction.h +++ b/goalc/emitter/Instruction.h @@ -169,7 +169,11 @@ struct Instruction { } } - void set_modrm_and_rex_for_reg_plus_reg_plus_s8(uint8_t reg, uint8_t addr1, uint8_t addr2, s8 offset, bool rex_w) { + void set_modrm_and_rex_for_reg_plus_reg_plus_s8(uint8_t reg, + uint8_t addr1, + uint8_t addr2, + s8 offset, + bool rex_w) { bool rex_b = false, rex_r = false, rex_x = false; bool addr1_ext = false; bool addr2_ext = false; @@ -190,8 +194,8 @@ struct Instruction { } ModRM modrm; - modrm.mod = 1; // no disp - modrm.rm = 4; // sib! + modrm.mod = 1; // no disp + modrm.rm = 4; // sib! modrm.reg_op = reg; SIB sib; @@ -200,7 +204,7 @@ struct Instruction { Imm imm2(1, offset); // default addr1 in index - if(addr1 == 4) { + if (addr1 == 4) { sib.index = addr2; sib.base = addr1; rex_x = addr2_ext; @@ -214,7 +218,7 @@ struct Instruction { } assert(sib.index != 4); - if(rex_b || rex_w || rex_r || rex_x) { + if (rex_b || rex_w || rex_r || rex_x) { set(REX(rex_w, rex_r, rex_x, rex_b)); } @@ -223,7 +227,11 @@ struct Instruction { set_disp(imm2); } - void set_modrm_and_rex_for_reg_plus_reg_plus_s32(uint8_t reg, uint8_t addr1, uint8_t addr2, s8 offset, bool rex_w) { + void set_modrm_and_rex_for_reg_plus_reg_plus_s32(uint8_t reg, + uint8_t addr1, + uint8_t addr2, + s8 offset, + bool rex_w) { bool rex_b = false, rex_r = false, rex_x = false; bool addr1_ext = false; bool addr2_ext = false; @@ -244,8 +252,8 @@ struct Instruction { } ModRM modrm; - modrm.mod = 2; // no disp - modrm.rm = 4; // sib! + modrm.mod = 2; // no disp + modrm.rm = 4; // sib! modrm.reg_op = reg; SIB sib; @@ -254,7 +262,7 @@ struct Instruction { Imm imm2(4, offset); // default addr1 in index - if(addr1 == 4) { + if (addr1 == 4) { sib.index = addr2; sib.base = addr1; rex_x = addr2_ext; @@ -268,7 +276,7 @@ struct Instruction { } assert(sib.index != 4); - if(rex_b || rex_w || rex_r || rex_x) { + if (rex_b || rex_w || rex_r || rex_x) { set(REX(rex_w, rex_r, rex_x, rex_b)); } @@ -277,7 +285,11 @@ struct Instruction { set_disp(imm2); } - void set_modrm_and_rex_for_reg_plus_reg_addr(uint8_t reg, uint8_t addr1, uint8_t addr2, bool rex_w = false, bool rex_always = false) { + void set_modrm_and_rex_for_reg_plus_reg_addr(uint8_t reg, + uint8_t addr1, + uint8_t addr2, + bool rex_w = false, + bool rex_always = false) { bool rex_b = false, rex_r = false, rex_x = false; bool addr1_ext = false; bool addr2_ext = false; @@ -298,14 +310,14 @@ struct Instruction { } ModRM modrm; - modrm.mod = 0; // no disp - modrm.rm = 4; // sib! + modrm.mod = 0; // no disp + modrm.rm = 4; // sib! modrm.reg_op = reg; SIB sib; sib.scale = 0; - if(addr1 == 5 && addr2 == 5) { + if (addr1 == 5 && addr2 == 5) { sib.index = addr1; sib.base = addr2; rex_x = addr1_ext; @@ -317,7 +329,7 @@ struct Instruction { // default addr1 in index bool flipped = (addr1 == 4) || (addr2 == 5); - if(flipped) { + if (flipped) { sib.index = addr2; sib.base = addr1; rex_x = addr2_ext; @@ -333,8 +345,7 @@ struct Instruction { assert(sib.index != 4); } - - if(rex_b || rex_w || rex_r || rex_x || rex_always) { + if (rex_b || rex_w || rex_r || rex_x || rex_always) { set(REX(rex_w, rex_r, rex_x, rex_b)); } diff --git a/goalc/emitter/Register.cpp b/goalc/emitter/Register.cpp index 8f692cdcff..30cac4b18f 100644 --- a/goalc/emitter/Register.cpp +++ b/goalc/emitter/Register.cpp @@ -18,19 +18,16 @@ RegisterInfo RegisterInfo::make_register_info() { info.m_info[R10] = {6, true, false, "r10"}; info.m_info[R11] = {7, true, false, "r11"}; info.m_info[R12] = {-1, true, false, "r12"}; - info.m_info[R13] = {-1, false, true, "r13"}; // pp? - info.m_info[R14] = {-1, false, true, "r14"}; // st? - info.m_info[R15] = {-1, false, true, "r15"}; // offset. + info.m_info[R13] = {-1, false, true, "r13"}; // pp? + info.m_info[R14] = {-1, false, true, "r14"}; // st? + info.m_info[R15] = {-1, false, true, "r15"}; // offset. info.m_arg_regs = std::array({RDI, RSI, RDX, RCX, R8, R9, R10, R11}); info.m_saved_gprs = std::array({RBX, RBP, R10, R11, R12}); - info.m_saved_xmms = std::array({XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15}); + info.m_saved_xmms = + std::array({XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15}); return info; } - - - - -} \ No newline at end of file +} // namespace emitter \ No newline at end of file diff --git a/goalc/emitter/Register.h b/goalc/emitter/Register.h index 91acd4ada0..f8d17260b1 100644 --- a/goalc/emitter/Register.h +++ b/goalc/emitter/Register.h @@ -51,8 +51,6 @@ enum X86_REG : u8 { XMM15 }; - - class Register { public: Register() = default; @@ -75,9 +73,7 @@ class Register { return 0xff; } - int id() const { - return m_id; - } + int id() const { return m_id; } struct hash { auto operator()(const Register& x) const { return std::hash()(x.m_id); } @@ -109,37 +105,21 @@ class RegisterInfo { std::string name; }; - const Info& get_info(Register r) const { - return m_info.at(r.id()); - } + const Info& get_info(Register r) const { return m_info.at(r.id()); } - Register get_arg_reg(int id) const { - return m_arg_regs.at(id); - } + Register get_arg_reg(int id) const { return m_arg_regs.at(id); } - Register get_saved_gpr(int id) const { - return m_saved_gprs.at(id); - } + Register get_saved_gpr(int id) const { return m_saved_gprs.at(id); } - Register get_saved_xmm(int id) const { - return m_saved_xmms.at(id); - } + Register get_saved_xmm(int id) const { return m_saved_xmms.at(id); } - Register get_process_reg() const { - return R13; - } + Register get_process_reg() const { return R13; } - Register get_st_reg() const { - return R14; - } + Register get_st_reg() const { return R14; } - Register get_offset_reg() const { - return R15; - } + Register get_offset_reg() const { return R15; } - Register get_ret_reg() const { - return RAX; - } + Register get_ret_reg() const { return RAX; } private: RegisterInfo() = default; diff --git a/goalc/goos/Interpreter.cpp b/goalc/goos/Interpreter.cpp index 937525e050..3f514a19ff 100644 --- a/goalc/goos/Interpreter.cpp +++ b/goalc/goos/Interpreter.cpp @@ -85,7 +85,6 @@ Interpreter::Interpreter() { load_goos_library(); } - Interpreter::~Interpreter() { // There are some circular references that prevent shared_ptrs from cleaning up if we // don't do this. diff --git a/test/test_CodeTester.cpp b/test/test_CodeTester.cpp index 77e3e41832..04a56ab8a4 100644 --- a/test/test_CodeTester.cpp +++ b/test/test_CodeTester.cpp @@ -167,4 +167,3 @@ TEST(CodeTester, push_pop_all_the_things) { tester.emit_return(); tester.execute(); } - diff --git a/test/test_emitter_fast.cpp b/test/test_emitter_fast.cpp index f336458c1f..fbb6791ca4 100644 --- a/test/test_emitter_fast.cpp +++ b/test/test_emitter_fast.cpp @@ -139,8 +139,8 @@ TEST(Emitter, load8s_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -208,8 +208,8 @@ TEST(Emitter, load8s_gpr64_gpr64_gpr64_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -277,8 +277,8 @@ TEST(Emitter, load8s_gpr64_gpr64_gpr64_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -352,8 +352,8 @@ TEST(Emitter, load8u_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -421,8 +421,8 @@ TEST(Emitter, load8u_gpr64_gpr64_gpr64_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -490,8 +490,8 @@ TEST(Emitter, load8u_gpr64_gpr64_gpr64_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -565,8 +565,8 @@ TEST(Emitter, load16s_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -634,8 +634,8 @@ TEST(Emitter, load16s_gpr64_gpr64_plus_gpr64_plus_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -703,8 +703,8 @@ TEST(Emitter, load16s_gpr64_gpr64_plus_gpr64_plus_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -778,8 +778,8 @@ TEST(Emitter, load16u_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -847,8 +847,8 @@ TEST(Emitter, load16u_gpr64_gpr64_plus_gpr64_plus_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -916,8 +916,8 @@ TEST(Emitter, load16u_gpr64_gpr64_plus_gpr64_plus_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -952,7 +952,6 @@ TEST(Emitter, load32s_gpr64_goal_ptr_gpr64) { tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); EXPECT_EQ(tester.dump_to_hex_string(), "48 63 04 1e"); - int iter = 0; for (int i = 0; i < 16; i++) { if (i == RSP) { @@ -980,8 +979,8 @@ TEST(Emitter, load32s_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1049,8 +1048,8 @@ TEST(Emitter, load32s_gpr64_gpr64_plus_gpr64_plus_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1118,8 +1117,8 @@ TEST(Emitter, load32s_gpr64_gpr64_plus_gpr64_plus_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1154,7 +1153,6 @@ TEST(Emitter, load32u_gpr64_goal_ptr_gpr64) { tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); EXPECT_EQ(tester.dump_to_hex_string(), "8b 04 1e"); - int iter = 0; for (int i = 0; i < 16; i++) { if (i == RSP) { @@ -1182,8 +1180,8 @@ TEST(Emitter, load32u_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1251,8 +1249,8 @@ TEST(Emitter, load32u_gpr64_gpr64_plus_gpr64_plus_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1320,8 +1318,8 @@ TEST(Emitter, load32u_gpr64_gpr64_plus_gpr64_plus_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1356,7 +1354,6 @@ TEST(Emitter, load64_gpr64_goal_ptr_gpr64) { tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 04 1e"); - int iter = 0; for (int i = 0; i < 16; i++) { if (i == RSP) { @@ -1384,8 +1381,8 @@ TEST(Emitter, load64_gpr64_goal_ptr_gpr64) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1412,7 +1409,6 @@ TEST(Emitter, load64_gpr64_goal_ptr_gpr64) { } } - TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s8) { CodeTester tester; tester.init_code_buffer(512); @@ -1454,8 +1450,8 @@ TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s8) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1523,8 +1519,8 @@ TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s32) { tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 // fill k with junk - if(k != i && k != j) { - tester.emit(IGen::mov_gpr64_u64(k, (iter&1)?0:UINT64_MAX)); + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); } // load into k @@ -1549,4 +1545,402 @@ TEST(Emitter, load64_gpr64_gpr64_plus_gpr64_plus_s32) { } } } +} + +TEST(Emitter, store8_gpr64_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64(RAX, RCX, RDX)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 14 01"); + + 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::store8_gpr64_gpr64_plus_gpr64(i, j, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s8 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 3, 7, 0); + EXPECT_EQ(memory[2], -3); + EXPECT_EQ(memory[3], 7); + 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, store8_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 54 01 0c"); + + auto instr = IGen::store8_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::store8_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s8 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); + + 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, store8_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 94 01 0c 00 00 00"); + + auto instr = IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(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::store8_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s8 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); + + 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) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64(RCX, RAX, R8)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 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::store16_gpr64_gpr64_plus_gpr64(i, j, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + 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); + + 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) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 44 01 0c"); + + auto instr = IGen::store16_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::store16_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + 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); + + 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) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 84 01 0c 00 00 00"); + + auto instr = IGen::store16_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::store16_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + 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); + + 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++; + } + } + } } \ No newline at end of file diff --git a/test/test_emitter_slow.cpp b/test/test_emitter_slow.cpp index fc878cb578..ebe298745d 100644 --- a/test/test_emitter_slow.cpp +++ b/test/test_emitter_slow.cpp @@ -11,8 +11,6 @@ // using namespace emitter; - - TEST(EmitterSlow, xmm32_move) { std::vector u32_constants = {0, INT32_MAX, UINT32_MAX, 17};