From 408691f9673fb69b5ed45326f6ded4f3b6f19c50 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Mon, 16 Jun 2014 23:58:24 +0000 Subject: [PATCH] [FastISel][X86] Refactor the code to get the X86 condition from a helper function. NFC. Make use of helper functions to simplify the branch and compare instruction selection in FastISel. Also add test cases for compare and conditonal branch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211077 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FastISel.cpp | 194 +++++++------- lib/Target/X86/X86InstrInfo.cpp | 5 +- lib/Target/X86/X86InstrInfo.h | 7 +- test/CodeGen/X86/fast-isel-cmp-branch2.ll | 294 ++++++++++++++++++++++ test/CodeGen/X86/fast-isel-cmp.ll | 272 ++++++++++++++++++++ 5 files changed, 676 insertions(+), 96 deletions(-) create mode 100644 test/CodeGen/X86/fast-isel-cmp-branch2.ll create mode 100644 test/CodeGen/X86/fast-isel-cmp.ll diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index e490c274b5f..80cc99bb80c 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -16,6 +16,7 @@ #include "X86.h" #include "X86CallingConv.h" #include "X86InstrBuilder.h" +#include "X86InstrInfo.h" #include "X86MachineFunctionInfo.h" #include "X86RegisterInfo.h" #include "X86Subtarget.h" @@ -154,6 +155,44 @@ private: } // end anonymous namespace. +static std::pair +getX86ConditonCode(CmpInst::Predicate Predicate) { + X86::CondCode CC = X86::COND_INVALID; + bool NeedSwap = false; + switch (Predicate) { + default: break; + // Floating-point Predicates + case CmpInst::FCMP_UEQ: CC = X86::COND_E; break; + case CmpInst::FCMP_OLT: NeedSwap = true; // fall-through + case CmpInst::FCMP_OGT: CC = X86::COND_A; break; + case CmpInst::FCMP_OLE: NeedSwap = true; // fall-through + case CmpInst::FCMP_OGE: CC = X86::COND_AE; break; + case CmpInst::FCMP_UGT: NeedSwap = true; // fall-through + case CmpInst::FCMP_ULT: CC = X86::COND_B; break; + case CmpInst::FCMP_UGE: NeedSwap = true; // fall-through + case CmpInst::FCMP_ULE: CC = X86::COND_BE; break; + case CmpInst::FCMP_ONE: CC = X86::COND_NE; break; + case CmpInst::FCMP_UNO: CC = X86::COND_P; break; + case CmpInst::FCMP_ORD: CC = X86::COND_NP; break; + case CmpInst::FCMP_OEQ: // fall-through + case CmpInst::FCMP_UNE: CC = X86::COND_INVALID; break; + + // Integer Predicates + case CmpInst::ICMP_EQ: CC = X86::COND_E; break; + case CmpInst::ICMP_NE: CC = X86::COND_NE; break; + case CmpInst::ICMP_UGT: CC = X86::COND_A; break; + case CmpInst::ICMP_UGE: CC = X86::COND_AE; break; + case CmpInst::ICMP_ULT: CC = X86::COND_B; break; + case CmpInst::ICMP_ULE: CC = X86::COND_BE; break; + case CmpInst::ICMP_SGT: CC = X86::COND_G; break; + case CmpInst::ICMP_SGE: CC = X86::COND_GE; break; + case CmpInst::ICMP_SLT: CC = X86::COND_L; break; + case CmpInst::ICMP_SLE: CC = X86::COND_LE; break; + } + + return std::make_pair(CC, NeedSwap); +} + bool X86FastISel::isTypeLegal(Type *Ty, MVT &VT, bool AllowI1) { EVT evt = TLI.getValueType(Ty, /*HandleUnknown=*/true); if (evt == MVT::Other || !evt.isSimple()) @@ -1009,73 +1048,51 @@ bool X86FastISel::X86SelectCmp(const Instruction *I) { if (!isTypeLegal(I->getOperand(0)->getType(), VT)) return false; - unsigned ResultReg = createResultReg(&X86::GR8RegClass); - unsigned SetCCOpc; - bool SwapArgs; // false -> compare Op0, Op1. true -> compare Op1, Op0. + // FCMP_OEQ and FCMP_UNE cannot be checked with a single instruction. + static unsigned SETFOpcTable[2][2] = { + { X86::SETEr, X86::SETNPr }, + { X86::SETNEr, X86::SETPr } + }; + unsigned *SETFOpc = nullptr; switch (CI->getPredicate()) { - case CmpInst::FCMP_OEQ: { + default: break; + case CmpInst::FCMP_OEQ: SETFOpc = &SETFOpcTable[0][0]; break; + case CmpInst::FCMP_UNE: SETFOpc = &SETFOpcTable[1][0]; break; + } + + unsigned ResultReg = createResultReg(&X86::GR8RegClass); + if (SETFOpc) { if (!X86FastEmitCompare(CI->getOperand(0), CI->getOperand(1), VT)) return false; - unsigned EReg = createResultReg(&X86::GR8RegClass); - unsigned NPReg = createResultReg(&X86::GR8RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::SETEr), EReg); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(X86::SETNPr), NPReg); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(X86::AND8rr), ResultReg).addReg(NPReg).addReg(EReg); + unsigned FlagReg1 = createResultReg(&X86::GR8RegClass); + unsigned FlagReg2 = createResultReg(&X86::GR8RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[0]), + FlagReg1); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[1]), + FlagReg2); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::AND8rr), + ResultReg).addReg(FlagReg1).addReg(FlagReg2); UpdateValueMap(I, ResultReg); return true; } - case CmpInst::FCMP_UNE: { - if (!X86FastEmitCompare(CI->getOperand(0), CI->getOperand(1), VT)) - return false; - unsigned NEReg = createResultReg(&X86::GR8RegClass); - unsigned PReg = createResultReg(&X86::GR8RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::SETNEr), NEReg); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::SETPr), PReg); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::OR8rr),ResultReg) - .addReg(PReg).addReg(NEReg); - UpdateValueMap(I, ResultReg); - return true; - } - case CmpInst::FCMP_OGT: SwapArgs = false; SetCCOpc = X86::SETAr; break; - case CmpInst::FCMP_OGE: SwapArgs = false; SetCCOpc = X86::SETAEr; break; - case CmpInst::FCMP_OLT: SwapArgs = true; SetCCOpc = X86::SETAr; break; - case CmpInst::FCMP_OLE: SwapArgs = true; SetCCOpc = X86::SETAEr; break; - case CmpInst::FCMP_ONE: SwapArgs = false; SetCCOpc = X86::SETNEr; break; - case CmpInst::FCMP_ORD: SwapArgs = false; SetCCOpc = X86::SETNPr; break; - case CmpInst::FCMP_UNO: SwapArgs = false; SetCCOpc = X86::SETPr; break; - case CmpInst::FCMP_UEQ: SwapArgs = false; SetCCOpc = X86::SETEr; break; - case CmpInst::FCMP_UGT: SwapArgs = true; SetCCOpc = X86::SETBr; break; - case CmpInst::FCMP_UGE: SwapArgs = true; SetCCOpc = X86::SETBEr; break; - case CmpInst::FCMP_ULT: SwapArgs = false; SetCCOpc = X86::SETBr; break; - case CmpInst::FCMP_ULE: SwapArgs = false; SetCCOpc = X86::SETBEr; break; + X86::CondCode CC; + bool SwapArgs; // false -> compare Op0, Op1. true -> compare Op1, Op0. + std::tie(CC, SwapArgs) = getX86ConditonCode(CI->getPredicate()); + assert(CC <= X86::LAST_VALID_COND && "Unexpected conditon code."); + unsigned Opc = X86::getSETFromCond(CC); - case CmpInst::ICMP_EQ: SwapArgs = false; SetCCOpc = X86::SETEr; break; - case CmpInst::ICMP_NE: SwapArgs = false; SetCCOpc = X86::SETNEr; break; - case CmpInst::ICMP_UGT: SwapArgs = false; SetCCOpc = X86::SETAr; break; - case CmpInst::ICMP_UGE: SwapArgs = false; SetCCOpc = X86::SETAEr; break; - case CmpInst::ICMP_ULT: SwapArgs = false; SetCCOpc = X86::SETBr; break; - case CmpInst::ICMP_ULE: SwapArgs = false; SetCCOpc = X86::SETBEr; break; - case CmpInst::ICMP_SGT: SwapArgs = false; SetCCOpc = X86::SETGr; break; - case CmpInst::ICMP_SGE: SwapArgs = false; SetCCOpc = X86::SETGEr; break; - case CmpInst::ICMP_SLT: SwapArgs = false; SetCCOpc = X86::SETLr; break; - case CmpInst::ICMP_SLE: SwapArgs = false; SetCCOpc = X86::SETLEr; break; - default: - return false; - } - - const Value *Op0 = CI->getOperand(0), *Op1 = CI->getOperand(1); + const Value *LHS = CI->getOperand(0); + const Value *RHS = CI->getOperand(1); if (SwapArgs) - std::swap(Op0, Op1); + std::swap(LHS, RHS); // Emit a compare of Op0/Op1. - if (!X86FastEmitCompare(Op0, Op1, VT)) + if (!X86FastEmitCompare(LHS, RHS, VT)) return false; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SetCCOpc), ResultReg); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg); UpdateValueMap(I, ResultReg); return true; } @@ -1152,66 +1169,59 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) { Predicate = CmpInst::getInversePredicate(Predicate); } - bool SwapArgs; // false -> compare Op0, Op1. true -> compare Op1, Op0. - unsigned BranchOpc; // Opcode to jump on, e.g. "X86::JA" - + // FCMP_OEQ and FCMP_UNE cannot be expressed with a single flag/conditon + // code check. Instead two branch instructions are required to check all + // the flags. First we change the predicate to a supported conditon code, + // which will be the first branch. Later one we will emit the second + // branch. + bool NeedExtraBranch = false; switch (Predicate) { + default: break; case CmpInst::FCMP_OEQ: - std::swap(TrueMBB, FalseMBB); - Predicate = CmpInst::FCMP_UNE; - // FALL THROUGH - case CmpInst::FCMP_UNE: SwapArgs = false; BranchOpc = X86::JNE_4; break; - case CmpInst::FCMP_OGT: SwapArgs = false; BranchOpc = X86::JA_4; break; - case CmpInst::FCMP_OGE: SwapArgs = false; BranchOpc = X86::JAE_4; break; - case CmpInst::FCMP_OLT: SwapArgs = true; BranchOpc = X86::JA_4; break; - case CmpInst::FCMP_OLE: SwapArgs = true; BranchOpc = X86::JAE_4; break; - case CmpInst::FCMP_ONE: SwapArgs = false; BranchOpc = X86::JNE_4; break; - case CmpInst::FCMP_ORD: SwapArgs = false; BranchOpc = X86::JNP_4; break; - case CmpInst::FCMP_UNO: SwapArgs = false; BranchOpc = X86::JP_4; break; - case CmpInst::FCMP_UEQ: SwapArgs = false; BranchOpc = X86::JE_4; break; - case CmpInst::FCMP_UGT: SwapArgs = true; BranchOpc = X86::JB_4; break; - case CmpInst::FCMP_UGE: SwapArgs = true; BranchOpc = X86::JBE_4; break; - case CmpInst::FCMP_ULT: SwapArgs = false; BranchOpc = X86::JB_4; break; - case CmpInst::FCMP_ULE: SwapArgs = false; BranchOpc = X86::JBE_4; break; - - case CmpInst::ICMP_EQ: SwapArgs = false; BranchOpc = X86::JE_4; break; - case CmpInst::ICMP_NE: SwapArgs = false; BranchOpc = X86::JNE_4; break; - case CmpInst::ICMP_UGT: SwapArgs = false; BranchOpc = X86::JA_4; break; - case CmpInst::ICMP_UGE: SwapArgs = false; BranchOpc = X86::JAE_4; break; - case CmpInst::ICMP_ULT: SwapArgs = false; BranchOpc = X86::JB_4; break; - case CmpInst::ICMP_ULE: SwapArgs = false; BranchOpc = X86::JBE_4; break; - case CmpInst::ICMP_SGT: SwapArgs = false; BranchOpc = X86::JG_4; break; - case CmpInst::ICMP_SGE: SwapArgs = false; BranchOpc = X86::JGE_4; break; - case CmpInst::ICMP_SLT: SwapArgs = false; BranchOpc = X86::JL_4; break; - case CmpInst::ICMP_SLE: SwapArgs = false; BranchOpc = X86::JLE_4; break; - default: - return false; + std::swap(TrueMBB, FalseMBB); // fall-through + case CmpInst::FCMP_UNE: + NeedExtraBranch = true; + Predicate = CmpInst::FCMP_ONE; + break; } - const Value *Op0 = CI->getOperand(0), *Op1 = CI->getOperand(1); + X86::CondCode CC; + bool SwapArgs; // false -> compare Op0, Op1. true -> compare Op1, Op0. + unsigned BranchOpc; // Opcode to jump on, e.g. "X86::JA" + std::tie(CC, SwapArgs) = getX86ConditonCode(Predicate); + assert(CC <= X86::LAST_VALID_COND && "Unexpected conditon code."); + + BranchOpc = X86::GetCondBranchFromCond(CC); + const Value *CmpLHS = CI->getOperand(0); + const Value *CmpRHS = CI->getOperand(1); if (SwapArgs) - std::swap(Op0, Op1); + std::swap(CmpLHS, CmpRHS); // Emit a compare of the LHS and RHS, setting the flags. - if (!X86FastEmitCompare(Op0, Op1, VT)) + if (!X86FastEmitCompare(CmpLHS, CmpRHS, VT)) return false; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(BranchOpc)) .addMBB(TrueMBB); - if (Predicate == CmpInst::FCMP_UNE) { - // X86 requires a second branch to handle UNE (and OEQ, - // which is mapped to UNE above). + // X86 requires a second branch to handle UNE (and OEQ, which is mapped + // to UNE above). + if (NeedExtraBranch) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::JP_4)) .addMBB(TrueMBB); } - FastEmitBranch(FalseMBB, DbgLoc); + // Obtain the branch weight and add the TrueBB to the successor list. uint32_t BranchWeight = 0; if (FuncInfo.BPI) BranchWeight = FuncInfo.BPI->getEdgeWeight(BI->getParent(), TrueMBB->getBasicBlock()); FuncInfo.MBB->addSuccessor(TrueMBB, BranchWeight); + + // Emits an unconditional branch to the FalseBB, obtains the branch + // weight, andd adds it to the successor list. + FastEmitBranch(FalseMBB, DbgLoc); + return true; } } else if (TruncInst *TI = dyn_cast(BI->getCondition())) { diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index b9f1ed0124c..bfc8e2759dc 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -2670,8 +2670,7 @@ static X86::CondCode getSwappedCondition(X86::CondCode CC) { /// getSETFromCond - Return a set opcode for the given condition and /// whether it has memory operand. -static unsigned getSETFromCond(X86::CondCode CC, - bool HasMemoryOperand) { +unsigned X86::getSETFromCond(CondCode CC, bool HasMemoryOperand) { static const uint16_t Opc[16][2] = { { X86::SETAr, X86::SETAm }, { X86::SETAEr, X86::SETAEm }, @@ -2691,7 +2690,7 @@ static unsigned getSETFromCond(X86::CondCode CC, { X86::SETSr, X86::SETSm } }; - assert(CC < 16 && "Can only handle standard cond codes"); + assert(CC <= LAST_VALID_COND && "Can only handle standard cond codes"); return Opc[CC][HasMemoryOperand ? 1 : 0]; } diff --git a/lib/Target/X86/X86InstrInfo.h b/lib/Target/X86/X86InstrInfo.h index 18ee24a8e3f..d76c52ce47d 100644 --- a/lib/Target/X86/X86InstrInfo.h +++ b/lib/Target/X86/X86InstrInfo.h @@ -46,6 +46,7 @@ namespace X86 { COND_O = 13, COND_P = 14, COND_S = 15, + LAST_VALID_COND = COND_S, // Artificial condition codes. These are used by AnalyzeBranch // to indicate a block terminated with two conditional branches to @@ -61,12 +62,16 @@ namespace X86 { // Turn condition code into conditional branch opcode. unsigned GetCondBranchFromCond(CondCode CC); + /// \brief Return a set opcode for the given condition and whether it has + /// a memory operand. + unsigned getSETFromCond(CondCode CC, bool HasMemoryOperand = false); + // Turn CMov opcode into condition code. CondCode getCondFromCMovOpc(unsigned Opc); /// GetOppositeBranchCondition - Return the inverse of the specified cond, /// e.g. turning COND_E to COND_NE. - CondCode GetOppositeBranchCondition(X86::CondCode CC); + CondCode GetOppositeBranchCondition(CondCode CC); } // end namespace X86; diff --git a/test/CodeGen/X86/fast-isel-cmp-branch2.ll b/test/CodeGen/X86/fast-isel-cmp-branch2.ll new file mode 100644 index 00000000000..7e45c49f48f --- /dev/null +++ b/test/CodeGen/X86/fast-isel-cmp-branch2.ll @@ -0,0 +1,294 @@ +; RUN: llc < %s -mtriple=x86_64-apple-darwin10 | FileCheck %s +; RUN: llc < %s -fast-isel -fast-isel-abort -mtriple=x86_64-apple-darwin10 | FileCheck %s + +define i32 @fcmp_oeq(float %x, float %y) { +; CHECK-LABEL: fcmp_oeq +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jne {{LBB.+_1}} +; CHECK-NEXT: jnp {{LBB.+_2}} + %1 = fcmp oeq float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ogt(float %x, float %y) { +; CHECK-LABEL: fcmp_ogt +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jbe {{LBB.+_1}} + %1 = fcmp ogt float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_oge(float %x, float %y) { +; CHECK-LABEL: fcmp_oge +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jb {{LBB.+_1}} + %1 = fcmp oge float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_olt(float %x, float %y) { +; CHECK-LABEL: fcmp_olt +; CHECK: ucomiss %xmm0, %xmm1 +; CHECK-NEXT: jbe {{LBB.+_1}} + %1 = fcmp olt float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ole(float %x, float %y) { +; CHECK-LABEL: fcmp_ole +; CHECK: ucomiss %xmm0, %xmm1 +; CHECK-NEXT: jb {{LBB.+_1}} + %1 = fcmp ole float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_one(float %x, float %y) { +; CHECK-LABEL: fcmp_one +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: je {{LBB.+_1}} + %1 = fcmp one float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ord(float %x, float %y) { +; CHECK-LABEL: fcmp_ord +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jp {{LBB.+_1}} + %1 = fcmp ord float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_uno(float %x, float %y) { +; CHECK-LABEL: fcmp_uno +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jp {{LBB.+_2}} + %1 = fcmp uno float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ueq(float %x, float %y) { +; CHECK-LABEL: fcmp_ueq +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: je {{LBB.+_2}} + %1 = fcmp ueq float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ugt(float %x, float %y) { +; CHECK-LABEL: fcmp_ugt +; CHECK: ucomiss %xmm0, %xmm1 +; CHECK-NEXT: jae {{LBB.+_1}} + %1 = fcmp ugt float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_uge(float %x, float %y) { +; CHECK-LABEL: fcmp_uge +; CHECK: ucomiss %xmm0, %xmm1 +; CHECK-NEXT: ja {{LBB.+_1}} + %1 = fcmp uge float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ult(float %x, float %y) { +; CHECK-LABEL: fcmp_ult +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jae {{LBB.+_1}} + %1 = fcmp ult float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_ule(float %x, float %y) { +; CHECK-LABEL: fcmp_ule +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: ja {{LBB.+_1}} + %1 = fcmp ule float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @fcmp_une(float %x, float %y) { +; CHECK-LABEL: fcmp_une +; CHECK: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: jne {{LBB.+_2}} +; CHECK-NEXT: jp {{LBB.+_2}} +; CHECK-NEXT: jmp {{LBB.+_1}} + %1 = fcmp une float %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_eq(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_eq +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jne {{LBB.+_1}} + %1 = icmp eq i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_ne(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_ne +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: je {{LBB.+_1}} + %1 = icmp ne i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_ugt(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_ugt +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jbe {{LBB.+_1}} + %1 = icmp ugt i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_uge(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_uge +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jb {{LBB.+_1}} + %1 = icmp uge i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_ult(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_ult +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jae {{LBB.+_1}} + %1 = icmp ult i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_ule(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_ule +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: ja {{LBB.+_1}} + %1 = icmp ule i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_sgt(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_sgt +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jle {{LBB.+_1}} + %1 = icmp sgt i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_sge(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_sge +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jl {{LBB.+_1}} + %1 = icmp sge i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_slt(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_slt +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jge {{LBB.+_1}} + %1 = icmp slt i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + +define i32 @icmp_sle(i32 %x, i32 %y) { +; CHECK-LABEL: icmp_sle +; CHECK: cmpl %esi, %edi +; CHECK-NEXT: jg {{LBB.+_1}} + %1 = icmp sle i32 %x, %y + br i1 %1, label %bb1, label %bb2 +bb2: + ret i32 1 +bb1: + ret i32 0 +} + diff --git a/test/CodeGen/X86/fast-isel-cmp.ll b/test/CodeGen/X86/fast-isel-cmp.ll new file mode 100644 index 00000000000..edf1263a3ea --- /dev/null +++ b/test/CodeGen/X86/fast-isel-cmp.ll @@ -0,0 +1,272 @@ +; RUN: llc < %s -mtriple=x86_64-apple-darwin10 | FileCheck %s --check-prefix=SDAG +; RUN: llc < %s -fast-isel -fast-isel-abort -mtriple=x86_64-apple-darwin10 | FileCheck %s --check-prefix=FAST + +define zeroext i1 @fcmp_oeq(float %x, float %y) { +; SDAG-LABEL: fcmp_oeq +; SDAG: cmpeqss %xmm1, %xmm0 +; SDAG-NEXT: movd %xmm0, %eax +; SDAG-NEXT: andl $1, %eax +; FAST-LABEL: fcmp_oeq +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: sete %al +; FAST-NEXT: setnp %cl +; FAST-NEXT: andb %al, %cl + %1 = fcmp oeq float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ogt(float %x, float %y) { +; SDAG-LABEL: fcmp_ogt +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: seta %al +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: seta %al + %1 = fcmp ogt float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_oge(float %x, float %y) { +; SDAG-LABEL: fcmp_oge +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: setae %al +; FAST-LABEL: fcmp_oge +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setae %al + %1 = fcmp oge float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_olt(float %x, float %y) { +; SDAG-LABEL: fcmp_olt +; SDAG: ucomiss %xmm0, %xmm1 +; SDAG-NEXT: seta %al +; FAST-LABEL: fcmp_olt +; FAST: ucomiss %xmm0, %xmm1 +; FAST-NEXT: seta %al + %1 = fcmp olt float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ole(float %x, float %y) { +; SDAG-LABEL: fcmp_ole +; SDAG: ucomiss %xmm0, %xmm1 +; SDAG-NEXT: setae %al +; FAST-LABEL: fcmp_ole +; FAST: ucomiss %xmm0, %xmm1 +; FAST-NEXT: setae %al + %1 = fcmp ole float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_one(float %x, float %y) { +; SDAG-LABEL: fcmp_one +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: setne %al +; FAST-LABEL: fcmp_one +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setne %al + %1 = fcmp one float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ord(float %x, float %y) { +; SDAG-LABEL: fcmp_ord +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: setnp %al +; FAST-LABEL: fcmp_ord +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setnp %al + %1 = fcmp ord float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_uno(float %x, float %y) { +; SDAG-LABEL: fcmp_uno +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: setp %al +; FAST-LABEL: fcmp_uno +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setp %al + %1 = fcmp uno float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ueq(float %x, float %y) { +; SDAG-LABEL: fcmp_ueq +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: sete %al +; FAST-LABEL: fcmp_ueq +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: sete %al + %1 = fcmp ueq float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ugt(float %x, float %y) { +; SDAG-LABEL: fcmp_ugt +; SDAG: ucomiss %xmm0, %xmm1 +; SDAG-NEXT: setb %al +; FAST-LABEL: fcmp_ugt +; FAST: ucomiss %xmm0, %xmm1 +; FAST-NEXT: setb %al + %1 = fcmp ugt float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_uge(float %x, float %y) { +; SDAG-LABEL: fcmp_uge +; SDAG: ucomiss %xmm0, %xmm1 +; SDAG-NEXT: setbe %al +; FAST-LABEL: fcmp_uge +; FAST: ucomiss %xmm0, %xmm1 +; FAST-NEXT: setbe %al + %1 = fcmp uge float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ult(float %x, float %y) { +; SDAG-LABEL: fcmp_ult +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: setb %al +; FAST-LABEL: fcmp_ult +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setb %al + %1 = fcmp ult float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_ule(float %x, float %y) { +; SDAG-LABEL: fcmp_ule +; SDAG: ucomiss %xmm1, %xmm0 +; SDAG-NEXT: setbe %al +; FAST-LABEL: fcmp_ule +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setbe %al + %1 = fcmp ule float %x, %y + ret i1 %1 +} + +define zeroext i1 @fcmp_une(float %x, float %y) { +; SDAG-LABEL: fcmp_une +; SDAG: cmpneqss %xmm1, %xmm0 +; SDAG-NEXT: movd %xmm0, %eax +; SDAG-NEXT: andl $1, %eax +; FAST-LABEL: fcmp_une +; FAST: ucomiss %xmm1, %xmm0 +; FAST-NEXT: setne %al +; FAST-NEXT: setp %cl +; FAST-NEXT: andb %al, %cl + %1 = fcmp une float %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_eq(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_eq +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: sete %al +; FAST-LABEL: icmp_eq +; FAST: cmpl %esi, %edi +; FAST-NEXT: sete %al + %1 = icmp eq i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_ne(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_ne +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setne %al +; FAST-LABEL: icmp_ne +; FAST: cmpl %esi, %edi +; FAST-NEXT: setne %al + %1 = icmp ne i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_ugt(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_ugt +; SDAG: cmpl %edi, %esi +; SDAG-NEXT: setb %al +; FAST-LABEL: icmp_ugt +; FAST: cmpl %esi, %edi +; FAST-NEXT: seta %al + %1 = icmp ugt i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_uge(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_uge +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setae %al +; FAST-LABEL: icmp_uge +; FAST: cmpl %esi, %edi +; FAST-NEXT: setae %al + %1 = icmp uge i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_ult(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_ult +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setb %al +; FAST-LABEL: icmp_ult +; FAST: cmpl %esi, %edi +; FAST-NEXT: setb %al + %1 = icmp ult i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_ule(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_ule +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setbe %al +; FAST-LABEL: icmp_ule +; FAST: cmpl %esi, %edi +; FAST-NEXT: setbe %al + %1 = icmp ule i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_sgt(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_sgt +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setg %al +; FAST-LABEL: icmp_sgt +; FAST: cmpl %esi, %edi +; FAST-NEXT: setg %al + %1 = icmp sgt i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_sge(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_sge +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setge %al +; FAST-LABEL: icmp_sge +; FAST: cmpl %esi, %edi +; FAST-NEXT: setge %al + %1 = icmp sge i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_slt(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_slt +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setl %al +; FAST-LABEL: icmp_slt +; FAST: cmpl %esi, %edi +; FAST-NEXT: setl %al + %1 = icmp slt i32 %x, %y + ret i1 %1 +} + +define zeroext i1 @icmp_sle(i32 %x, i32 %y) { +; SDAG-LABEL: icmp_sle +; SDAG: cmpl %esi, %edi +; SDAG-NEXT: setle %al +; FAST-LABEL: icmp_sle +; FAST: cmpl %esi, %edi +; FAST-NEXT: setle %al + %1 = icmp sle i32 %x, %y + ret i1 %1 +} +