| //===- 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 |