//===- 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; \
const uint32_t T1 = allocateDword(); \
__ 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)); \
__ popl(Encoded_GPR_##Src##q()); \
__ mov(IceType_i32, dwordAddress(T1), Encoded_GPR_##Src##d()); \
__ call(dwordAddress(T1)); \
\
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