274 lines
16 KiB
C++
274 lines
16 KiB
C++
//===- 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
|