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