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