| //===- subzero/unittest/AssemblerX8632/X87.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(AssemblerX8632LowLevelTest, Fld) { | |
| __ fld(IceType_f32, | |
| Address(GPRRegister::Encoded_Reg_ebp, 1, AssemblerFixup::NoFixup)); | |
| __ fld(IceType_f64, Address(GPRRegister::Encoded_Reg_ebp, 0x10000, | |
| AssemblerFixup::NoFixup)); | |
| constexpr size_t ByteCount = 9; | |
| ASSERT_EQ(ByteCount, codeBytesSize()); | |
| constexpr uint8_t Fld32Opcode = 0xd9; | |
| constexpr uint8_t Fld32ModRM = (/*mod*/ 1 << 6) | (/*reg*/ 0 << 3) | | |
| (/*rm*/ GPRRegister::Encoded_Reg_ebp); | |
| constexpr uint8_t Fld64Opcode = 0xdd; | |
| constexpr uint8_t Fld64ModRM = (/*mod*/ 2 << 6) | (/*reg*/ 0 << 3) | | |
| (/*rm*/ GPRRegister::Encoded_Reg_ebp); | |
| verifyBytes<ByteCount>(codeBytes(), Fld32Opcode, Fld32ModRM, 0x01, | |
| Fld64Opcode, Fld64ModRM, 0x00, 0x00, 0x01, 0x00); | |
| } | |
| TEST_F(AssemblerX8632LowLevelTest, FstpAddr) { | |
| __ fstp(IceType_f32, | |
| Address(GPRRegister::Encoded_Reg_ebp, 1, AssemblerFixup::NoFixup)); | |
| __ fstp(IceType_f64, Address(GPRRegister::Encoded_Reg_ebp, 0x10000, | |
| AssemblerFixup::NoFixup)); | |
| constexpr size_t ByteCount = 9; | |
| ASSERT_EQ(ByteCount, codeBytesSize()); | |
| constexpr uint8_t Fld32Opcode = 0xd9; | |
| constexpr uint8_t Fld32ModRM = (/*mod*/ 1 << 6) | (/*reg*/ 3 << 3) | | |
| (/*rm*/ GPRRegister::Encoded_Reg_ebp); | |
| constexpr uint8_t Fld64Opcode = 0xdd; | |
| constexpr uint8_t Fld64ModRM = (/*mod*/ 2 << 6) | (/*reg*/ 3 << 3) | | |
| (/*rm*/ GPRRegister::Encoded_Reg_ebp); | |
| verifyBytes<ByteCount>(codeBytes(), Fld32Opcode, Fld32ModRM, 0x01, | |
| Fld64Opcode, Fld64ModRM, 0x00, 0x00, 0x01, 0x00); | |
| } | |
| TEST_F(AssemblerX8632LowLevelTest, Fincstp) { | |
| __ fincstp(); | |
| constexpr size_t ByteCount = 2; | |
| ASSERT_EQ(ByteCount, codeBytesSize()); | |
| verifyBytes<ByteCount>(codeBytes(), 0xD9, 0XF7); | |
| } | |
| TEST_F(AssemblerX8632LowLevelTest, FnstcwAddr) { | |
| __ fnstcw( | |
| Address(GPRRegister::Encoded_Reg_ebp, 0x12345, AssemblerFixup::NoFixup)); | |
| constexpr size_t ByteCount = 6; | |
| ASSERT_EQ(ByteCount, codeBytesSize()); | |
| constexpr uint8_t Opcode = 0xd9; | |
| constexpr uint8_t ModRM = (/*mod*/ 2 << 6) | (/*reg*/ 7 << 3) | | |
| (/*rm*/ GPRRegister::Encoded_Reg_ebp); | |
| verifyBytes<ByteCount>(codeBytes(), Opcode, ModRM, 0x45, 0x23, 0x01, 0x00); | |
| } | |
| TEST_F(AssemblerX8632LowLevelTest, FldcwAddr) { | |
| __ fldcw( | |
| Address(GPRRegister::Encoded_Reg_ebp, 0x12345, AssemblerFixup::NoFixup)); | |
| constexpr size_t ByteCount = 6; | |
| ASSERT_EQ(ByteCount, codeBytesSize()); | |
| constexpr uint8_t Opcode = 0xd9; | |
| constexpr uint8_t ModRM = (/*mod*/ 2 << 6) | (/*reg*/ 5 << 3) | | |
| (/*rm*/ GPRRegister::Encoded_Reg_ebp); | |
| verifyBytes<ByteCount>(codeBytes(), Opcode, ModRM, 0x45, 0x23, 0x01, 0x00); | |
| } | |
| TEST_F(AssemblerX8632Test, FstpSt) { | |
| #define TestFstpSt(Size, MemorySize, Type) \ | |
| do { \ | |
| const uint32_t T1 = allocate##MemorySize(); \ | |
| const Type OldValue1 = -1.0f; \ | |
| const uint32_t T2 = allocate##MemorySize(); \ | |
| const Type OldValue2 = -2.0f; \ | |
| const uint32_t T3 = allocate##MemorySize(); \ | |
| const Type OldValue3 = -3.0f; \ | |
| const uint32_t T4 = allocate##MemorySize(); \ | |
| const Type OldValue4 = -4.0f; \ | |
| const uint32_t T5 = allocate##MemorySize(); \ | |
| const Type OldValue5 = -5.0f; \ | |
| const uint32_t T6 = allocate##MemorySize(); \ | |
| const Type OldValue6 = -6.0f; \ | |
| const uint32_t T7 = allocate##MemorySize(); \ | |
| const Type OldValue7 = -7.0f; \ | |
| \ | |
| const uint32_t N7 = allocate##MemorySize(); \ | |
| constexpr Type NewValue7 = 777.77f; \ | |
| const uint32_t N6 = allocate##MemorySize(); \ | |
| constexpr Type NewValue6 = 666.66f; \ | |
| const uint32_t N5 = allocate##MemorySize(); \ | |
| constexpr Type NewValue5 = 555.55f; \ | |
| const uint32_t N4 = allocate##MemorySize(); \ | |
| constexpr Type NewValue4 = 444.44f; \ | |
| const uint32_t N3 = allocate##MemorySize(); \ | |
| constexpr Type NewValue3 = 333.33f; \ | |
| const uint32_t N2 = allocate##MemorySize(); \ | |
| constexpr Type NewValue2 = 222.22f; \ | |
| const uint32_t N1 = allocate##MemorySize(); \ | |
| constexpr Type NewValue1 = 111.11f; \ | |
| \ | |
| __ fincstp(); \ | |
| __ fincstp(); \ | |
| __ fincstp(); \ | |
| __ fincstp(); \ | |
| __ fincstp(); \ | |
| __ fincstp(); \ | |
| __ fincstp(); \ | |
| \ | |
| __ fld(IceType_f##Size, dwordAddress(N7)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_7); \ | |
| __ fld(IceType_f##Size, dwordAddress(N6)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_6); \ | |
| __ fld(IceType_f##Size, dwordAddress(N5)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_5); \ | |
| __ fld(IceType_f##Size, dwordAddress(N4)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_4); \ | |
| __ fld(IceType_f##Size, dwordAddress(N3)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_3); \ | |
| __ fld(IceType_f##Size, dwordAddress(N2)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_2); \ | |
| __ fld(IceType_f##Size, dwordAddress(N1)); \ | |
| __ fstp(X87STRegister::Encoded_X87ST_1); \ | |
| \ | |
| __ fstp(IceType_f##Size, dwordAddress(T1)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T2)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T3)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T4)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T5)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T6)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T7)); \ | |
| \ | |
| AssembledTest test = assemble(); \ | |
| test.set##MemorySize##To(T1, OldValue1); \ | |
| test.set##MemorySize##To(N1, NewValue1); \ | |
| test.set##MemorySize##To(T2, OldValue2); \ | |
| test.set##MemorySize##To(N2, NewValue2); \ | |
| test.set##MemorySize##To(T3, OldValue3); \ | |
| test.set##MemorySize##To(N3, NewValue3); \ | |
| test.set##MemorySize##To(T4, OldValue4); \ | |
| test.set##MemorySize##To(N4, NewValue4); \ | |
| test.set##MemorySize##To(T5, OldValue5); \ | |
| test.set##MemorySize##To(N5, NewValue5); \ | |
| test.set##MemorySize##To(T6, OldValue6); \ | |
| test.set##MemorySize##To(N6, NewValue6); \ | |
| test.set##MemorySize##To(T7, OldValue7); \ | |
| test.set##MemorySize##To(N7, NewValue7); \ | |
| \ | |
| test.run(); \ | |
| \ | |
| ASSERT_FLOAT_EQ(NewValue1, test.contentsOf##MemorySize<Type>(T1)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue1, test.contentsOf##MemorySize<Type>(N1)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue2, test.contentsOf##MemorySize<Type>(T2)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue2, test.contentsOf##MemorySize<Type>(N2)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue3, test.contentsOf##MemorySize<Type>(T3)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue3, test.contentsOf##MemorySize<Type>(N3)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue4, test.contentsOf##MemorySize<Type>(T4)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue4, test.contentsOf##MemorySize<Type>(N4)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue5, test.contentsOf##MemorySize<Type>(T5)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue5, test.contentsOf##MemorySize<Type>(N5)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue6, test.contentsOf##MemorySize<Type>(T6)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue6, test.contentsOf##MemorySize<Type>(N6)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue7, test.contentsOf##MemorySize<Type>(T7)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| ASSERT_FLOAT_EQ(NewValue7, test.contentsOf##MemorySize<Type>(N7)) \ | |
| << "(" #Size ", " #MemorySize ", " #Type ")"; \ | |
| \ | |
| reset(); \ | |
| } while (0) | |
| TestFstpSt(32, Dword, float); | |
| TestFstpSt(64, Qword, double); | |
| #undef TestFstpSt | |
| } | |
| TEST_F(AssemblerX8632Test, Fild) { | |
| #define TestFild(OperandType, Size, MemorySize, FpType, IntType) \ | |
| do { \ | |
| const uint32_t T0 = allocate##MemorySize(); \ | |
| constexpr IntType V0 = 0x1234; \ | |
| \ | |
| __ fild##OperandType(dwordAddress(T0)); \ | |
| __ fstp(IceType_f##Size, dwordAddress(T0)); \ | |
| \ | |
| AssembledTest test = assemble(); \ | |
| \ | |
| test.set##MemorySize##To(T0, V0); \ | |
| test.run(); \ | |
| \ | |
| ASSERT_FLOAT_EQ(static_cast<FpType>(V0), \ | |
| test.contentsOf##MemorySize<FpType>(T0)) \ | |
| << "(" #OperandType ", " #Size ", " #MemorySize ", " #FpType \ | |
| ", " #IntType ")"; \ | |
| \ | |
| reset(); \ | |
| } while (0) | |
| TestFild(s, 32, Dword, float, uint32_t); | |
| TestFild(l, 64, Qword, double, uint64_t); | |
| #undef TestFild | |
| } | |
| TEST_F(AssemblerX8632Test, Fistp) { | |
| #define TestFistp(OperandType, Size, MemorySize, FpType, IntType) \ | |
| do { \ | |
| const uint32_t T0 = allocate##MemorySize(); \ | |
| constexpr IntType V0 = 0x1234; \ | |
| const uint32_t T1 = allocate##MemorySize(); \ | |
| constexpr IntType V1 = 0xFFFF; \ | |
| \ | |
| __ fild##OperandType(dwordAddress(T0)); \ | |
| __ fistp##OperandType(dwordAddress(T1)); \ | |
| \ | |
| AssembledTest test = assemble(); \ | |
| \ | |
| test.set##MemorySize##To(T0, V0); \ | |
| test.set##MemorySize##To(T1, V1); \ | |
| test.run(); \ | |
| \ | |
| ASSERT_EQ(static_cast<IntType>(V0), \ | |
| test.contentsOf##MemorySize<IntType>(T0)) \ | |
| << "(" #OperandType ", " #Size ", " #MemorySize ", " #FpType \ | |
| ", " #IntType ")"; \ | |
| ASSERT_EQ(static_cast<IntType>(V0), \ | |
| test.contentsOf##MemorySize<IntType>(T1)) \ | |
| << "(" #OperandType ", " #Size ", " #MemorySize ", " #FpType \ | |
| ", " #IntType ")"; \ | |
| \ | |
| reset(); \ | |
| } while (0) | |
| TestFistp(s, 32, Dword, float, uint32_t); | |
| TestFistp(l, 64, Qword, double, uint64_t); | |
| #undef TestFistp | |
| } | |
| } // end of anonymous namespace | |
| } // end of namespace Test | |
| } // end of namespace X8632 | |
| } // end of namespace Ice |