//===- subzero/unittest/AssemblerX8632/ControleFlow.cpp -------------------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "IceAssemblerX8632.h"
#include "AssemblerX8632/TestUtil.h"
namespace Ice {
namespace X8632 {
namespace Test {
namespace {
TEST_F(AssemblerX8632Test, J) {
#define TestJ(C, Near, Src0, Value0, Src1, Value1, Dest) \
do { \
const bool NearJmp = AssemblerX8632::k##Near##Jump; \
Label ShouldBeTaken; \
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0xBEEF)); \
__ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
GPRRegister::Encoded_Reg_##Src1); \
__ j(Cond::Br_##C, &ShouldBeTaken, NearJmp); \
__ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0xC0FFEE)); \
__ bind(&ShouldBeTaken); \
AssembledTest test = assemble(); \
test.run(); \
EXPECT_EQ(Value0, test.Src0()) << "Br_" #C ", " #Near; \
EXPECT_EQ(Value1, test.Src1()) << "Br_" #C ", " #Near; \
EXPECT_EQ(0xBEEFul, test.Dest()) << "Br_" #C ", " #Near; \
reset(); \
} while (0)
TestJ(o, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
TestJ(o, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
TestJ(no, Near, ecx, 0x1ul, edx, 0x1ul, edi);
TestJ(no, Far, edx, 0x1ul, edi, 0x1ul, esi);
TestJ(b, Near, edi, 0x1ul, esi, 0x80000000ul, eax);
TestJ(b, Far, esi, 0x1ul, eax, 0x80000000ul, ebx);
TestJ(ae, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
TestJ(ae, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
TestJ(e, Near, ecx, 0x80000000ul, edx, 0x80000000ul, edi);
TestJ(e, Far, edx, 0x80000000ul, edi, 0x80000000ul, esi);
TestJ(ne, Near, edi, 0x80000000ul, esi, 0x1ul, eax);
TestJ(ne, Far, esi, 0x80000000ul, eax, 0x1ul, ebx);
TestJ(be, Near, eax, 0x1ul, ebx, 0x80000000ul, ecx);
TestJ(be, Far, ebx, 0x1ul, ecx, 0x80000000ul, edx);
TestJ(a, Near, ecx, 0x80000000ul, edx, 0x1ul, edi);
TestJ(a, Far, edx, 0x80000000ul, edi, 0x1ul, esi);
TestJ(s, Near, edi, 0x1ul, esi, 0x80000000ul, eax);
TestJ(s, Far, esi, 0x1ul, eax, 0x80000000ul, ebx);
TestJ(ns, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
TestJ(ns, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
TestJ(p, Near, ecx, 0x80000000ul, edx, 0x1ul, edi);
TestJ(p, Far, edx, 0x80000000ul, edi, 0x1ul, esi);
TestJ(np, Near, edi, 0x1ul, esi, 0x80000000ul, eax);
TestJ(np, Far, esi, 0x1ul, eax, 0x80000000ul, ebx);
TestJ(l, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
TestJ(l, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
TestJ(ge, Near, ecx, 0x1ul, edx, 0x80000000ul, edi);
TestJ(ge, Far, edx, 0x1ul, edi, 0x80000000ul, esi);
TestJ(le, Near, edi, 0x80000000ul, esi, 0x1ul, eax);
TestJ(le, Far, esi, 0x80000000ul, eax, 0x1ul, ebx);
TestJ(g, Near, eax, 0x1ul, ebx, 0x80000000ul, ecx);
TestJ(g, Far, ebx, 0x1ul, ecx, 0x80000000ul, edx);
#undef TestJ
}
TEST_F(AssemblerX8632Test, 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(AssemblerX8632Test, CallReg) {
__ call(Immediate(16));
__ popl(GPRRegister::Encoded_Reg_edx);
__ pushl(GPRRegister::Encoded_Reg_edx);
__ ret();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ popl(GPRRegister::Encoded_Reg_ebx);
__ call(GPRRegister::Encoded_Reg_ebx);
AssembledTest test = assemble();
test.run();
EXPECT_EQ(15u, test.edx() - test.ebx());
}
TEST_F(AssemblerX8632Test, CallAddr) {
__ call(Immediate(16));
__ mov(IceType_i8, GPRRegister::Encoded_Reg_eax, Immediate(0xf4));
__ ret();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ hlt();
__ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xf1f2f300));
__ call(Address(GPRRegister::Encoded_Reg_esp, 0, AssemblerFixup::NoFixup));
__ popl(GPRRegister::Encoded_Reg_edx);
AssembledTest test = assemble();
test.run();
EXPECT_EQ(0xf1f2f3f4, test.eax());
}
TEST_F(AssemblerX8632Test, 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, AssemblerX8632::k##Near##Jump); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ bind(&BackwardJmp); \
__ jmp(&Done, AssemblerX8632::k##Near##Jump); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ bind(&ForwardJmp); \
__ jmp(&BackwardJmp, AssemblerX8632::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, AssemblerX8632::kNearJump); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ hlt(); \
__ popl(GPRRegister::Encoded_Reg_##Dst); \
__ jmp(GPRRegister::Encoded_Reg_##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(eax);
TestImplReg(ebx);
TestImplReg(ecx);
TestImplReg(edx);
TestImplReg(esi);
TestImplReg(edi);
#undef TestImplReg
#undef TestImplAddr
}
} // end of anonymous namespace
} // end of namespace Test
} // end of namespace X8632
} // end of namespace Ice