summaryrefslogtreecommitdiff
path: root/Source/UnitTests/Common/x64EmitterTest.cpp
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2016-06-24 10:43:46 +0200
committerPierre Bourdon <delroth@gmail.com>2016-06-24 10:43:46 +0200
commit3570c7f03a2aa90aa634f96c0af1969af610f14d (patch)
tree4252e03c0e853ba7cffe022937698c854ad0eaa9 /Source/UnitTests/Common/x64EmitterTest.cpp
parent2115e8a4a6814e32107b5205ff5c95bbd3c6e99c (diff)
Reformat all the things. Have fun with merge conflicts.
Diffstat (limited to 'Source/UnitTests/Common/x64EmitterTest.cpp')
-rw-r--r--Source/UnitTests/Common/x64EmitterTest.cpp1319
1 files changed, 656 insertions, 663 deletions
diff --git a/Source/UnitTests/Common/x64EmitterTest.cpp b/Source/UnitTests/Common/x64EmitterTest.cpp
index b6fe971546..648f9cdf34 100644
--- a/Source/UnitTests/Common/x64EmitterTest.cpp
+++ b/Source/UnitTests/Common/x64EmitterTest.cpp
@@ -5,10 +5,10 @@
#include <cctype>
#include <cstring>
#include <disasm.h> // From Bochs, fallback included in Externals.
+#include <gtest/gtest.h>
#include <map>
#include <memory>
#include <vector>
-#include <gtest/gtest.h>
// gtest defines the TEST macro to generate test case functions. It conflicts
// with the TEST method in the x64Emitter.
@@ -22,164 +22,153 @@
namespace Gen
{
-
struct NamedReg
{
- X64Reg reg;
- std::string name;
+ X64Reg reg;
+ std::string name;
};
-const std::vector<NamedReg> reg8names {
- { RAX, "al" }, { RBX, "bl" }, { RCX, "cl" }, { RDX, "dl" },
- { RSI, "sil" }, { RDI, "dil" }, { RBP, "bpl" }, { RSP, "spl" },
- { R8, "r8b" }, { R9, "r9b" }, { R10, "r10b" }, { R11, "r11b" },
- { R12, "r12b" }, { R13, "r13b" }, { R14, "r14b" }, { R15, "r15b" },
+const std::vector<NamedReg> reg8names{
+ {RAX, "al"}, {RBX, "bl"}, {RCX, "cl"}, {RDX, "dl"}, {RSI, "sil"}, {RDI, "dil"},
+ {RBP, "bpl"}, {RSP, "spl"}, {R8, "r8b"}, {R9, "r9b"}, {R10, "r10b"}, {R11, "r11b"},
+ {R12, "r12b"}, {R13, "r13b"}, {R14, "r14b"}, {R15, "r15b"},
};
-const std::vector<NamedReg> reg8hnames {
- { AH, "ah" }, { BH, "bh" }, { CH, "ch" }, { DH, "dh" },
+const std::vector<NamedReg> reg8hnames{
+ {AH, "ah"}, {BH, "bh"}, {CH, "ch"}, {DH, "dh"},
};
-const std::vector<NamedReg> reg16names {
- { RAX, "ax" }, { RBX, "bx" }, { RCX, "cx" }, { RDX, "dx" },
- { RSI, "si" }, { RDI, "di" }, { RBP, "bp" }, { RSP, "sp" },
- { R8, "r8w" }, { R9, "r9w" }, { R10, "r10w" }, { R11, "r11w" },
- { R12, "r12w" }, { R13, "r13w" }, { R14, "r14w" }, { R15, "r15w" },
+const std::vector<NamedReg> reg16names{
+ {RAX, "ax"}, {RBX, "bx"}, {RCX, "cx"}, {RDX, "dx"}, {RSI, "si"}, {RDI, "di"},
+ {RBP, "bp"}, {RSP, "sp"}, {R8, "r8w"}, {R9, "r9w"}, {R10, "r10w"}, {R11, "r11w"},
+ {R12, "r12w"}, {R13, "r13w"}, {R14, "r14w"}, {R15, "r15w"},
};
-const std::vector<NamedReg> reg32names {
- { RAX, "eax" }, { RBX, "ebx" }, { RCX, "ecx" }, { RDX, "edx" },
- { RSI, "esi" }, { RDI, "edi" }, { RBP, "ebp" }, { RSP, "esp" },
- { R8, "r8d" }, { R9, "r9d" }, { R10, "r10d" }, { R11, "r11d" },
- { R12, "r12d" }, { R13, "r13d" }, { R14, "r14d" }, { R15, "r15d" },
+const std::vector<NamedReg> reg32names{
+ {RAX, "eax"}, {RBX, "ebx"}, {RCX, "ecx"}, {RDX, "edx"}, {RSI, "esi"}, {RDI, "edi"},
+ {RBP, "ebp"}, {RSP, "esp"}, {R8, "r8d"}, {R9, "r9d"}, {R10, "r10d"}, {R11, "r11d"},
+ {R12, "r12d"}, {R13, "r13d"}, {R14, "r14d"}, {R15, "r15d"},
};
-const std::vector<NamedReg> reg64names {
- { RAX, "rax" }, { RBX, "rbx" }, { RCX, "rcx" }, { RDX, "rdx" },
- { RSI, "rsi" }, { RDI, "rdi" }, { RBP, "rbp" }, { RSP, "rsp" },
- { R8, "r8" }, { R9, "r9" }, { R10, "r10" }, { R11, "r11" },
- { R12, "r12" }, { R13, "r13" }, { R14, "r14" }, { R15, "r15" },
+const std::vector<NamedReg> reg64names{
+ {RAX, "rax"}, {RBX, "rbx"}, {RCX, "rcx"}, {RDX, "rdx"}, {RSI, "rsi"}, {RDI, "rdi"},
+ {RBP, "rbp"}, {RSP, "rsp"}, {R8, "r8"}, {R9, "r9"}, {R10, "r10"}, {R11, "r11"},
+ {R12, "r12"}, {R13, "r13"}, {R14, "r14"}, {R15, "r15"},
};
-const std::vector<NamedReg> xmmnames {
- { XMM0, "xmm0" }, { XMM1, "xmm1" }, { XMM2, "xmm2" }, { XMM3, "xmm3" },
- { XMM4, "xmm4" }, { XMM5, "xmm5" }, { XMM6, "xmm6" }, { XMM7, "xmm7" },
- { XMM8, "xmm8" }, { XMM9, "xmm9" }, { XMM10, "xmm10" }, { XMM11, "xmm11" },
- { XMM12, "xmm12" }, { XMM13, "xmm13" }, { XMM14, "xmm14" }, { XMM15, "xmm15" },
+const std::vector<NamedReg> xmmnames{
+ {XMM0, "xmm0"}, {XMM1, "xmm1"}, {XMM2, "xmm2"}, {XMM3, "xmm3"},
+ {XMM4, "xmm4"}, {XMM5, "xmm5"}, {XMM6, "xmm6"}, {XMM7, "xmm7"},
+ {XMM8, "xmm8"}, {XMM9, "xmm9"}, {XMM10, "xmm10"}, {XMM11, "xmm11"},
+ {XMM12, "xmm12"}, {XMM13, "xmm13"}, {XMM14, "xmm14"}, {XMM15, "xmm15"},
};
-const std::vector<NamedReg> ymmnames {
- { YMM0, "ymm0" }, { YMM1, "ymm1" }, { YMM2, "ymm2" }, { YMM3, "ymm3" },
- { YMM4, "ymm4" }, { YMM5, "ymm5" }, { YMM6, "ymm6" }, { YMM7, "ymm7" },
- { YMM8, "ymm8" }, { YMM9, "ymm9" }, { YMM10, "ymm10" }, { YMM11, "ymm11" },
- { YMM12, "ymm12" }, { YMM13, "ymm13" }, { YMM14, "ymm14" }, { YMM15, "ymm15" },
+const std::vector<NamedReg> ymmnames{
+ {YMM0, "ymm0"}, {YMM1, "ymm1"}, {YMM2, "ymm2"}, {YMM3, "ymm3"},
+ {YMM4, "ymm4"}, {YMM5, "ymm5"}, {YMM6, "ymm6"}, {YMM7, "ymm7"},
+ {YMM8, "ymm8"}, {YMM9, "ymm9"}, {YMM10, "ymm10"}, {YMM11, "ymm11"},
+ {YMM12, "ymm12"}, {YMM13, "ymm13"}, {YMM14, "ymm14"}, {YMM15, "ymm15"},
};
-struct { CCFlags cc; std::string name; } ccnames[] = {
- { CC_O, "o" }, { CC_NO, "no" },
- { CC_B, "b" }, { CC_NB, "nb" },
- { CC_Z, "z" }, { CC_NZ, "nz" },
- { CC_BE, "be" }, { CC_NBE, "nbe" },
- { CC_S, "s" }, { CC_NS, "ns" },
- { CC_P, "p" }, { CC_NP, "np" },
- { CC_L, "l" }, { CC_NL, "nl" },
- { CC_LE, "le" }, { CC_NLE, "nle" },
+struct
+{
+ CCFlags cc;
+ std::string name;
+} ccnames[] = {
+ {CC_O, "o"}, {CC_NO, "no"}, {CC_B, "b"}, {CC_NB, "nb"}, {CC_Z, "z"}, {CC_NZ, "nz"},
+ {CC_BE, "be"}, {CC_NBE, "nbe"}, {CC_S, "s"}, {CC_NS, "ns"}, {CC_P, "p"}, {CC_NP, "np"},
+ {CC_L, "l"}, {CC_NL, "nl"}, {CC_LE, "le"}, {CC_NLE, "nle"},
};
class x64EmitterTest : public testing::Test
{
protected:
- void SetUp() override
- {
- memset(&cpu_info, 0xFF, sizeof (cpu_info));
-
- emitter.reset(new X64CodeBlock());
- emitter->AllocCodeSpace(4096);
- code_buffer = emitter->GetWritableCodePtr();
-
- disasm.reset(new disassembler);
- disasm->set_syntax_intel();
- }
-
- void TearDown() override
- {
- cpu_info = CPUInfo();
- }
-
- void ExpectDisassembly(const std::string& expected)
- {
- std::string disasmed;
- const u8* generated_code_iterator = code_buffer;
- while (generated_code_iterator < emitter->GetCodePtr())
- {
- char instr_buffer[1024] = "";
- generated_code_iterator += disasm->disasm64(
- (u64)generated_code_iterator,
- (u64)generated_code_iterator,
- generated_code_iterator, instr_buffer);
- disasmed += instr_buffer;
- disasmed += "\n";
- }
-
- auto NormalizeAssembly = [](const std::string& str) -> std::string {
- // Normalize assembly code to make it suitable for equality checks.
- // In particular:
- // * Replace all whitespace characters by a single space.
- // * Remove leading and trailing whitespaces.
- // * Lowercase everything.
- // * Remove all (0x...) addresses.
- std::string out;
- bool previous_was_space = false;
- bool inside_parens = false;
- for (auto c : str)
- {
- c = tolower(c);
- if (c == '(')
- {
- inside_parens = true;
- continue;
- }
- else if (inside_parens)
- {
- if (c == ')')
- inside_parens = false;
- continue;
- }
- else if (isspace(c))
- {
- previous_was_space = true;
- continue;
- }
- else if (previous_was_space)
- {
- previous_was_space = false;
- if (!out.empty())
- out += ' ';
- }
- out += c;
- }
- return out;
- };
- std::string expected_norm = NormalizeAssembly(expected);
- std::string disasmed_norm = NormalizeAssembly(disasmed);
-
- EXPECT_EQ(expected_norm, disasmed_norm);
-
- // Reset code buffer afterwards.
- emitter->SetCodePtr(code_buffer);
- }
-
- std::unique_ptr<X64CodeBlock> emitter;
- std::unique_ptr<disassembler> disasm;
- u8* code_buffer;
+ void SetUp() override
+ {
+ memset(&cpu_info, 0xFF, sizeof(cpu_info));
+
+ emitter.reset(new X64CodeBlock());
+ emitter->AllocCodeSpace(4096);
+ code_buffer = emitter->GetWritableCodePtr();
+
+ disasm.reset(new disassembler);
+ disasm->set_syntax_intel();
+ }
+
+ void TearDown() override { cpu_info = CPUInfo(); }
+ void ExpectDisassembly(const std::string& expected)
+ {
+ std::string disasmed;
+ const u8* generated_code_iterator = code_buffer;
+ while (generated_code_iterator < emitter->GetCodePtr())
+ {
+ char instr_buffer[1024] = "";
+ generated_code_iterator +=
+ disasm->disasm64((u64)generated_code_iterator, (u64)generated_code_iterator,
+ generated_code_iterator, instr_buffer);
+ disasmed += instr_buffer;
+ disasmed += "\n";
+ }
+
+ auto NormalizeAssembly = [](const std::string& str) -> std::string {
+ // Normalize assembly code to make it suitable for equality checks.
+ // In particular:
+ // * Replace all whitespace characters by a single space.
+ // * Remove leading and trailing whitespaces.
+ // * Lowercase everything.
+ // * Remove all (0x...) addresses.
+ std::string out;
+ bool previous_was_space = false;
+ bool inside_parens = false;
+ for (auto c : str)
+ {
+ c = tolower(c);
+ if (c == '(')
+ {
+ inside_parens = true;
+ continue;
+ }
+ else if (inside_parens)
+ {
+ if (c == ')')
+ inside_parens = false;
+ continue;
+ }
+ else if (isspace(c))
+ {
+ previous_was_space = true;
+ continue;
+ }
+ else if (previous_was_space)
+ {
+ previous_was_space = false;
+ if (!out.empty())
+ out += ' ';
+ }
+ out += c;
+ }
+ return out;
+ };
+ std::string expected_norm = NormalizeAssembly(expected);
+ std::string disasmed_norm = NormalizeAssembly(disasmed);
+
+ EXPECT_EQ(expected_norm, disasmed_norm);
+
+ // Reset code buffer afterwards.
+ emitter->SetCodePtr(code_buffer);
+ }
+
+ std::unique_ptr<X64CodeBlock> emitter;
+ std::unique_ptr<disassembler> disasm;
+ u8* code_buffer;
};
-#define TEST_INSTR_NO_OPERANDS(Name, ExpectedDisasm) \
- TEST_F(x64EmitterTest, Name) \
- { \
- emitter->Name(); \
- ExpectDisassembly(ExpectedDisasm); \
- }
+#define TEST_INSTR_NO_OPERANDS(Name, ExpectedDisasm) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ emitter->Name(); \
+ ExpectDisassembly(ExpectedDisasm); \
+ }
TEST_INSTR_NO_OPERANDS(INT3, "int3")
TEST_INSTR_NO_OPERANDS(NOP, "nop")
@@ -211,79 +200,79 @@ TEST_INSTR_NO_OPERANDS(RDTSC, "rdtsc")
TEST_F(x64EmitterTest, NOP_MultiByte)
{
- // 2 bytes is "rep nop", still a simple nop.
- emitter->NOP(2);
- ExpectDisassembly("nop");
-
- for (int i = 3; i <= 11; ++i)
- {
- emitter->NOP(i);
- ExpectDisassembly("multibyte nop");
- }
-
- // Larger NOPs are split into several NOPs.
- emitter->NOP(20);
- ExpectDisassembly("multibyte nop "
- "multibyte nop");
+ // 2 bytes is "rep nop", still a simple nop.
+ emitter->NOP(2);
+ ExpectDisassembly("nop");
+
+ for (int i = 3; i <= 11; ++i)
+ {
+ emitter->NOP(i);
+ ExpectDisassembly("multibyte nop");
+ }
+
+ // Larger NOPs are split into several NOPs.
+ emitter->NOP(20);
+ ExpectDisassembly("multibyte nop "
+ "multibyte nop");
}
TEST_F(x64EmitterTest, PUSH_Register)
{
- for (const auto& r : reg64names)
- {
- emitter->PUSH(r.reg);
- ExpectDisassembly("push " + r.name);
- }
+ for (const auto& r : reg64names)
+ {
+ emitter->PUSH(r.reg);
+ ExpectDisassembly("push " + r.name);
+ }
}
TEST_F(x64EmitterTest, PUSH_Immediate)
{
- emitter->PUSH(64, Imm8(0xf0));
- ExpectDisassembly("push 0xfffffffffffffff0");
+ emitter->PUSH(64, Imm8(0xf0));
+ ExpectDisassembly("push 0xfffffffffffffff0");
- // X64 is weird like that... this pushes 2 bytes, not 8 bytes with sext.
- emitter->PUSH(64, Imm16(0xe0f0));
- ExpectDisassembly("push 0xe0f0");
+ // X64 is weird like that... this pushes 2 bytes, not 8 bytes with sext.
+ emitter->PUSH(64, Imm16(0xe0f0));
+ ExpectDisassembly("push 0xe0f0");
- emitter->PUSH(64, Imm32(0xc0d0e0f0));
- ExpectDisassembly("push 0xffffffffc0d0e0f0");
+ emitter->PUSH(64, Imm32(0xc0d0e0f0));
+ ExpectDisassembly("push 0xffffffffc0d0e0f0");
}
TEST_F(x64EmitterTest, PUSH_MComplex)
{
- emitter->PUSH(64, MComplex(RAX, RBX, SCALE_2, 4));
- ExpectDisassembly("push qword ptr ds:[rax+rbx*2+4]");
+ emitter->PUSH(64, MComplex(RAX, RBX, SCALE_2, 4));
+ ExpectDisassembly("push qword ptr ds:[rax+rbx*2+4]");
}
TEST_F(x64EmitterTest, POP_Register)
{
- for (const auto& r : reg64names)
- {
- emitter->POP(r.reg);
- ExpectDisassembly("pop " + r.name);
- }
+ for (const auto& r : reg64names)
+ {
+ emitter->POP(r.reg);
+ ExpectDisassembly("pop " + r.name);
+ }
}
TEST_F(x64EmitterTest, JMP)
{
- emitter->NOP(6);
- emitter->JMP(code_buffer);
- ExpectDisassembly("multibyte nop "
- "jmp .-8");
-
- emitter->NOP(6);
- emitter->JMP(code_buffer, true);
- ExpectDisassembly("multibyte nop "
- "jmp .-11");
+ emitter->NOP(6);
+ emitter->JMP(code_buffer);
+ ExpectDisassembly("multibyte nop "
+ "jmp .-8");
+
+ emitter->NOP(6);
+ emitter->JMP(code_buffer, true);
+ ExpectDisassembly("multibyte nop "
+ "jmp .-11");
}
TEST_F(x64EmitterTest, JMPptr_Register)
{
- for (const auto& r : reg64names)
- {
- emitter->JMPptr(R(r.reg));
- ExpectDisassembly("jmp " + r.name);
- }
+ for (const auto& r : reg64names)
+ {
+ emitter->JMPptr(R(r.reg));
+ ExpectDisassembly("jmp " + r.name);
+ }
}
// TODO: J/SetJumpTarget
@@ -294,59 +283,62 @@ TEST_F(x64EmitterTest, JMPptr_Register)
TEST_F(x64EmitterTest, SETcc)
{
- for (const auto& cc : ccnames)
- {
- for (const auto& r : reg8names)
- {
- emitter->SETcc(cc.cc, R(r.reg));
- ExpectDisassembly("set" + cc.name + " " + r.name);
- }
- for (const auto& r : reg8hnames)
- {
- emitter->SETcc(cc.cc, R(r.reg));
- ExpectDisassembly("set" + cc.name + " " + r.name);
- }
- }
+ for (const auto& cc : ccnames)
+ {
+ for (const auto& r : reg8names)
+ {
+ emitter->SETcc(cc.cc, R(r.reg));
+ ExpectDisassembly("set" + cc.name + " " + r.name);
+ }
+ for (const auto& r : reg8hnames)
+ {
+ emitter->SETcc(cc.cc, R(r.reg));
+ ExpectDisassembly("set" + cc.name + " " + r.name);
+ }
+ }
}
TEST_F(x64EmitterTest, CMOVcc_Register)
{
- for (const auto& cc : ccnames)
- {
- emitter->CMOVcc(64, RAX, R(R12), cc.cc);
- emitter->CMOVcc(32, RAX, R(R12), cc.cc);
- emitter->CMOVcc(16, RAX, R(R12), cc.cc);
-
- ExpectDisassembly("cmov" + cc.name + " rax, r12 "
- "cmov" + cc.name + " eax, r12d "
- "cmov" + cc.name + " ax, r12w");
- }
+ for (const auto& cc : ccnames)
+ {
+ emitter->CMOVcc(64, RAX, R(R12), cc.cc);
+ emitter->CMOVcc(32, RAX, R(R12), cc.cc);
+ emitter->CMOVcc(16, RAX, R(R12), cc.cc);
+
+ ExpectDisassembly("cmov" + cc.name + " rax, r12 "
+ "cmov" +
+ cc.name + " eax, r12d "
+ "cmov" +
+ cc.name + " ax, r12w");
+ }
}
-#define BITSEARCH_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string size; \
- std::string rax_name; \
- } regsets[] = { \
- { 16, reg16names, "word", "ax" }, \
- { 32, reg32names, "dword", "eax" }, \
- { 64, reg64names, "qword", "rax" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, r.reg, R(RAX)); \
- emitter->Name(regset.bits, RAX, R(r.reg)); \
- emitter->Name(regset.bits, r.reg, MatR(RAX)); \
- ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " \
- #Name " " + regset.rax_name + ", " + r.name + " " \
- #Name " " + r.name + ", " + regset.size + " ptr ds:[rax] " ); \
- } \
- }
+#define BITSEARCH_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string size; \
+ std::string rax_name; \
+ } regsets[] = { \
+ {16, reg16names, "word", "ax"}, \
+ {32, reg32names, "dword", "eax"}, \
+ {64, reg64names, "qword", "rax"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, r.reg, R(RAX)); \
+ emitter->Name(regset.bits, RAX, R(r.reg)); \
+ emitter->Name(regset.bits, r.reg, MatR(RAX)); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " #Name " " + \
+ regset.rax_name + ", " + r.name + " " #Name " " + r.name + ", " + \
+ regset.size + " ptr ds:[rax] "); \
+ } \
+ }
BITSEARCH_TEST(BSR);
BITSEARCH_TEST(BSF);
@@ -355,65 +347,65 @@ BITSEARCH_TEST(TZCNT);
TEST_F(x64EmitterTest, PREFETCH)
{
- emitter->PREFETCH(XEmitter::PF_NTA, MatR(R12));
- emitter->PREFETCH(XEmitter::PF_T0, MatR(R12));
- emitter->PREFETCH(XEmitter::PF_T1, MatR(R12));
- emitter->PREFETCH(XEmitter::PF_T2, MatR(R12));
-
- ExpectDisassembly("prefetchnta byte ptr ds:[r12] "
- "prefetcht0 byte ptr ds:[r12] "
- "prefetcht1 byte ptr ds:[r12] "
- "prefetcht2 byte ptr ds:[r12]");
+ emitter->PREFETCH(XEmitter::PF_NTA, MatR(R12));
+ emitter->PREFETCH(XEmitter::PF_T0, MatR(R12));
+ emitter->PREFETCH(XEmitter::PF_T1, MatR(R12));
+ emitter->PREFETCH(XEmitter::PF_T2, MatR(R12));
+
+ ExpectDisassembly("prefetchnta byte ptr ds:[r12] "
+ "prefetcht0 byte ptr ds:[r12] "
+ "prefetcht1 byte ptr ds:[r12] "
+ "prefetcht2 byte ptr ds:[r12]");
}
TEST_F(x64EmitterTest, MOVNTI)
{
- emitter->MOVNTI(32, MatR(RAX), R12);
- emitter->MOVNTI(32, M(code_buffer), R12);
- emitter->MOVNTI(64, MatR(RAX), R12);
- emitter->MOVNTI(64, M(code_buffer), R12);
-
- ExpectDisassembly("movnti dword ptr ds:[rax], r12d "
- "movnti dword ptr ds:[rip-12], r12d "
- "movnti qword ptr ds:[rax], r12 "
- "movnti qword ptr ds:[rip-24], r12");
+ emitter->MOVNTI(32, MatR(RAX), R12);
+ emitter->MOVNTI(32, M(code_buffer), R12);
+ emitter->MOVNTI(64, MatR(RAX), R12);
+ emitter->MOVNTI(64, M(code_buffer), R12);
+
+ ExpectDisassembly("movnti dword ptr ds:[rax], r12d "
+ "movnti dword ptr ds:[rip-12], r12d "
+ "movnti qword ptr ds:[rax], r12 "
+ "movnti qword ptr ds:[rip-24], r12");
}
// Grouped together since these 3 instructions do exactly the same thing.
TEST_F(x64EmitterTest, MOVNT_DQ_PS_PD)
{
- for (const auto& r : xmmnames)
- {
- emitter->MOVNTDQ(MatR(RAX), r.reg);
- emitter->MOVNTPS(MatR(RAX), r.reg);
- emitter->MOVNTPD(MatR(RAX), r.reg);
- ExpectDisassembly("movntdq dqword ptr ds:[rax], " + r.name + " "
- "movntps dqword ptr ds:[rax], " + r.name + " "
- "movntpd dqword ptr ds:[rax], " + r.name);
- }
+ for (const auto& r : xmmnames)
+ {
+ emitter->MOVNTDQ(MatR(RAX), r.reg);
+ emitter->MOVNTPS(MatR(RAX), r.reg);
+ emitter->MOVNTPD(MatR(RAX), r.reg);
+ ExpectDisassembly("movntdq dqword ptr ds:[rax], " + r.name + " "
+ "movntps dqword ptr ds:[rax], " +
+ r.name + " "
+ "movntpd dqword ptr ds:[rax], " +
+ r.name);
+ }
}
-#define MUL_DIV_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- } regsets[] = { \
- { 8, reg8names, "al" }, \
- { 8, reg8hnames, "al" }, \
- { 16, reg16names, "ax" }, \
- { 32, reg32names, "eax" }, \
- { 64, reg64names, "rax" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, R(r.reg)); \
- ExpectDisassembly(#Name " " + regset.out_name + ", " + r.name); \
- } \
- }
+#define MUL_DIV_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ } regsets[] = { \
+ {8, reg8names, "al"}, {8, reg8hnames, "al"}, {16, reg16names, "ax"}, \
+ {32, reg32names, "eax"}, {64, reg64names, "rax"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, R(r.reg)); \
+ ExpectDisassembly(#Name " " + regset.out_name + ", " + r.name); \
+ } \
+ }
MUL_DIV_TEST(MUL)
MUL_DIV_TEST(IMUL)
@@ -422,30 +414,26 @@ MUL_DIV_TEST(IDIV)
// TODO: More complex IMUL variants.
-#define SHIFT_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- } regsets[] = { \
- { 8, reg8names }, \
- { 8, reg8hnames }, \
- { 16, reg16names }, \
- { 32, reg32names }, \
- { 64, reg64names }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, R(r.reg), Imm8(1)); \
- emitter->Name(regset.bits, R(r.reg), Imm8(4)); \
- emitter->Name(regset.bits, R(r.reg), R(CL)); \
- ExpectDisassembly(#Name " " + r.name + ", 1 " \
- #Name " " + r.name + ", 0x04 " \
- #Name " " + r.name + ", cl"); \
- } \
- }
+#define SHIFT_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ } regsets[] = { \
+ {8, reg8names}, {8, reg8hnames}, {16, reg16names}, {32, reg32names}, {64, reg64names}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, R(r.reg), Imm8(1)); \
+ emitter->Name(regset.bits, R(r.reg), Imm8(4)); \
+ emitter->Name(regset.bits, R(r.reg), R(CL)); \
+ ExpectDisassembly(#Name " " + r.name + ", 1 " #Name " " + r.name + ", 0x04 " #Name " " + \
+ r.name + ", cl"); \
+ } \
+ }
SHIFT_TEST(ROL)
SHIFT_TEST(ROR)
@@ -455,32 +443,32 @@ SHIFT_TEST(SHL)
SHIFT_TEST(SHR)
SHIFT_TEST(SAR)
-#define BT_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 16, reg16names, "ax", "word" }, \
- { 32, reg32names, "eax", "dword" }, \
- { 64, reg64names, "rax", "qword" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, R(r.reg), R(RAX)); \
- emitter->Name(regset.bits, R(RAX), R(r.reg)); \
- emitter->Name(regset.bits, R(r.reg), Imm8(0x42)); \
- emitter->Name(regset.bits, MatR(R12), R(r.reg)); \
- ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + " " \
- #Name " " + regset.out_name + ", " + r.name + " " \
- #Name " " + r.name + ", 0x42 " \
- #Name " " + regset.size + " ptr ds:[r12], " + r.name); \
- } \
- }
+#define BT_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {16, reg16names, "ax", "word"}, \
+ {32, reg32names, "eax", "dword"}, \
+ {64, reg64names, "rax", "qword"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, R(r.reg), R(RAX)); \
+ emitter->Name(regset.bits, R(RAX), R(r.reg)); \
+ emitter->Name(regset.bits, R(r.reg), Imm8(0x42)); \
+ emitter->Name(regset.bits, MatR(R12), R(r.reg)); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + " " #Name " " + \
+ regset.out_name + ", " + r.name + " " #Name " " + r.name + \
+ ", 0x42 " #Name " " + regset.size + " ptr ds:[r12], " + r.name); \
+ } \
+ }
BT_TEST(BT)
BT_TEST(BTS)
@@ -489,67 +477,65 @@ BT_TEST(BTC)
// TODO: LEA tests
-#define ONE_OP_ARITH_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string size; \
- } regsets[] = { \
- { 8, reg8names, "byte" }, \
- { 8, reg8hnames, "byte" }, \
- { 16, reg16names, "word" }, \
- { 32, reg32names, "dword" }, \
- { 64, reg64names, "qword" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, R(r.reg)); \
- emitter->Name(regset.bits, MatR(RAX)); \
- emitter->Name(regset.bits, MatR(R12)); \
- ExpectDisassembly(#Name " " + r.name + " " \
- #Name " " + regset.size + " ptr ds:[rax] " \
- #Name " " + regset.size + " ptr ds:[r12]"); \
- } \
- }
+#define ONE_OP_ARITH_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string size; \
+ } regsets[] = { \
+ {8, reg8names, "byte"}, {8, reg8hnames, "byte"}, {16, reg16names, "word"}, \
+ {32, reg32names, "dword"}, {64, reg64names, "qword"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, R(r.reg)); \
+ emitter->Name(regset.bits, MatR(RAX)); \
+ emitter->Name(regset.bits, MatR(R12)); \
+ ExpectDisassembly(#Name " " + r.name + " " #Name " " + regset.size + \
+ " ptr ds:[rax] " #Name " " + regset.size + " ptr ds:[r12]"); \
+ } \
+ }
ONE_OP_ARITH_TEST(NOT)
ONE_OP_ARITH_TEST(NEG)
-#define TWO_OP_ARITH_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string size; \
- std::string rax_name; \
- Gen::OpArg imm; \
- std::string immname; \
- } regsets[] = { \
- { 8, reg8names, "byte", "al", Imm8(0xEF), "0xef" }, \
- { 8, reg8hnames, "byte", "al", Imm8(0xEF), "0xef" }, \
- { 16, reg16names, "word", "ax", Imm16(0xBEEF), "0xbeef" }, \
- { 32, reg32names, "dword", "eax", Imm32(0xDEADBEEF), "0xdeadbeef" }, \
- { 64, reg64names, "qword", "rax", Imm32(0xDEADBEEF), "0xffffffffdeadbeef" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, R(r.reg), R(RAX)); \
- emitter->Name(regset.bits, R(RAX), R(r.reg)); \
- emitter->Name(regset.bits, R(r.reg), MatR(RAX)); \
- emitter->Name(regset.bits, MatR(RAX), R(r.reg)); \
- emitter->Name(regset.bits, R(r.reg), regset.imm); \
- ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " \
- #Name " " + regset.rax_name + ", " + r.name + " " \
- #Name " " + r.name + ", " + regset.size + " ptr ds:[rax] " \
- #Name " " + regset.size + " ptr ds:[rax], " + r.name + " " \
- #Name " " + r.name + ", " + regset.immname ); \
- } \
- }
+#define TWO_OP_ARITH_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string size; \
+ std::string rax_name; \
+ Gen::OpArg imm; \
+ std::string immname; \
+ } regsets[] = { \
+ {8, reg8names, "byte", "al", Imm8(0xEF), "0xef"}, \
+ {8, reg8hnames, "byte", "al", Imm8(0xEF), "0xef"}, \
+ {16, reg16names, "word", "ax", Imm16(0xBEEF), "0xbeef"}, \
+ {32, reg32names, "dword", "eax", Imm32(0xDEADBEEF), "0xdeadbeef"}, \
+ {64, reg64names, "qword", "rax", Imm32(0xDEADBEEF), "0xffffffffdeadbeef"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, R(r.reg), R(RAX)); \
+ emitter->Name(regset.bits, R(RAX), R(r.reg)); \
+ emitter->Name(regset.bits, R(r.reg), MatR(RAX)); \
+ emitter->Name(regset.bits, MatR(RAX), R(r.reg)); \
+ emitter->Name(regset.bits, R(r.reg), regset.imm); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " #Name " " + \
+ regset.rax_name + ", " + r.name + " " #Name " " + r.name + ", " + \
+ regset.size + " ptr ds:[rax] " #Name " " + regset.size + \
+ " ptr ds:[rax], " + r.name + " " #Name " " + r.name + ", " + \
+ regset.immname); \
+ } \
+ }
TWO_OP_ARITH_TEST(ADD)
TWO_OP_ARITH_TEST(ADC)
@@ -567,117 +553,117 @@ TWO_OP_ARITH_TEST(MOV)
TEST_F(x64EmitterTest, BSWAP)
{
- struct {
- int bits;
- std::vector<NamedReg> regs;
- } regsets[] = {
- { 32, reg32names },
- { 64, reg64names },
- };
- for (const auto& regset : regsets)
- for (const auto& r : regset.regs)
- {
- emitter->BSWAP(regset.bits, r.reg);
- ExpectDisassembly("bswap " + r.name);
- }
+ struct
+ {
+ int bits;
+ std::vector<NamedReg> regs;
+ } regsets[] = {
+ {32, reg32names}, {64, reg64names},
+ };
+ for (const auto& regset : regsets)
+ for (const auto& r : regset.regs)
+ {
+ emitter->BSWAP(regset.bits, r.reg);
+ ExpectDisassembly("bswap " + r.name);
+ }
}
TEST_F(x64EmitterTest, MOVSX)
{
- emitter->MOVSX(16, 8, RAX, R(AH));
- emitter->MOVSX(32, 8, RAX, R(R12));
- emitter->MOVSX(32, 16, R12, R(RBX));
- emitter->MOVSX(64, 8, R12, R(RBX));
- emitter->MOVSX(64, 16, RAX, R(R12));
- emitter->MOVSX(64, 32, R12, R(RSP));
- ExpectDisassembly("movsx ax, ah "
- "movsx eax, r12b "
- "movsx r12d, bx "
- "movsx r12, bl "
- "movsx rax, r12w "
- "movsxd r12, esp");
+ emitter->MOVSX(16, 8, RAX, R(AH));
+ emitter->MOVSX(32, 8, RAX, R(R12));
+ emitter->MOVSX(32, 16, R12, R(RBX));
+ emitter->MOVSX(64, 8, R12, R(RBX));
+ emitter->MOVSX(64, 16, RAX, R(R12));
+ emitter->MOVSX(64, 32, R12, R(RSP));
+ ExpectDisassembly("movsx ax, ah "
+ "movsx eax, r12b "
+ "movsx r12d, bx "
+ "movsx r12, bl "
+ "movsx rax, r12w "
+ "movsxd r12, esp");
}
TEST_F(x64EmitterTest, MOVZX)
{
- emitter->MOVZX(16, 8, RAX, R(AH));
- emitter->MOVZX(32, 8, R12, R(RBP));
- emitter->MOVZX(64, 8, R12, R(RDI));
- emitter->MOVZX(32, 16, RAX, R(R12));
- emitter->MOVZX(64, 16, RCX, R(RSI));
- ExpectDisassembly("movzx ax, ah "
- "movzx r12d, bpl "
- "movzx r12d, dil " // Generates 32 bit movzx
- "movzx eax, r12w "
- "movzx ecx, si");
+ emitter->MOVZX(16, 8, RAX, R(AH));
+ emitter->MOVZX(32, 8, R12, R(RBP));
+ emitter->MOVZX(64, 8, R12, R(RDI));
+ emitter->MOVZX(32, 16, RAX, R(R12));
+ emitter->MOVZX(64, 16, RCX, R(RSI));
+ ExpectDisassembly("movzx ax, ah "
+ "movzx r12d, bpl "
+ "movzx r12d, dil " // Generates 32 bit movzx
+ "movzx eax, r12w "
+ "movzx ecx, si");
}
TEST_F(x64EmitterTest, MOVBE)
{
- emitter->MOVBE(16, RAX, MatR(R12));
- emitter->MOVBE(16, MatR(RAX), R12);
- emitter->MOVBE(32, RAX, MatR(R12));
- emitter->MOVBE(32, MatR(RAX), R12);
- emitter->MOVBE(64, RAX, MatR(R12));
- emitter->MOVBE(64, MatR(RAX), R12);
- ExpectDisassembly("movbe ax, word ptr ds:[r12] "
- "movbe word ptr ds:[rax], r12w "
- "movbe eax, dword ptr ds:[r12] "
- "movbe dword ptr ds:[rax], r12d "
- "movbe rax, qword ptr ds:[r12] "
- "movbe qword ptr ds:[rax], r12");
+ emitter->MOVBE(16, RAX, MatR(R12));
+ emitter->MOVBE(16, MatR(RAX), R12);
+ emitter->MOVBE(32, RAX, MatR(R12));
+ emitter->MOVBE(32, MatR(RAX), R12);
+ emitter->MOVBE(64, RAX, MatR(R12));
+ emitter->MOVBE(64, MatR(RAX), R12);
+ ExpectDisassembly("movbe ax, word ptr ds:[r12] "
+ "movbe word ptr ds:[rax], r12w "
+ "movbe eax, dword ptr ds:[r12] "
+ "movbe dword ptr ds:[rax], r12d "
+ "movbe rax, qword ptr ds:[r12] "
+ "movbe qword ptr ds:[rax], r12");
}
TEST_F(x64EmitterTest, STMXCSR)
{
- emitter->STMXCSR(MatR(R12));
- ExpectDisassembly("stmxcsr dword ptr ds:[r12]");
+ emitter->STMXCSR(MatR(R12));
+ ExpectDisassembly("stmxcsr dword ptr ds:[r12]");
}
TEST_F(x64EmitterTest, LDMXCSR)
{
- emitter->LDMXCSR(MatR(R12));
- ExpectDisassembly("ldmxcsr dword ptr ds:[r12]");
+ emitter->LDMXCSR(MatR(R12));
+ ExpectDisassembly("ldmxcsr dword ptr ds:[r12]");
}
TEST_F(x64EmitterTest, FLD_FST_FSTP)
{
- emitter->FLD(32, MatR(RBP));
- emitter->FLD(64, MatR(RBP));
- emitter->FLD(80, MatR(RBP));
-
- emitter->FST(32, MatR(RBP));
- emitter->FST(64, MatR(RBP));
- // No 80 bit version of FST
-
- emitter->FSTP(32, MatR(RBP));
- emitter->FSTP(64, MatR(RBP));
- emitter->FSTP(80, MatR(RBP));
-
- ExpectDisassembly("fld dword ptr ss:[rbp] "
- "fld qword ptr ss:[rbp] "
- "fld tbyte ptr ss:[rbp] "
- "fst dword ptr ss:[rbp] "
- "fst qword ptr ss:[rbp] "
- "fstp dword ptr ss:[rbp] "
- "fstp qword ptr ss:[rbp] "
- "fstp tbyte ptr ss:[rbp]");
+ emitter->FLD(32, MatR(RBP));
+ emitter->FLD(64, MatR(RBP));
+ emitter->FLD(80, MatR(RBP));
+
+ emitter->FST(32, MatR(RBP));
+ emitter->FST(64, MatR(RBP));
+ // No 80 bit version of FST
+
+ emitter->FSTP(32, MatR(RBP));
+ emitter->FSTP(64, MatR(RBP));
+ emitter->FSTP(80, MatR(RBP));
+
+ ExpectDisassembly("fld dword ptr ss:[rbp] "
+ "fld qword ptr ss:[rbp] "
+ "fld tbyte ptr ss:[rbp] "
+ "fst dword ptr ss:[rbp] "
+ "fst qword ptr ss:[rbp] "
+ "fstp dword ptr ss:[rbp] "
+ "fstp qword ptr ss:[rbp] "
+ "fstp tbyte ptr ss:[rbp]");
}
-#define TWO_OP_SSE_TEST(Name, MemBits) \
- TEST_F(x64EmitterTest, Name) \
- { \
- for (const auto& r1 : xmmnames) \
- { \
- for (const auto& r2 : xmmnames) \
- { \
- emitter->Name(r1.reg, R(r2.reg)); \
- ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \
- } \
- emitter->Name(r1.reg, MatR(R12)); \
- ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \
- } \
- }
+#define TWO_OP_SSE_TEST(Name, MemBits) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ for (const auto& r1 : xmmnames) \
+ { \
+ for (const auto& r2 : xmmnames) \
+ { \
+ emitter->Name(r1.reg, R(r2.reg)); \
+ ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \
+ } \
+ emitter->Name(r1.reg, MatR(R12)); \
+ ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \
+ } \
+ }
TWO_OP_SSE_TEST(ADDSS, "dword")
TWO_OP_SSE_TEST(SUBSS, "dword")
@@ -736,34 +722,34 @@ TWO_OP_SSE_TEST(COMISD, "qword")
TWO_OP_SSE_TEST(UCOMISD, "qword")
// register-only instructions
-#define TWO_OP_SSE_REG_TEST(Name, MemBits) \
- TEST_F(x64EmitterTest, Name) \
- { \
- for (const auto& r1 : xmmnames) \
- { \
- for (const auto& r2 : xmmnames) \
- { \
- emitter->Name(r1.reg, r2.reg); \
- ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \
- } \
- } \
- }
+#define TWO_OP_SSE_REG_TEST(Name, MemBits) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ for (const auto& r1 : xmmnames) \
+ { \
+ for (const auto& r2 : xmmnames) \
+ { \
+ emitter->Name(r1.reg, r2.reg); \
+ ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \
+ } \
+ } \
+ }
TWO_OP_SSE_REG_TEST(MOVHLPS, "qword")
TWO_OP_SSE_REG_TEST(MOVLHPS, "qword")
// "register + memory"-only instructions
-#define TWO_OP_SSE_MEM_TEST(Name, MemBits) \
- TEST_F(x64EmitterTest, Name) \
- { \
- for (const auto& r1 : xmmnames) \
- { \
- emitter->Name(r1.reg, MatR(R12)); \
- ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \
- emitter->Name(MatR(R12), r1.reg); \
- ExpectDisassembly(#Name " " MemBits " ptr ds:[r12], " + r1.name); \
- } \
- }
+#define TWO_OP_SSE_MEM_TEST(Name, MemBits) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ for (const auto& r1 : xmmnames) \
+ { \
+ emitter->Name(r1.reg, MatR(R12)); \
+ ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \
+ emitter->Name(MatR(R12), r1.reg); \
+ ExpectDisassembly(#Name " " MemBits " ptr ds:[r12], " + r1.name); \
+ } \
+ }
TWO_OP_SSE_MEM_TEST(MOVLPS, "qword")
TWO_OP_SSE_MEM_TEST(MOVHPS, "qword")
@@ -777,23 +763,23 @@ TWO_OP_SSE_MEM_TEST(MOVHPD, "qword")
TEST_F(x64EmitterTest, MASKMOVDQU)
{
- for (const auto& r1 : xmmnames)
- {
- for (const auto& r2 : xmmnames)
- {
- emitter->MASKMOVDQU(r1.reg, r2.reg);
- ExpectDisassembly("maskmovdqu " + r1.name + ", " + r2.name + ", dqword ptr ds:[rdi]");
- }
- }
+ for (const auto& r1 : xmmnames)
+ {
+ for (const auto& r2 : xmmnames)
+ {
+ emitter->MASKMOVDQU(r1.reg, r2.reg);
+ ExpectDisassembly("maskmovdqu " + r1.name + ", " + r2.name + ", dqword ptr ds:[rdi]");
+ }
+ }
}
TEST_F(x64EmitterTest, LDDQU)
{
- for (const auto& r : xmmnames)
- {
- emitter->LDDQU(r.reg, MatR(R12));
- ExpectDisassembly("lddqu " + r.name + ", dqword ptr ds:[r12]");
- }
+ for (const auto& r : xmmnames)
+ {
+ emitter->LDDQU(r.reg, MatR(R12));
+ ExpectDisassembly("lddqu " + r.name + ", dqword ptr ds:[r12]");
+ }
}
TWO_OP_SSE_TEST(CVTPS2PD, "dqword")
@@ -875,29 +861,30 @@ TWO_OP_SSE_TEST(PMOVZXDQ, "qword")
// TODO: AVX
// for VEX GPR instructions that take the form op reg, r/m, reg
-#define VEX_RMR_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 32, reg32names, "eax", "dword" }, \
- { 64, reg64names, "rax", "qword" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, r.reg, R(RAX), RAX); \
- emitter->Name(regset.bits, RAX, R(r.reg), RAX); \
- emitter->Name(regset.bits, RAX, MatR(R12), r.reg); \
- ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + " " \
- #Name " " + regset.out_name + ", " + r.name + ", " + regset.out_name + " " \
- #Name " " + regset.out_name + ", " + regset.size + " ptr ds:[r12], " + r.name + " "); \
- } \
- }
+#define VEX_RMR_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, r.reg, R(RAX), RAX); \
+ emitter->Name(regset.bits, RAX, R(r.reg), RAX); \
+ emitter->Name(regset.bits, RAX, MatR(R12), r.reg); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \
+ " " #Name " " + regset.out_name + ", " + r.name + ", " + \
+ regset.out_name + " " #Name " " + regset.out_name + ", " + regset.size + \
+ " ptr ds:[r12], " + r.name + " "); \
+ } \
+ }
VEX_RMR_TEST(SHRX)
VEX_RMR_TEST(SARX)
@@ -906,29 +893,30 @@ VEX_RMR_TEST(BEXTR)
VEX_RMR_TEST(BZHI)
// for VEX GPR instructions that take the form op reg, reg, r/m
-#define VEX_RRM_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 32, reg32names, "eax", "dword" }, \
- { 64, reg64names, "rax", "qword" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, r.reg, RAX, R(RAX)); \
- emitter->Name(regset.bits, RAX, RAX, R(r.reg)); \
- emitter->Name(regset.bits, RAX, r.reg, MatR(R12)); \
- ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", " + regset.out_name + " " \
- #Name " " + regset.out_name + ", " + regset.out_name + ", " + r.name + " " \
- #Name " " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12] "); \
- } \
- }
+#define VEX_RRM_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, r.reg, RAX, R(RAX)); \
+ emitter->Name(regset.bits, RAX, RAX, R(r.reg)); \
+ emitter->Name(regset.bits, RAX, r.reg, MatR(R12)); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \
+ " " #Name " " + regset.out_name + ", " + regset.out_name + ", " + \
+ r.name + " " #Name " " + regset.out_name + ", " + r.name + ", " + \
+ regset.size + " ptr ds:[r12] "); \
+ } \
+ }
VEX_RRM_TEST(PEXT)
VEX_RRM_TEST(PDEP)
@@ -936,105 +924,107 @@ VEX_RRM_TEST(MULX)
VEX_RRM_TEST(ANDN)
// for VEX GPR instructions that take the form op reg, r/m
-#define VEX_RM_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 32, reg32names, "eax", "dword" }, \
- { 64, reg64names, "rax", "qword" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, r.reg, R(RAX)); \
- emitter->Name(regset.bits, RAX, R(r.reg)); \
- emitter->Name(regset.bits, r.reg, MatR(R12)); \
- ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + " " \
- #Name " " + regset.out_name + ", " + r.name + " " \
- #Name " " + r.name + ", " + regset.size + " ptr ds:[r12] "); \
- } \
- }
+#define VEX_RM_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, r.reg, R(RAX)); \
+ emitter->Name(regset.bits, RAX, R(r.reg)); \
+ emitter->Name(regset.bits, r.reg, MatR(R12)); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + " " #Name " " + \
+ regset.out_name + ", " + r.name + " " #Name " " + r.name + ", " + \
+ regset.size + " ptr ds:[r12] "); \
+ } \
+ }
VEX_RM_TEST(BLSR)
VEX_RM_TEST(BLSMSK)
VEX_RM_TEST(BLSI)
// for VEX GPR instructions that take the form op reg, r/m, imm
-#define VEX_RMI_TEST(Name) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 32, reg32names, "eax", "dword" }, \
- { 64, reg64names, "rax", "qword" }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(regset.bits, r.reg, R(RAX), 4); \
- emitter->Name(regset.bits, RAX, R(r.reg), 4); \
- emitter->Name(regset.bits, r.reg, MatR(R12), 4); \
- ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", 0x04 " \
- #Name " " + regset.out_name + ", " + r.name + ", 0x04 " \
- #Name " " + r.name + ", " + regset.size + " ptr ds:[r12], 0x04 "); \
- } \
- }
+#define VEX_RMI_TEST(Name) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(regset.bits, r.reg, R(RAX), 4); \
+ emitter->Name(regset.bits, RAX, R(r.reg), 4); \
+ emitter->Name(regset.bits, r.reg, MatR(R12), 4); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", 0x04 " #Name " " + \
+ regset.out_name + ", " + r.name + ", 0x04 " #Name " " + r.name + ", " + \
+ regset.size + " ptr ds:[r12], 0x04 "); \
+ } \
+ }
VEX_RMI_TEST(RORX)
// for AVX instructions that take the form op reg, reg, r/m
-#define AVX_RRM_TEST(Name, sizename) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 64, xmmnames, "xmm0", sizename }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(r.reg, XMM0, R(XMM0)); \
- emitter->Name(XMM0, XMM0, R(r.reg)); \
- emitter->Name(XMM0, r.reg, MatR(R12)); \
- ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", " + regset.out_name + " " \
- #Name " " + regset.out_name + ", " + regset.out_name + ", " + r.name + " " \
- #Name " " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12] "); \
- } \
- }
-
-AVX_RRM_TEST(VANDPS, "dqword")
-AVX_RRM_TEST(VANDPD, "dqword")
+#define AVX_RRM_TEST(Name, sizename) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {64, xmmnames, "xmm0", sizename}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(r.reg, XMM0, R(XMM0)); \
+ emitter->Name(XMM0, XMM0, R(r.reg)); \
+ emitter->Name(XMM0, r.reg, MatR(R12)); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \
+ " " #Name " " + regset.out_name + ", " + regset.out_name + ", " + \
+ r.name + " " #Name " " + regset.out_name + ", " + r.name + ", " + \
+ regset.size + " ptr ds:[r12] "); \
+ } \
+ }
+
+AVX_RRM_TEST(VANDPS, "dqword")
+AVX_RRM_TEST(VANDPD, "dqword")
AVX_RRM_TEST(VANDNPS, "dqword")
AVX_RRM_TEST(VANDNPD, "dqword")
-AVX_RRM_TEST(VORPS, "dqword")
-AVX_RRM_TEST(VORPD, "dqword")
-AVX_RRM_TEST(VXORPS, "dqword")
-AVX_RRM_TEST(VXORPD, "dqword")
-AVX_RRM_TEST(VPAND, "dqword")
-AVX_RRM_TEST(VPANDN, "dqword")
-AVX_RRM_TEST(VPOR, "dqword")
-AVX_RRM_TEST(VPXOR, "dqword")
-
-#define FMA3_TEST(Name, P, packed) \
- AVX_RRM_TEST(Name ## 132 ## P ## S, packed ? "dqword" : "dword") \
- AVX_RRM_TEST(Name ## 213 ## P ## S, packed ? "dqword" : "dword") \
- AVX_RRM_TEST(Name ## 231 ## P ## S, packed ? "dqword" : "dword") \
- AVX_RRM_TEST(Name ## 132 ## P ## D, packed ? "dqword" : "qword") \
- AVX_RRM_TEST(Name ## 213 ## P ## D, packed ? "dqword" : "qword") \
- AVX_RRM_TEST(Name ## 231 ## P ## D, packed ? "dqword" : "qword")
+AVX_RRM_TEST(VORPS, "dqword")
+AVX_RRM_TEST(VORPD, "dqword")
+AVX_RRM_TEST(VXORPS, "dqword")
+AVX_RRM_TEST(VXORPD, "dqword")
+AVX_RRM_TEST(VPAND, "dqword")
+AVX_RRM_TEST(VPANDN, "dqword")
+AVX_RRM_TEST(VPOR, "dqword")
+AVX_RRM_TEST(VPXOR, "dqword")
+
+#define FMA3_TEST(Name, P, packed) \
+ AVX_RRM_TEST(Name##132##P##S, packed ? "dqword" : "dword") \
+ AVX_RRM_TEST(Name##213##P##S, packed ? "dqword" : "dword") \
+ AVX_RRM_TEST(Name##231##P##S, packed ? "dqword" : "dword") \
+ AVX_RRM_TEST(Name##132##P##D, packed ? "dqword" : "qword") \
+ AVX_RRM_TEST(Name##213##P##D, packed ? "dqword" : "qword") \
+ AVX_RRM_TEST(Name##231##P##D, packed ? "dqword" : "qword")
FMA3_TEST(VFMADD, P, true)
FMA3_TEST(VFMADD, S, false)
@@ -1048,32 +1038,35 @@ FMA3_TEST(VFMADDSUB, P, true)
FMA3_TEST(VFMSUBADD, P, true)
// for VEX instructions that take the form op reg, reg, r/m, reg OR reg, reg, reg, r/m
-#define VEX_RRMR_RRRM_TEST(Name, sizename) \
- TEST_F(x64EmitterTest, Name) \
- { \
- struct { \
- int bits; \
- std::vector<NamedReg> regs; \
- std::string out_name; \
- std::string size; \
- } regsets[] = { \
- { 64, xmmnames, "xmm0", sizename }, \
- }; \
- for (const auto& regset : regsets) \
- for (const auto& r : regset.regs) \
- { \
- emitter->Name(r.reg, XMM0, R(XMM0), r.reg); \
- emitter->Name(XMM0, XMM0, r.reg, MatR(R12)); \
- emitter->Name(XMM0, r.reg, MatR(R12), XMM0); \
- ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", " + regset.out_name + ", " + r.name + " " \
- #Name " " + regset.out_name + ", " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12] " \
- #Name " " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12], " + regset.out_name); \
- } \
- }
-
-#define FMA4_TEST(Name, P, packed) \
- VEX_RRMR_RRRM_TEST(Name ## P ## S, packed ? "dqword" : "dword") \
- VEX_RRMR_RRRM_TEST(Name ## P ## D, packed ? "dqword" : "qword")
+#define VEX_RRMR_RRRM_TEST(Name, sizename) \
+ TEST_F(x64EmitterTest, Name) \
+ { \
+ struct \
+ { \
+ int bits; \
+ std::vector<NamedReg> regs; \
+ std::string out_name; \
+ std::string size; \
+ } regsets[] = { \
+ {64, xmmnames, "xmm0", sizename}, \
+ }; \
+ for (const auto& regset : regsets) \
+ for (const auto& r : regset.regs) \
+ { \
+ emitter->Name(r.reg, XMM0, R(XMM0), r.reg); \
+ emitter->Name(XMM0, XMM0, r.reg, MatR(R12)); \
+ emitter->Name(XMM0, r.reg, MatR(R12), XMM0); \
+ ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \
+ ", " + r.name + " " #Name " " + regset.out_name + ", " + \
+ regset.out_name + ", " + r.name + ", " + regset.size + \
+ " ptr ds:[r12] " #Name " " + regset.out_name + ", " + r.name + ", " + \
+ regset.size + " ptr ds:[r12], " + regset.out_name); \
+ } \
+ }
+
+#define FMA4_TEST(Name, P, packed) \
+ VEX_RRMR_RRRM_TEST(Name##P##S, packed ? "dqword" : "dword") \
+ VEX_RRMR_RRRM_TEST(Name##P##D, packed ? "dqword" : "qword")
FMA4_TEST(VFMADD, P, true)
FMA4_TEST(VFMADD, S, false)