| Index: unittest/AssemblerX8632/X87.cpp
|
| diff --git a/unittest/AssemblerX8632/X87.cpp b/unittest/AssemblerX8632/X87.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d3f38a16c19907593b2f3fdd3d3a48a01b34436b
|
| --- /dev/null
|
| +++ b/unittest/AssemblerX8632/X87.cpp
|
| @@ -0,0 +1,267 @@
|
| +//===- 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));
|
| + __ fld(IceType_f64, Address(GPRRegister::Encoded_Reg_ebp, 0x10000));
|
| +
|
| + 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));
|
| + __ fstp(IceType_f64, Address(GPRRegister::Encoded_Reg_ebp, 0x10000));
|
| +
|
| + 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));
|
| +
|
| + 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));
|
| +
|
| + 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
|
|
|