You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1201 lines
64 KiB
1201 lines
64 KiB
//===- subzero/unittest/AssemblerX8632/DataMov.cpp ------------------------===//
|
|
//
|
|
// The Subzero Code Generator
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "AssemblerX8632/TestUtil.h"
|
|
|
|
namespace Ice {
|
|
namespace X8632 {
|
|
namespace Test {
|
|
namespace {
|
|
|
|
TEST_F(AssemblerX8632Test, MovRegImm) {
|
|
constexpr uint32_t ExpectedEax = 0x000000FFul;
|
|
constexpr uint32_t ExpectedEbx = 0x0000FF00ul;
|
|
constexpr uint32_t ExpectedEcx = 0x00FF0000ul;
|
|
constexpr uint32_t ExpectedEdx = 0xFF000000ul;
|
|
constexpr uint32_t ExpectedEdi = 0x6AAA0006ul;
|
|
constexpr uint32_t ExpectedEsi = 0x6000AAA6ul;
|
|
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ExpectedEax));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(ExpectedEbx));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(ExpectedEcx));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(ExpectedEdx));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(ExpectedEdi));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(ExpectedEsi));
|
|
|
|
AssembledTest test = assemble();
|
|
test.run();
|
|
EXPECT_EQ(ExpectedEax, test.eax());
|
|
EXPECT_EQ(ExpectedEbx, test.ebx());
|
|
EXPECT_EQ(ExpectedEcx, test.ecx());
|
|
EXPECT_EQ(ExpectedEdx, test.edx());
|
|
EXPECT_EQ(ExpectedEdi, test.edi());
|
|
EXPECT_EQ(ExpectedEsi, test.esi());
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovMemImm) {
|
|
const uint32_t T0 = allocateDword();
|
|
constexpr uint32_t ExpectedT0 = 0x00111100ul;
|
|
const uint32_t T1 = allocateDword();
|
|
constexpr uint32_t ExpectedT1 = 0x00222200ul;
|
|
const uint32_t T2 = allocateDword();
|
|
constexpr uint32_t ExpectedT2 = 0x03333000ul;
|
|
const uint32_t T3 = allocateDword();
|
|
constexpr uint32_t ExpectedT3 = 0x00444400ul;
|
|
|
|
__ mov(IceType_i32, dwordAddress(T0), Immediate(ExpectedT0));
|
|
__ mov(IceType_i32, dwordAddress(T1), Immediate(ExpectedT1));
|
|
__ mov(IceType_i32, dwordAddress(T2), Immediate(ExpectedT2));
|
|
__ mov(IceType_i32, dwordAddress(T3), Immediate(ExpectedT3));
|
|
|
|
AssembledTest test = assemble();
|
|
test.run();
|
|
EXPECT_EQ(0ul, test.eax());
|
|
EXPECT_EQ(0ul, test.ebx());
|
|
EXPECT_EQ(0ul, test.ecx());
|
|
EXPECT_EQ(0ul, test.edx());
|
|
EXPECT_EQ(0ul, test.edi());
|
|
EXPECT_EQ(0ul, test.esi());
|
|
EXPECT_EQ(ExpectedT0, test.contentsOfDword(T0));
|
|
EXPECT_EQ(ExpectedT1, test.contentsOfDword(T1));
|
|
EXPECT_EQ(ExpectedT2, test.contentsOfDword(T2));
|
|
EXPECT_EQ(ExpectedT3, test.contentsOfDword(T3));
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovMemReg) {
|
|
const uint32_t T0 = allocateDword();
|
|
constexpr uint32_t ExpectedT0 = 0x00111100ul;
|
|
const uint32_t T1 = allocateDword();
|
|
constexpr uint32_t ExpectedT1 = 0x00222200ul;
|
|
const uint32_t T2 = allocateDword();
|
|
constexpr uint32_t ExpectedT2 = 0x00333300ul;
|
|
const uint32_t T3 = allocateDword();
|
|
constexpr uint32_t ExpectedT3 = 0x00444400ul;
|
|
const uint32_t T4 = allocateDword();
|
|
constexpr uint32_t ExpectedT4 = 0x00555500ul;
|
|
const uint32_t T5 = allocateDword();
|
|
constexpr uint32_t ExpectedT5 = 0x00666600ul;
|
|
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ExpectedT0));
|
|
__ mov(IceType_i32, dwordAddress(T0), GPRRegister::Encoded_Reg_eax);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(ExpectedT1));
|
|
__ mov(IceType_i32, dwordAddress(T1), GPRRegister::Encoded_Reg_ebx);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(ExpectedT2));
|
|
__ mov(IceType_i32, dwordAddress(T2), GPRRegister::Encoded_Reg_ecx);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(ExpectedT3));
|
|
__ mov(IceType_i32, dwordAddress(T3), GPRRegister::Encoded_Reg_edx);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(ExpectedT4));
|
|
__ mov(IceType_i32, dwordAddress(T4), GPRRegister::Encoded_Reg_edi);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(ExpectedT5));
|
|
__ mov(IceType_i32, dwordAddress(T5), GPRRegister::Encoded_Reg_esi);
|
|
|
|
AssembledTest test = assemble();
|
|
test.run();
|
|
EXPECT_EQ(ExpectedT0, test.contentsOfDword(T0));
|
|
EXPECT_EQ(ExpectedT1, test.contentsOfDword(T1));
|
|
EXPECT_EQ(ExpectedT2, test.contentsOfDword(T2));
|
|
EXPECT_EQ(ExpectedT3, test.contentsOfDword(T3));
|
|
EXPECT_EQ(ExpectedT4, test.contentsOfDword(T4));
|
|
EXPECT_EQ(ExpectedT5, test.contentsOfDword(T5));
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovRegReg) {
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x20));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx,
|
|
GPRRegister::Encoded_Reg_eax);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx,
|
|
GPRRegister::Encoded_Reg_ebx);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edx,
|
|
GPRRegister::Encoded_Reg_ecx);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edi,
|
|
GPRRegister::Encoded_Reg_edx);
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_esi,
|
|
GPRRegister::Encoded_Reg_edi);
|
|
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x55000000ul));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_eax,
|
|
GPRRegister::Encoded_Reg_esi);
|
|
|
|
AssembledTest test = assemble();
|
|
test.run();
|
|
EXPECT_EQ(0x55000000ul, test.eax());
|
|
EXPECT_EQ(0x20ul, test.ebx());
|
|
EXPECT_EQ(0x20ul, test.ecx());
|
|
EXPECT_EQ(0x20ul, test.edx());
|
|
EXPECT_EQ(0x20ul, test.edi());
|
|
EXPECT_EQ(0x55000000ul, test.esi());
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovRegMem) {
|
|
const uint32_t T0 = allocateDword();
|
|
constexpr uint32_t ExpectedT0 = 0x00111100ul;
|
|
const uint32_t T1 = allocateDword();
|
|
constexpr uint32_t ExpectedT1 = 0x00222200ul;
|
|
const uint32_t T2 = allocateDword();
|
|
constexpr uint32_t ExpectedT2 = 0x00333300ul;
|
|
const uint32_t T3 = allocateDword();
|
|
constexpr uint32_t ExpectedT3 = 0x00444400ul;
|
|
const uint32_t T4 = allocateDword();
|
|
constexpr uint32_t ExpectedT4 = 0x00555500ul;
|
|
const uint32_t T5 = allocateDword();
|
|
constexpr uint32_t ExpectedT5 = 0x00666600ul;
|
|
|
|
__ mov(IceType_i32, dwordAddress(T0), Immediate(ExpectedT0));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, dwordAddress(T0));
|
|
|
|
__ mov(IceType_i32, dwordAddress(T1), Immediate(ExpectedT1));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, dwordAddress(T1));
|
|
|
|
__ mov(IceType_i32, dwordAddress(T2), Immediate(ExpectedT2));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, dwordAddress(T2));
|
|
|
|
__ mov(IceType_i32, dwordAddress(T3), Immediate(ExpectedT3));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, dwordAddress(T3));
|
|
|
|
__ mov(IceType_i32, dwordAddress(T4), Immediate(ExpectedT4));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, dwordAddress(T4));
|
|
|
|
__ mov(IceType_i32, dwordAddress(T5), Immediate(ExpectedT5));
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, dwordAddress(T5));
|
|
|
|
AssembledTest test = assemble();
|
|
test.run();
|
|
EXPECT_EQ(ExpectedT0, test.eax());
|
|
EXPECT_EQ(ExpectedT1, test.ebx());
|
|
EXPECT_EQ(ExpectedT2, test.ecx());
|
|
EXPECT_EQ(ExpectedT3, test.edx());
|
|
EXPECT_EQ(ExpectedT4, test.edi());
|
|
EXPECT_EQ(ExpectedT5, test.esi());
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, Movzx) {
|
|
#define TestMovzx8bitWithRegDest(Src, Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
|
|
__ mov(IceType_i8, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
|
|
__ movzx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, \
|
|
GPRRegister::Encoded_Reg_##Src); \
|
|
AssembledTest test = assemble(); \
|
|
test.run(); \
|
|
ASSERT_EQ(Imm, test.Dst()) << "(" #Src ", " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovzx16bitWithRegDest(Src, Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
|
|
__ mov(IceType_i16, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
|
|
__ movzx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, \
|
|
GPRRegister::Encoded_Reg_##Src); \
|
|
AssembledTest test = assemble(); \
|
|
test.run(); \
|
|
ASSERT_EQ(Imm, test.Dst()) << "(" #Src ", " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovzx8bitWithAddrSrc(Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Imm; \
|
|
__ movzx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
AssembledTest test = assemble(); \
|
|
test.setDwordTo(T0, V0); \
|
|
test.run(); \
|
|
ASSERT_EQ(Imm, test.Dst()) << "(Addr, " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovzx16bitWithAddrSrc(Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Imm; \
|
|
__ movzx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
AssembledTest test = assemble(); \
|
|
test.setDwordTo(T0, V0); \
|
|
test.run(); \
|
|
ASSERT_EQ(Imm, test.Dst()) << "(Addr, " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovzx(Dst) \
|
|
do { \
|
|
TestMovzx8bitWithRegDest(eax, Dst, 0x81u); \
|
|
TestMovzx8bitWithRegDest(ebx, Dst, 0x82u); \
|
|
TestMovzx8bitWithRegDest(ecx, Dst, 0x83u); \
|
|
TestMovzx8bitWithRegDest(edx, Dst, 0x84u); \
|
|
/* esi is encoded as dh */ \
|
|
TestMovzx8bitWithRegDest(esi, Dst, 0x85u); \
|
|
/* edi is encoded as bh */ \
|
|
TestMovzx8bitWithRegDest(edi, Dst, 0x86u); \
|
|
/* ebp is encoded as ch */ \
|
|
TestMovzx8bitWithRegDest(ebp, Dst, 0x87u); \
|
|
/* esp is encoded as ah */ \
|
|
TestMovzx8bitWithRegDest(esp, Dst, 0x88u); \
|
|
TestMovzx8bitWithAddrSrc(Dst, 0x8Fu); \
|
|
\
|
|
TestMovzx16bitWithRegDest(eax, Dst, 0x8118u); \
|
|
TestMovzx16bitWithRegDest(ebx, Dst, 0x8228u); \
|
|
TestMovzx16bitWithRegDest(ecx, Dst, 0x8338u); \
|
|
TestMovzx16bitWithRegDest(edx, Dst, 0x8448u); \
|
|
TestMovzx16bitWithAddrSrc(Dst, 0x8FF8u); \
|
|
} while (0)
|
|
|
|
TestMovzx(eax);
|
|
TestMovzx(ebx);
|
|
TestMovzx(ecx);
|
|
TestMovzx(edx);
|
|
TestMovzx(esi);
|
|
TestMovzx(edi);
|
|
|
|
#undef TestMovzx
|
|
#undef TestMovzx16bitWithAddrDest
|
|
#undef TestMovzx8bitWithAddrDest
|
|
#undef TestMovzx16bitWithRegDest
|
|
#undef TestMovzx8bitWithRegDest
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, Movsx) {
|
|
#define TestMovsx8bitWithRegDest(Src, Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
|
|
__ mov(IceType_i8, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
|
|
__ movsx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, \
|
|
GPRRegister::Encoded_Reg_##Src); \
|
|
AssembledTest test = assemble(); \
|
|
test.run(); \
|
|
ASSERT_EQ((0xFFFFFF00 | (Imm)), test.Dst()) \
|
|
<< "(" #Src ", " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovsx16bitWithRegDest(Src, Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
|
|
__ mov(IceType_i16, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
|
|
__ movsx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, \
|
|
GPRRegister::Encoded_Reg_##Src); \
|
|
AssembledTest test = assemble(); \
|
|
test.run(); \
|
|
ASSERT_EQ((0xFFFF0000 | (Imm)), test.Dst()) \
|
|
<< "(" #Src ", " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovsx8bitWithAddrSrc(Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Imm; \
|
|
__ movsx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
AssembledTest test = assemble(); \
|
|
test.setDwordTo(T0, V0); \
|
|
test.run(); \
|
|
ASSERT_EQ((0xFFFFFF00 | (Imm)), test.Dst()) \
|
|
<< "(Addr, " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovsx16bitWithAddrSrc(Dst, Imm) \
|
|
do { \
|
|
static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Imm; \
|
|
__ movsx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
AssembledTest test = assemble(); \
|
|
test.setDwordTo(T0, V0); \
|
|
test.run(); \
|
|
ASSERT_EQ((0xFFFF0000 | (Imm)), test.Dst()) \
|
|
<< "(Addr, " #Dst ", " #Imm ")"; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovsx(Dst) \
|
|
do { \
|
|
TestMovsx8bitWithRegDest(eax, Dst, 0x81u); \
|
|
TestMovsx8bitWithRegDest(ebx, Dst, 0x82u); \
|
|
TestMovsx8bitWithRegDest(ecx, Dst, 0x83u); \
|
|
TestMovsx8bitWithRegDest(edx, Dst, 0x84u); \
|
|
/* esi is encoded as dh */ \
|
|
TestMovsx8bitWithRegDest(esi, Dst, 0x85u); \
|
|
/* edi is encoded as bh */ \
|
|
TestMovsx8bitWithRegDest(edi, Dst, 0x86u); \
|
|
/* ebp is encoded as ch */ \
|
|
TestMovsx8bitWithRegDest(ebp, Dst, 0x87u); \
|
|
/* esp is encoded as ah */ \
|
|
TestMovsx8bitWithRegDest(esp, Dst, 0x88u); \
|
|
TestMovsx8bitWithAddrSrc(Dst, 0x8Fu); \
|
|
\
|
|
TestMovsx16bitWithRegDest(eax, Dst, 0x8118u); \
|
|
TestMovsx16bitWithRegDest(ebx, Dst, 0x8228u); \
|
|
TestMovsx16bitWithRegDest(ecx, Dst, 0x8338u); \
|
|
TestMovsx16bitWithRegDest(edx, Dst, 0x8448u); \
|
|
TestMovsx16bitWithAddrSrc(Dst, 0x8FF8u); \
|
|
} while (0)
|
|
|
|
TestMovsx(eax);
|
|
TestMovsx(ebx);
|
|
TestMovsx(ecx);
|
|
TestMovsx(edx);
|
|
TestMovsx(esi);
|
|
TestMovsx(edi);
|
|
|
|
#undef TestMovsx
|
|
#undef TestMovsx16bitWithAddrDest
|
|
#undef TestMovsx8bitWithAddrDest
|
|
#undef TestMovsx16bitWithRegDest
|
|
#undef TestMovsx8bitWithRegDest
|
|
}
|
|
|
|
TEST_F(AssemblerX8632LowLevelTest, RepMovsb) {
|
|
__ rep_movsb();
|
|
|
|
static constexpr uint32_t ByteCount = 2;
|
|
static constexpr uint8_t Prefix = 0xF3;
|
|
static constexpr uint8_t Opcode = 0xA4;
|
|
|
|
ASSERT_EQ(ByteCount, codeBytesSize());
|
|
verifyBytes<ByteCount>(codeBytes(), Prefix, Opcode);
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovssXmmAddr) {
|
|
#define TestMovssXmmAddrFloatLength(FloatLength, Xmm, Value) \
|
|
do { \
|
|
static_assert((FloatLength) == 32 || (FloatLength) == 64, \
|
|
"Invalid fp length #FloatLength"); \
|
|
using Type = std::conditional<FloatLength == 32, float, double>::type; \
|
|
\
|
|
static constexpr char TestString[] = "(" #FloatLength ", " #Xmm ")"; \
|
|
static constexpr bool IsDouble = std::is_same<Type, double>::value; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const Type V0 = Value; \
|
|
\
|
|
__ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Xmm, \
|
|
dwordAddress(T0)); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
if (IsDouble) { \
|
|
test.setQwordTo(T0, static_cast<double>(V0)); \
|
|
} else { \
|
|
test.setDwordTo(T0, static_cast<float>(V0)); \
|
|
} \
|
|
test.run(); \
|
|
ASSERT_DOUBLE_EQ(Value, test.Xmm<Type>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovssXmmAddr(FloatLength) \
|
|
do { \
|
|
using Type = std::conditional<FloatLength == 32, float, double>::type; \
|
|
for (const Type Value : {0.0, -0.0, 1.0, -1.0, 3.14, 99999.9999}) { \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm0, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm1, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm2, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm3, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm4, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm5, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm6, Value); \
|
|
TestMovssXmmAddrFloatLength(FloatLength, xmm7, Value); \
|
|
} \
|
|
} while (0)
|
|
|
|
TestMovssXmmAddr(32);
|
|
TestMovssXmmAddr(64);
|
|
|
|
#undef TestMovssXmmAddr
|
|
#undef TestMovssXmmAddrType
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovssAddrXmm) {
|
|
#define TestMovssAddrXmmFloatLength(FloatLength, Xmm, Value) \
|
|
do { \
|
|
static_assert((FloatLength) == 32 || (FloatLength) == 64, \
|
|
"Invalid fp length #FloatLength"); \
|
|
using Type = std::conditional<FloatLength == 32, float, double>::type; \
|
|
\
|
|
static constexpr char TestString[] = "(" #FloatLength ", " #Xmm ")"; \
|
|
static constexpr bool IsDouble = std::is_same<Type, double>::value; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const Type V0 = Value; \
|
|
const uint32_t T1 = allocateQword(); \
|
|
static_assert(std::numeric_limits<Type>::has_quiet_NaN, \
|
|
"f" #FloatLength " does not have quiet nan."); \
|
|
const Type V1 = std::numeric_limits<Type>::quiet_NaN(); \
|
|
\
|
|
__ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Xmm, \
|
|
dwordAddress(T0)); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
if (IsDouble) { \
|
|
test.setQwordTo(T0, static_cast<double>(V0)); \
|
|
test.setQwordTo(T1, static_cast<double>(V1)); \
|
|
} else { \
|
|
test.setDwordTo(T0, static_cast<float>(V0)); \
|
|
test.setDwordTo(T1, static_cast<float>(V1)); \
|
|
} \
|
|
test.run(); \
|
|
ASSERT_DOUBLE_EQ(Value, test.Xmm<Type>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovssAddrXmm(FloatLength) \
|
|
do { \
|
|
using Type = std::conditional<FloatLength == 32, float, double>::type; \
|
|
for (const Type Value : {0.0, -0.0, 1.0, -1.0, 3.14, 99999.9999}) { \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm0, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm1, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm2, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm3, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm4, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm5, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm6, Value); \
|
|
TestMovssAddrXmmFloatLength(FloatLength, xmm7, Value); \
|
|
} \
|
|
} while (0)
|
|
|
|
TestMovssAddrXmm(32);
|
|
TestMovssAddrXmm(64);
|
|
|
|
#undef TestMovssAddrXmm
|
|
#undef TestMovssAddrXmmType
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovssXmmXmm) {
|
|
#define TestMovssXmmXmmFloatLength(FloatLength, Src, Dst, Value) \
|
|
do { \
|
|
static_assert((FloatLength) == 32 || (FloatLength) == 64, \
|
|
"Invalid fp length #FloatLength"); \
|
|
using Type = std::conditional<FloatLength == 32, float, double>::type; \
|
|
\
|
|
static constexpr char TestString[] = \
|
|
"(" #FloatLength ", " #Src ", " #Dst ")"; \
|
|
static constexpr bool IsDouble = std::is_same<Type, double>::value; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const Type V0 = Value; \
|
|
const uint32_t T1 = allocateQword(); \
|
|
static_assert(std::numeric_limits<Type>::has_quiet_NaN, \
|
|
"f" #FloatLength " does not have quiet nan."); \
|
|
const Type V1 = std::numeric_limits<Type>::quiet_NaN(); \
|
|
\
|
|
__ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Src, \
|
|
dwordAddress(T0)); \
|
|
__ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Dst, \
|
|
dwordAddress(T1)); \
|
|
__ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Dst, \
|
|
XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
if (IsDouble) { \
|
|
test.setQwordTo(T0, static_cast<double>(V0)); \
|
|
test.setQwordTo(T1, static_cast<double>(V1)); \
|
|
} else { \
|
|
test.setDwordTo(T0, static_cast<float>(V0)); \
|
|
test.setDwordTo(T1, static_cast<float>(V1)); \
|
|
} \
|
|
test.run(); \
|
|
ASSERT_DOUBLE_EQ(Value, test.Dst<Type>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovssXmmXmm(FloatLength) \
|
|
do { \
|
|
using Type = std::conditional<FloatLength == 32, float, double>::type; \
|
|
for (const Type Value : {0.0, -0.0, 1.0, -1.0, 3.14, 99999.9999}) { \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm0, xmm1, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm1, xmm2, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm2, xmm3, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm3, xmm4, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm4, xmm5, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm5, xmm6, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm6, xmm7, Value); \
|
|
TestMovssXmmXmmFloatLength(FloatLength, xmm7, xmm0, Value); \
|
|
} \
|
|
} while (0)
|
|
|
|
TestMovssXmmXmm(32);
|
|
TestMovssXmmXmm(64);
|
|
|
|
#undef TestMovssXmmXmm
|
|
#undef TestMovssXmmXmmType
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovdToXmm) {
|
|
#define TestMovdXmmReg(Src, Dst, Value) \
|
|
do { \
|
|
assert(((Value)&0xFFFFFFFF) == (Value)); \
|
|
static constexpr char TestString[] = "(" #Src ", " #Dst ")"; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const uint64_t V0 = 0xFFFFFFFF00000000ull; \
|
|
\
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src, Immediate(Value)); \
|
|
__ movss(IceType_f64, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
__ movd(IceType_i32, XmmRegister::Encoded_Reg_##Dst, \
|
|
GPRRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setQwordTo(T0, V0); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.Dst<uint64_t>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovdXmmAddr(Dst, Value) \
|
|
do { \
|
|
assert(((Value)&0xFFFFFFFF) == (Value)); \
|
|
static constexpr char TestString[] = "(" #Dst ", Addr)"; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const uint32_t V0 = Value; \
|
|
const uint32_t T1 = allocateQword(); \
|
|
const uint64_t V1 = 0xFFFFFFFF00000000ull; \
|
|
\
|
|
__ movss(IceType_f64, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
|
|
__ movd(IceType_i32, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setDwordTo(T0, V0); \
|
|
test.setQwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.Dst<uint64_t>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovd(Dst) \
|
|
do { \
|
|
for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) { \
|
|
TestMovdXmmReg(eax, Dst, Value); \
|
|
TestMovdXmmReg(ebx, Dst, Value); \
|
|
TestMovdXmmReg(ecx, Dst, Value); \
|
|
TestMovdXmmReg(edx, Dst, Value); \
|
|
TestMovdXmmReg(esi, Dst, Value); \
|
|
TestMovdXmmReg(edi, Dst, Value); \
|
|
TestMovdXmmAddr(Dst, Value); \
|
|
} \
|
|
} while (0)
|
|
|
|
TestMovd(xmm0);
|
|
TestMovd(xmm1);
|
|
TestMovd(xmm2);
|
|
TestMovd(xmm3);
|
|
TestMovd(xmm4);
|
|
TestMovd(xmm5);
|
|
TestMovd(xmm6);
|
|
TestMovd(xmm7);
|
|
|
|
#undef TestMovdXmmAddr
|
|
#undef TestMovdXmmReg
|
|
#undef TestMovd
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovdFromXmm) {
|
|
#define TestMovdRegXmm(Src, Dst, Value) \
|
|
do { \
|
|
assert(((Value)&0xFFFFFFFF) == (Value)); \
|
|
static constexpr char TestString[] = "(" #Src ", " #Dst ")"; \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Value; \
|
|
\
|
|
__ movss(IceType_f64, XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movd(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
|
|
XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setDwordTo(T0, V0); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.contentsOfDword(T0)) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovdAddrXmm(Src, Value) \
|
|
do { \
|
|
assert(((Value)&0xFFFFFFFF) == (Value)); \
|
|
static constexpr char TestString[] = "(" #Src ", Addr)"; \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Value; \
|
|
const uint32_t T1 = allocateDword(); \
|
|
const uint32_t V1 = ~(Value); \
|
|
\
|
|
__ movss(IceType_f64, XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movd(IceType_i32, dwordAddress(T1), XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setDwordTo(T0, V0); \
|
|
test.setDwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.contentsOfDword(T1)) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovd(Src) \
|
|
do { \
|
|
for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) { \
|
|
TestMovdRegXmm(Src, eax, Value); \
|
|
TestMovdRegXmm(Src, ebx, Value); \
|
|
TestMovdRegXmm(Src, ecx, Value); \
|
|
TestMovdRegXmm(Src, edx, Value); \
|
|
TestMovdRegXmm(Src, esi, Value); \
|
|
TestMovdRegXmm(Src, edi, Value); \
|
|
TestMovdAddrXmm(Src, Value); \
|
|
} \
|
|
} while (0)
|
|
|
|
TestMovd(xmm0);
|
|
TestMovd(xmm1);
|
|
TestMovd(xmm2);
|
|
TestMovd(xmm3);
|
|
TestMovd(xmm4);
|
|
TestMovd(xmm5);
|
|
TestMovd(xmm6);
|
|
TestMovd(xmm7);
|
|
|
|
#undef TestMovdAddrXmm
|
|
#undef TestMovdRegXmm
|
|
#undef TestMovd
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovqXmmAddr) {
|
|
#define TestMovd(Dst, Value) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ", Addr)"; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const uint64_t V0 = Value; \
|
|
const uint32_t T1 = allocateQword(); \
|
|
const uint64_t V1 = ~(Value); \
|
|
\
|
|
__ movss(IceType_f64, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
|
|
__ movq(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setQwordTo(T0, V0); \
|
|
test.setQwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.Dst<uint64_t>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) {
|
|
TestMovd(xmm0, Value);
|
|
TestMovd(xmm1, Value);
|
|
TestMovd(xmm2, Value);
|
|
TestMovd(xmm3, Value);
|
|
TestMovd(xmm4, Value);
|
|
TestMovd(xmm5, Value);
|
|
TestMovd(xmm6, Value);
|
|
TestMovd(xmm7, Value);
|
|
}
|
|
|
|
#undef TestMovd
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovqAddrXmm) {
|
|
#define TestMovd(Dst, Value) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ", Addr)"; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const uint64_t V0 = Value; \
|
|
const uint32_t T1 = allocateQword(); \
|
|
const uint64_t V1 = ~(Value); \
|
|
\
|
|
__ movq(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
__ movq(dwordAddress(T1), XmmRegister::Encoded_Reg_##Dst); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setQwordTo(T0, V0); \
|
|
test.setQwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.Dst<uint64_t>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) {
|
|
TestMovd(xmm0, Value);
|
|
TestMovd(xmm1, Value);
|
|
TestMovd(xmm2, Value);
|
|
TestMovd(xmm3, Value);
|
|
TestMovd(xmm4, Value);
|
|
TestMovd(xmm5, Value);
|
|
TestMovd(xmm6, Value);
|
|
TestMovd(xmm7, Value);
|
|
}
|
|
|
|
#undef TestMovd
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovqXmmXmm) {
|
|
#define TestMovd(Src, Dst, Value) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Src ", " #Dst ")"; \
|
|
const uint32_t T0 = allocateQword(); \
|
|
const uint64_t V0 = Value; \
|
|
const uint32_t T1 = allocateQword(); \
|
|
const uint64_t V1 = ~(Value); \
|
|
\
|
|
__ movq(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movq(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
|
|
__ movq(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
\
|
|
test.setQwordTo(T0, V0); \
|
|
test.setQwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Value, test.Dst<uint64_t>()) \
|
|
<< TestString << " value is " << Value; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) {
|
|
TestMovd(xmm0, xmm1, Value);
|
|
TestMovd(xmm1, xmm2, Value);
|
|
TestMovd(xmm2, xmm3, Value);
|
|
TestMovd(xmm3, xmm4, Value);
|
|
TestMovd(xmm4, xmm5, Value);
|
|
TestMovd(xmm5, xmm6, Value);
|
|
TestMovd(xmm6, xmm7, Value);
|
|
TestMovd(xmm7, xmm0, Value);
|
|
}
|
|
|
|
#undef TestMovd
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovupsXmmAddr) {
|
|
#define TestMovups(Dst) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
|
|
std::numeric_limits<float>::infinity()); \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(V0, test.Dst<Dqword>()) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
TestMovups(xmm0);
|
|
TestMovups(xmm1);
|
|
TestMovups(xmm2);
|
|
TestMovups(xmm3);
|
|
TestMovups(xmm4);
|
|
TestMovups(xmm5);
|
|
TestMovups(xmm6);
|
|
TestMovups(xmm7);
|
|
|
|
#undef TestMovups
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovupsAddrXmm) {
|
|
#define TestMovups(Src) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Src ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
|
|
std::numeric_limits<float>::infinity()); \
|
|
const uint32_t T1 = allocateDqword(); \
|
|
const Dqword V1(0.0, 0.0, 0.0, 0.0); \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movups(dwordAddress(T1), XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.setDqwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(V0, test.contentsOfDqword(T1)) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
TestMovups(xmm0);
|
|
TestMovups(xmm1);
|
|
TestMovups(xmm2);
|
|
TestMovups(xmm3);
|
|
TestMovups(xmm4);
|
|
TestMovups(xmm5);
|
|
TestMovups(xmm6);
|
|
TestMovups(xmm7);
|
|
|
|
#undef TestMovups
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovupsXmmXmm) {
|
|
#define TestMovups(Dst, Src) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ", " #Src ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
|
|
std::numeric_limits<float>::infinity()); \
|
|
const uint32_t T1 = allocateDqword(); \
|
|
const Dqword V1(0.0, 0.0, 0.0, 0.0); \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
|
|
__ movups(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.setDqwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(V0, test.Dst<Dqword>()) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
TestMovups(xmm0, xmm1);
|
|
TestMovups(xmm1, xmm2);
|
|
TestMovups(xmm2, xmm3);
|
|
TestMovups(xmm3, xmm4);
|
|
TestMovups(xmm4, xmm5);
|
|
TestMovups(xmm5, xmm6);
|
|
TestMovups(xmm6, xmm7);
|
|
TestMovups(xmm7, xmm0);
|
|
|
|
#undef TestMovups
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, MovapsXmmXmm) {
|
|
#define TestMovaps(Dst, Src) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ", " #Src ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
|
|
std::numeric_limits<float>::infinity()); \
|
|
const uint32_t T1 = allocateDqword(); \
|
|
const Dqword V1(0.0, 0.0, 0.0, 0.0); \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
|
|
__ movaps(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.setDqwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(V0, test.Dst<Dqword>()) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
TestMovaps(xmm0, xmm1);
|
|
TestMovaps(xmm1, xmm2);
|
|
TestMovaps(xmm2, xmm3);
|
|
TestMovaps(xmm3, xmm4);
|
|
TestMovaps(xmm4, xmm5);
|
|
TestMovaps(xmm5, xmm6);
|
|
TestMovaps(xmm6, xmm7);
|
|
TestMovaps(xmm7, xmm0);
|
|
|
|
#undef TestMovaps
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, Movhlps_Movlhps) {
|
|
#define TestImplSingle(Dst, Src, Inst, Expect) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ", " #Src ", " #Inst ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0(uint64_t(0xAAAAAAAABBBBBBBBull), \
|
|
uint64_t(0xCCCCCCCCDDDDDDDDull)); \
|
|
const uint32_t T1 = allocateDqword(); \
|
|
const Dqword V1(uint64_t(0xEEEEEEEEFFFFFFFFull), \
|
|
uint64_t(0x9999999988888888ull)); \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
|
|
__ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
|
|
__ Inst(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.setDqwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Dqword Expect, test.Dst<Dqword>()) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestImpl(Dst, Src) \
|
|
do { \
|
|
TestImplSingle( \
|
|
Dst, Src, movhlps, \
|
|
(uint64_t(0x9999999988888888ull), uint64_t(0xCCCCCCCCDDDDDDDDull))); \
|
|
TestImplSingle( \
|
|
Dst, Src, movlhps, \
|
|
(uint64_t(0xAAAAAAAABBBBBBBBull), uint64_t(0xEEEEEEEEFFFFFFFFull))); \
|
|
} while (0)
|
|
|
|
TestImpl(xmm0, xmm1);
|
|
TestImpl(xmm1, xmm2);
|
|
TestImpl(xmm2, xmm3);
|
|
TestImpl(xmm3, xmm4);
|
|
TestImpl(xmm4, xmm5);
|
|
TestImpl(xmm5, xmm6);
|
|
TestImpl(xmm6, xmm7);
|
|
TestImpl(xmm7, xmm0);
|
|
|
|
#undef TestImpl
|
|
#undef TestImplSingle
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, Movmsk) {
|
|
#define TestMovmskGPRXmm(GPR, Src, Value1, Expected, Inst) \
|
|
do { \
|
|
static constexpr char TestString[] = \
|
|
"(" #GPR ", " #Src ", " #Value1 ", " #Expected ", " #Inst ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0 Value1; \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ Inst(IceType_v4f32, GPRRegister::Encoded_Reg_##GPR, \
|
|
XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.run(); \
|
|
\
|
|
ASSERT_EQ(Expected, test.GPR()) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestMovmsk(GPR, Src) \
|
|
do { \
|
|
TestMovmskGPRXmm(GPR, Src, (-1.0, 1.0, -1.0, 1.0), 0x05ul, movmsk); \
|
|
} while (0)
|
|
|
|
TestMovmsk(eax, xmm0);
|
|
TestMovmsk(ebx, xmm1);
|
|
TestMovmsk(ecx, xmm2);
|
|
TestMovmsk(edx, xmm3);
|
|
TestMovmsk(esi, xmm4);
|
|
TestMovmsk(edi, xmm5);
|
|
TestMovmsk(eax, xmm6);
|
|
TestMovmsk(ebx, xmm7);
|
|
|
|
#undef TestMovmskGPRXmm
|
|
#undef TestMovmsk
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, Pmovsxdq) {
|
|
#define TestPmovsxdqXmmXmm(Dst, Src, Value1) \
|
|
do { \
|
|
static constexpr char TestString[] = "(" #Dst ", " #Src ", " #Value1 ")"; \
|
|
const uint32_t T0 = allocateDqword(); \
|
|
const Dqword V0 Value1; \
|
|
const uint32_t T1 = allocateDqword(); \
|
|
const Dqword V1(uint64_t(0), uint64_t(0)); \
|
|
\
|
|
__ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
|
|
__ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
|
|
__ pmovsxdq(XmmRegister::Encoded_Reg_##Dst, \
|
|
XmmRegister::Encoded_Reg_##Src); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDqwordTo(T0, V0); \
|
|
test.setDqwordTo(T1, V1); \
|
|
test.run(); \
|
|
\
|
|
const Dqword Expected(uint64_t(V0.I32[0]), uint64_t(V0.I32[1])); \
|
|
ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
|
|
reset(); \
|
|
} while (0)
|
|
|
|
#define TestPmovsxdq(Dst, Src) \
|
|
do { \
|
|
TestPmovsxdqXmmXmm( \
|
|
Dst, Src, \
|
|
(uint64_t(0x700000007FFFFFFFull), uint64_t(0xAAAAAAAAEEEEEEEEull))); \
|
|
TestPmovsxdqXmmXmm( \
|
|
Dst, Src, \
|
|
(uint64_t(0x800000007FFFFFFFull), uint64_t(0xAAAAAAAAEEEEEEEEull))); \
|
|
TestPmovsxdqXmmXmm( \
|
|
Dst, Src, \
|
|
(uint64_t(0x70000000FFFFFFFFull), uint64_t(0xAAAAAAAAEEEEEEEEull))); \
|
|
TestPmovsxdqXmmXmm( \
|
|
Dst, Src, \
|
|
(uint64_t(0x80000000FFFFFFFFull), uint64_t(0xAAAAAAAAEEEEEEEEull))); \
|
|
} while (0)
|
|
|
|
TestPmovsxdq(xmm0, xmm1);
|
|
TestPmovsxdq(xmm1, xmm2);
|
|
TestPmovsxdq(xmm2, xmm3);
|
|
TestPmovsxdq(xmm3, xmm4);
|
|
TestPmovsxdq(xmm4, xmm5);
|
|
TestPmovsxdq(xmm5, xmm6);
|
|
TestPmovsxdq(xmm6, xmm7);
|
|
TestPmovsxdq(xmm7, xmm0);
|
|
|
|
#undef TestPmovsxdq
|
|
#undef TestPmovsxdqXmmXmm
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, CmovRegReg) {
|
|
#define TestCmovRegReg(C, Src0, Value0, Src1, Value1, Dest, IsTrue) \
|
|
do { \
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(Value0)); \
|
|
__ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
|
|
GPRRegister::Encoded_Reg_##Src1); \
|
|
__ cmov(IceType_i32, Cond::Br_##C, GPRRegister::Encoded_Reg_##Dest, \
|
|
GPRRegister::Encoded_Reg_##Src1); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.run(); \
|
|
ASSERT_EQ((IsTrue) ? (Value1) : (Value0), test.Dest()) \
|
|
<< "(" #C ", " #Src0 ", " #Value0 ", " #Src1 ", " #Value1 ", " #Dest \
|
|
", " #IsTrue ")"; \
|
|
\
|
|
reset(); \
|
|
} while (0)
|
|
|
|
TestCmovRegReg(o, eax, 0x80000000u, ebx, 0x1u, ecx, 1u);
|
|
TestCmovRegReg(o, eax, 0x1u, ebx, 0x10000000u, ecx, 0u);
|
|
|
|
TestCmovRegReg(no, ebx, 0x1u, ecx, 0x10000000u, edx, 1u);
|
|
TestCmovRegReg(no, ebx, 0x80000000u, ecx, 0x1u, edx, 0u);
|
|
|
|
TestCmovRegReg(b, ecx, 0x1, edx, 0x80000000u, eax, 1u);
|
|
TestCmovRegReg(b, ecx, 0x80000000u, edx, 0x1u, eax, 0u);
|
|
|
|
TestCmovRegReg(ae, edx, 0x80000000u, edi, 0x1u, ebx, 1u);
|
|
TestCmovRegReg(ae, edx, 0x1u, edi, 0x80000000u, ebx, 0u);
|
|
|
|
TestCmovRegReg(e, edi, 0x1u, esi, 0x1u, ecx, 1u);
|
|
TestCmovRegReg(e, edi, 0x1u, esi, 0x11111u, ecx, 0u);
|
|
|
|
TestCmovRegReg(ne, esi, 0x80000000u, eax, 0x1u, edx, 1u);
|
|
TestCmovRegReg(ne, esi, 0x1u, eax, 0x1u, edx, 0u);
|
|
|
|
TestCmovRegReg(be, eax, 0x1u, ebx, 0x80000000u, eax, 1u);
|
|
TestCmovRegReg(be, eax, 0x80000000u, ebx, 0x1u, eax, 0u);
|
|
|
|
TestCmovRegReg(a, ebx, 0x80000000u, ecx, 0x1u, ebx, 1u);
|
|
TestCmovRegReg(a, ebx, 0x1u, ecx, 0x80000000u, ebx, 0u);
|
|
|
|
TestCmovRegReg(s, ecx, 0x1u, edx, 0x80000000u, ecx, 1u);
|
|
TestCmovRegReg(s, ecx, 0x80000000u, edx, 0x1u, ecx, 0u);
|
|
|
|
TestCmovRegReg(ns, edx, 0x80000000u, edi, 0x1u, ecx, 1u);
|
|
TestCmovRegReg(ns, edx, 0x1u, edi, 0x80000000u, ecx, 0u);
|
|
|
|
TestCmovRegReg(p, edi, 0x80000000u, esi, 0x1u, edx, 1u);
|
|
TestCmovRegReg(p, edi, 0x1u, esi, 0x80000000u, edx, 0u);
|
|
|
|
TestCmovRegReg(np, esi, 0x1u, edi, 0x80000000u, eax, 1u);
|
|
TestCmovRegReg(np, esi, 0x80000000u, edi, 0x1u, eax, 0u);
|
|
|
|
TestCmovRegReg(l, edi, 0x80000000u, eax, 0x1u, ebx, 1u);
|
|
TestCmovRegReg(l, edi, 0x1u, eax, 0x80000000u, ebx, 0u);
|
|
|
|
TestCmovRegReg(ge, eax, 0x1u, ebx, 0x80000000u, ecx, 1u);
|
|
TestCmovRegReg(ge, eax, 0x80000000u, ebx, 0x1u, ecx, 0u);
|
|
|
|
TestCmovRegReg(le, ebx, 0x80000000u, ecx, 0x1u, edx, 1u);
|
|
TestCmovRegReg(le, ebx, 0x1u, ecx, 0x80000000u, edx, 0u);
|
|
|
|
#undef TestCmovRegReg
|
|
}
|
|
|
|
TEST_F(AssemblerX8632Test, CmovRegAddr) {
|
|
#define TestCmovRegAddr(C, Src0, Value0, Value1, Dest, IsTrue) \
|
|
do { \
|
|
const uint32_t T0 = allocateDword(); \
|
|
const uint32_t V0 = Value1; \
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
|
|
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(Value0)); \
|
|
__ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, dwordAddress(T0)); \
|
|
__ cmov(IceType_i32, Cond::Br_##C, GPRRegister::Encoded_Reg_##Dest, \
|
|
dwordAddress(T0)); \
|
|
\
|
|
AssembledTest test = assemble(); \
|
|
test.setDwordTo(T0, V0); \
|
|
test.run(); \
|
|
ASSERT_EQ((IsTrue) ? (Value1) : (Value0), test.Dest()) \
|
|
<< "(" #C ", " #Src0 ", " #Value0 ", " #Value1 ", " #Dest ", " #IsTrue \
|
|
")"; \
|
|
\
|
|
reset(); \
|
|
} while (0)
|
|
|
|
TestCmovRegAddr(o, eax, 0x80000000u, 0x1u, ecx, 1u);
|
|
TestCmovRegAddr(o, eax, 0x1u, 0x10000000u, ecx, 0u);
|
|
|
|
TestCmovRegAddr(no, ebx, 0x1u, 0x10000000u, edx, 1u);
|
|
TestCmovRegAddr(no, ebx, 0x80000000u, 0x1u, edx, 0u);
|
|
|
|
TestCmovRegAddr(b, ecx, 0x1, 0x80000000u, eax, 1u);
|
|
TestCmovRegAddr(b, ecx, 0x80000000u, 0x1u, eax, 0u);
|
|
|
|
TestCmovRegAddr(ae, edx, 0x80000000u, 0x1u, ebx, 1u);
|
|
TestCmovRegAddr(ae, edx, 0x1u, 0x80000000u, ebx, 0u);
|
|
|
|
TestCmovRegAddr(e, edi, 0x1u, 0x1u, ecx, 1u);
|
|
TestCmovRegAddr(e, edi, 0x1u, 0x11111u, ecx, 0u);
|
|
|
|
TestCmovRegAddr(ne, esi, 0x80000000u, 0x1u, edx, 1u);
|
|
TestCmovRegAddr(ne, esi, 0x1u, 0x1u, edx, 0u);
|
|
|
|
TestCmovRegAddr(be, eax, 0x1u, 0x80000000u, eax, 1u);
|
|
TestCmovRegAddr(be, eax, 0x80000000u, 0x1u, eax, 0u);
|
|
|
|
TestCmovRegAddr(a, ebx, 0x80000000u, 0x1u, ebx, 1u);
|
|
TestCmovRegAddr(a, ebx, 0x1u, 0x80000000u, ebx, 0u);
|
|
|
|
TestCmovRegAddr(s, ecx, 0x1u, 0x80000000u, ecx, 1u);
|
|
TestCmovRegAddr(s, ecx, 0x80000000u, 0x1u, ecx, 0u);
|
|
|
|
TestCmovRegAddr(ns, edx, 0x80000000u, 0x1u, ecx, 1u);
|
|
TestCmovRegAddr(ns, edx, 0x1u, 0x80000000u, ecx, 0u);
|
|
|
|
TestCmovRegAddr(p, edi, 0x80000000u, 0x1u, edx, 1u);
|
|
TestCmovRegAddr(p, edi, 0x1u, 0x80000000u, edx, 0u);
|
|
|
|
TestCmovRegAddr(np, esi, 0x1u, 0x80000000u, eax, 1u);
|
|
TestCmovRegAddr(np, esi, 0x80000000u, 0x1u, eax, 0u);
|
|
|
|
TestCmovRegAddr(l, edi, 0x80000000u, 0x1u, ebx, 1u);
|
|
TestCmovRegAddr(l, edi, 0x1u, 0x80000000u, ebx, 0u);
|
|
|
|
TestCmovRegAddr(ge, eax, 0x1u, 0x80000000u, ecx, 1u);
|
|
TestCmovRegAddr(ge, eax, 0x80000000u, 0x1u, ecx, 0u);
|
|
|
|
TestCmovRegAddr(le, ebx, 0x80000000u, 0x1u, edx, 1u);
|
|
TestCmovRegAddr(le, ebx, 0x1u, 0x80000000u, edx, 0u);
|
|
|
|
#undef TestCmovRegAddr
|
|
}
|
|
|
|
} // end of anonymous namespace
|
|
} // end of namespace Test
|
|
} // end of namespace X8632
|
|
} // end of namespace Ice
|