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