| Index: unittest/AssemblerX8664/ControlFlow.cpp
|
| diff --git a/unittest/AssemblerX8664/ControlFlow.cpp b/unittest/AssemblerX8664/ControlFlow.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..704f6fdb7d1fea6c7410c7eef5c77038d603f46e
|
| --- /dev/null
|
| +++ b/unittest/AssemblerX8664/ControlFlow.cpp
|
| @@ -0,0 +1,307 @@
|
| +//===- subzero/unittest/AssemblerX8664/ControlFlow.cpp --------------------===//
|
| +//
|
| +// The Subzero Code Generator
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +#include "AssemblerX8664/TestUtil.h"
|
| +
|
| +namespace Ice {
|
| +namespace X8664 {
|
| +namespace Test {
|
| +namespace {
|
| +
|
| +TEST_F(AssemblerX8664Test, J) {
|
| +#define TestJ(C, Near, Dest, Src0, Value0, Src1, Value1) \
|
| + do { \
|
| + static constexpr char TestString[] = \
|
| + "(" #C ", " #Near ", " #Dest ", " #Src0 ", " #Value0 ", " #Src1 \
|
| + ", " #Value1 ")"; \
|
| + const bool NearJmp = AssemblerX8664::k##Near##Jump; \
|
| + Label ShouldBeTaken; \
|
| + __ mov(IceType_i32, Encoded_GPR_##Src0(), Immediate(Value0)); \
|
| + __ mov(IceType_i32, Encoded_GPR_##Src1(), Immediate(Value1)); \
|
| + __ mov(IceType_i32, Encoded_GPR_##Dest(), Immediate(0xBEEF)); \
|
| + __ cmp(IceType_i32, Encoded_GPR_##Src0(), Encoded_GPR_##Src1()); \
|
| + __ j(Cond::Br_##C, &ShouldBeTaken, NearJmp); \
|
| + __ mov(IceType_i32, Encoded_GPR_##Dest(), Immediate(0xC0FFEE)); \
|
| + __ bind(&ShouldBeTaken); \
|
| + AssembledTest test = assemble(); \
|
| + test.run(); \
|
| + ASSERT_EQ(Value0, test.Src0()) << TestString; \
|
| + ASSERT_EQ(Value1, test.Src1()) << TestString; \
|
| + ASSERT_EQ(0xBEEFul, test.Dest()) << TestString; \
|
| + reset(); \
|
| + } while (0)
|
| +
|
| +#define TestImpl(Dst, Src0, Src1) \
|
| + do { \
|
| + TestJ(o, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(o, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(no, Near, Dst, Src0, 0x1ul, Src1, 0x1ul); \
|
| + TestJ(no, Far, Dst, Src0, 0x1ul, Src1, 0x1ul); \
|
| + TestJ(b, Near, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(b, Far, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(ae, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(ae, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(e, Near, Dst, Src0, 0x80000000ul, Src1, 0x80000000ul); \
|
| + TestJ(e, Far, Dst, Src0, 0x80000000ul, Src1, 0x80000000ul); \
|
| + TestJ(ne, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(ne, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(be, Near, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(be, Far, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(a, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(a, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(s, Near, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(s, Far, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(ns, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(ns, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(p, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(p, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(np, Near, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(np, Far, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(l, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(l, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(ge, Near, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(ge, Far, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(le, Near, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(le, Far, Dst, Src0, 0x80000000ul, Src1, 0x1ul); \
|
| + TestJ(g, Near, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + TestJ(g, Far, Dst, Src0, 0x1ul, Src1, 0x80000000ul); \
|
| + } while (0)
|
| +
|
| + TestImpl(r1, r2, r3);
|
| + TestImpl(r2, r3, r4);
|
| + TestImpl(r3, r4, r5);
|
| + TestImpl(r4, r5, r6);
|
| + TestImpl(r5, r6, r7);
|
| + TestImpl(r6, r7, r8);
|
| + TestImpl(r7, r8, r10);
|
| + TestImpl(r8, r10, r11);
|
| + TestImpl(r10, r11, r12);
|
| + TestImpl(r11, r12, r13);
|
| + TestImpl(r12, r13, r14);
|
| + TestImpl(r13, r14, r15);
|
| + TestImpl(r14, r15, r1);
|
| + TestImpl(r15, r1, r2);
|
| +
|
| +#undef TestImpl
|
| +#undef TestJ
|
| +}
|
| +
|
| +TEST_F(AssemblerX8664Test, CallImm) {
|
| + __ call(Immediate(16));
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ hlt();
|
| + __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xf00f));
|
| + __ popl(GPRRegister::Encoded_Reg_ebx);
|
| +
|
| + AssembledTest test = assemble();
|
| +
|
| + test.run();
|
| +
|
| + EXPECT_EQ(0xF00Fu, test.eax());
|
| +}
|
| +
|
| +TEST_F(AssemblerX8664Test, CallReg) {
|
| +#define TestImpl(Dst, Src) \
|
| + do { \
|
| + __ call(Immediate(16)); \
|
| + int CallTargetAddr = codeBytesSize() + 12; \
|
| + __ popl(Encoded_GPR_##Dst()); \
|
| + __ pushl(Encoded_GPR_##Dst()); \
|
| + __ ret(); \
|
| + for (int I = codeBytesSize(); I < CallTargetAddr; ++I) { \
|
| + __ hlt(); \
|
| + } \
|
| + __ popl(Encoded_GPR_##Src()); \
|
| + __ call(Encoded_GPR_##Src()); \
|
| + \
|
| + AssembledTest test = assemble(); \
|
| + \
|
| + test.run(); \
|
| + \
|
| + ASSERT_LE(15u, test.Dst() - test.Src()) << "(" #Dst ", " #Src ")"; \
|
| + reset(); \
|
| + } while (0)
|
| +
|
| + TestImpl(r1, r2);
|
| + TestImpl(r2, r3);
|
| + TestImpl(r3, r4);
|
| + TestImpl(r4, r5);
|
| + TestImpl(r5, r6);
|
| + TestImpl(r6, r7);
|
| + TestImpl(r7, r8);
|
| + TestImpl(r8, r10);
|
| + TestImpl(r10, r11);
|
| + TestImpl(r11, r12);
|
| + TestImpl(r12, r13);
|
| + TestImpl(r13, r14);
|
| + TestImpl(r14, r15);
|
| + TestImpl(r15, r1);
|
| +
|
| +#undef TestImpl
|
| +}
|
| +
|
| +TEST_F(AssemblerX8664Test, CallAddr) {
|
| +#define TestImpl(Dst, Src) \
|
| + do { \
|
| + const uint32_t T0 = allocateQword(); \
|
| + const uint64_t V0 = 0xA0C0FFEEBEEFFEEFull; \
|
| + __ call(Immediate(16)); \
|
| + int CallTargetAddr = codeBytesSize() + 12; \
|
| + __ mov(IceType_i8, Encoded_GPR_##Dst##l(), Immediate(0xf4)); \
|
| + __ ret(); \
|
| + for (int I = codeBytesSize(); I < CallTargetAddr; ++I) { \
|
| + __ hlt(); \
|
| + } \
|
| + __ mov(IceType_i64, Encoded_GPR_##Dst##q(), dwordAddress(T0)); \
|
| + __ mov(IceType_i64, Encoded_GPR_##Src##q(), Encoded_GPR_rsp()); \
|
| + __ call(Address(Encoded_GPR_##Src##q(), 0)); \
|
| + __ popl(Encoded_GPR_##Src##q()); \
|
| + \
|
| + AssembledTest test = assemble(); \
|
| + test.setQwordTo(T0, V0); \
|
| + test.run(); \
|
| + \
|
| + ASSERT_EQ(0xA0C0FFEEBEEFFEF4ull, test.Dst##q()) << "(" #Dst ", " #Src ")"; \
|
| + reset(); \
|
| + } while (0)
|
| +
|
| + TestImpl(r1, r2);
|
| + TestImpl(r2, r3);
|
| + TestImpl(r3, r4);
|
| + TestImpl(r4, r5);
|
| + TestImpl(r5, r6);
|
| + TestImpl(r6, r7);
|
| + TestImpl(r7, r8);
|
| + TestImpl(r8, r10);
|
| + TestImpl(r10, r11);
|
| + TestImpl(r11, r12);
|
| + TestImpl(r12, r13);
|
| + TestImpl(r13, r14);
|
| + TestImpl(r14, r15);
|
| + TestImpl(r15, r1);
|
| +
|
| +#undef TestImpl
|
| +}
|
| +
|
| +TEST_F(AssemblerX8664Test, Jmp) {
|
| +// TestImplReg uses jmp(Label), so jmp(Label) needs to be tested before it.
|
| +#define TestImplAddr(Near) \
|
| + do { \
|
| + Label ForwardJmp; \
|
| + Label BackwardJmp; \
|
| + Label Done; \
|
| + \
|
| + __ jmp(&ForwardJmp, AssemblerX8664::k##Near##Jump); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ bind(&BackwardJmp); \
|
| + __ jmp(&Done, AssemblerX8664::k##Near##Jump); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ bind(&ForwardJmp); \
|
| + __ jmp(&BackwardJmp, AssemblerX8664::k##NearJump); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ bind(&Done); \
|
| + } while (0)
|
| +
|
| +#define TestImplReg(Dst) \
|
| + do { \
|
| + __ call(Immediate(16)); \
|
| + Label Done; \
|
| + __ jmp(&Done, AssemblerX8664::kNearJump); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ popl(Encoded_GPR_##Dst()); \
|
| + __ jmp(Encoded_GPR_##Dst()); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ hlt(); \
|
| + __ bind(&Done); \
|
| + \
|
| + AssembledTest test = assemble(); \
|
| + test.run(); \
|
| + \
|
| + reset(); \
|
| + } while (0)
|
| +
|
| + TestImplAddr(Near);
|
| + TestImplAddr(Far);
|
| +
|
| + TestImplReg(r1);
|
| + TestImplReg(r2);
|
| + TestImplReg(r3);
|
| + TestImplReg(r4);
|
| + TestImplReg(r5);
|
| + TestImplReg(r6);
|
| + TestImplReg(r7);
|
| + TestImplReg(r8);
|
| + TestImplReg(r10);
|
| + TestImplReg(r11);
|
| + TestImplReg(r12);
|
| + TestImplReg(r13);
|
| + TestImplReg(r14);
|
| + TestImplReg(r15);
|
| +
|
| +#undef TestImplReg
|
| +#undef TestImplAddr
|
| +}
|
| +
|
| +} // end of anonymous namespace
|
| +} // end of namespace Test
|
| +} // end of namespace X8664
|
| +} // end of namespace Ice
|
|
|