From 24aad1b0c1e6fd6daba1f5e2167a119b428b1cae Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 10 Jan 2005 22:10:13 +0000 Subject: [PATCH] Fold setcc instructions into selects. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19438 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86ISelPattern.cpp | 134 ++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 18 deletions(-) diff --git a/lib/Target/X86/X86ISelPattern.cpp b/lib/Target/X86/X86ISelPattern.cpp index 4c093fba3b9..bc451a184bb 100644 --- a/lib/Target/X86/X86ISelPattern.cpp +++ b/lib/Target/X86/X86ISelPattern.cpp @@ -1,5 +1,5 @@ //===-- X86ISelPattern.cpp - A pattern matching inst selector for X86 -----===// -// +// // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under @@ -348,6 +348,8 @@ namespace { void EmitCMP(SDOperand LHS, SDOperand RHS); bool EmitBranchCC(MachineBasicBlock *Dest, SDOperand Cond); + void EmitSelectCC(SDOperand Cond, MVT::ValueType SVT, + unsigned RTrue, unsigned RFalse, unsigned RDest); unsigned SelectExpr(SDOperand N); bool SelectAddress(SDOperand N, X86AddressMode &AM); void Select(SDOperand N); @@ -622,6 +624,116 @@ bool ISel::EmitBranchCC(MachineBasicBlock *Dest, SDOperand Cond) { return false; } +/// EmitSelectCC - Emit code into BB that performs a select operation between +/// the two registers RTrue and RFalse, generating a result into RDest. Return +/// true if the fold cannot be performed. +/// +void ISel::EmitSelectCC(SDOperand Cond, MVT::ValueType SVT, + unsigned RTrue, unsigned RFalse, unsigned RDest) { + enum Condition { + EQ, NE, LT, LE, GT, GE, B, BE, A, AE, P, NP, + NOT_SET + } CondCode = NOT_SET; + + static const unsigned CMOVTAB16[] = { + X86::CMOVE16rr, X86::CMOVNE16rr, X86::CMOVL16rr, X86::CMOVLE16rr, + X86::CMOVG16rr, X86::CMOVGE16rr, X86::CMOVB16rr, X86::CMOVBE16rr, + X86::CMOVA16rr, X86::CMOVAE16rr, X86::CMOVP16rr, X86::CMOVNP16rr, + }; + static const unsigned CMOVTAB32[] = { + X86::CMOVE32rr, X86::CMOVNE32rr, X86::CMOVL32rr, X86::CMOVLE32rr, + X86::CMOVG32rr, X86::CMOVGE32rr, X86::CMOVB32rr, X86::CMOVBE32rr, + X86::CMOVA32rr, X86::CMOVAE32rr, X86::CMOVP32rr, X86::CMOVNP32rr, + }; + static const unsigned CMOVTABFP[] = { + X86::FCMOVE , X86::FCMOVNE, /*missing*/0, /*missing*/0, + /*missing*/0, /*missing*/0, X86::FCMOVB , X86::FCMOVBE, + X86::FCMOVA , X86::FCMOVAE, X86::FCMOVP , X86::FCMOVNP + }; + + if (SetCCSDNode *SetCC = dyn_cast(Cond)) { + if (MVT::isInteger(SetCC->getOperand(0).getValueType())) { + switch (SetCC->getCondition()) { + default: assert(0 && "Unknown integer comparison!"); + case ISD::SETEQ: CondCode = EQ; break; + case ISD::SETGT: CondCode = GT; break; + case ISD::SETGE: CondCode = GE; break; + case ISD::SETLT: CondCode = LT; break; + case ISD::SETLE: CondCode = LE; break; + case ISD::SETNE: CondCode = NE; break; + case ISD::SETULT: CondCode = B; break; + case ISD::SETUGT: CondCode = A; break; + case ISD::SETULE: CondCode = BE; break; + case ISD::SETUGE: CondCode = AE; break; + } + } else { + // On a floating point condition, the flags are set as follows: + // ZF PF CF op + // 0 | 0 | 0 | X > Y + // 0 | 0 | 1 | X < Y + // 1 | 0 | 0 | X == Y + // 1 | 1 | 1 | unordered + // + switch (SetCC->getCondition()) { + default: assert(0 && "Unknown FP comparison!"); + case ISD::SETUEQ: + case ISD::SETEQ: CondCode = EQ; break; // True if ZF = 1 + case ISD::SETOGT: + case ISD::SETGT: CondCode = A; break; // True if CF = 0 and ZF = 0 + case ISD::SETOGE: + case ISD::SETGE: CondCode = AE; break; // True if CF = 0 + case ISD::SETULT: + case ISD::SETLT: CondCode = B; break; // True if CF = 1 + case ISD::SETULE: + case ISD::SETLE: CondCode = BE; break; // True if CF = 1 or ZF = 1 + case ISD::SETONE: + case ISD::SETNE: CondCode = NE; break; // True if ZF = 0 + case ISD::SETUO: CondCode = P; break; // True if PF = 1 + case ISD::SETO: CondCode = NP; break; // True if PF = 0 + case ISD::SETUGT: // PF = 1 | (ZF = 0 & CF = 0) + case ISD::SETUGE: // PF = 1 | CF = 0 + case ISD::SETUNE: // PF = 1 | ZF = 0 + case ISD::SETOEQ: // PF = 0 & ZF = 1 + case ISD::SETOLT: // PF = 0 & CF = 1 + case ISD::SETOLE: // PF = 0 & (CF = 1 || ZF = 1) + // We cannot emit this comparison as a single cmov. + break; + } + } + } + + unsigned Opc = 0; + if (CondCode != NOT_SET) { + switch (SVT) { + default: assert(0 && "Cannot select this type!"); + case MVT::i16: Opc = CMOVTAB16[CondCode]; break; + case MVT::i32: Opc = CMOVTAB32[CondCode]; break; + case MVT::f32: + case MVT::f64: Opc = CMOVTABFP[CondCode]; ContainsFPCode = true; break; + } + } + + // Finally, if we weren't able to fold this, just emit the condition and test + // it. + if (CondCode == NOT_SET || Opc == 0) { + // Get the condition into the zero flag. + unsigned CondReg = SelectExpr(Cond); + BuildMI(BB, X86::TEST8rr, 2).addReg(CondReg).addReg(CondReg); + + switch (SVT) { + default: assert(0 && "Cannot select this type!"); + case MVT::i16: Opc = X86::CMOVE16rr; break; + case MVT::i32: Opc = X86::CMOVE32rr; break; + case MVT::f32: + case MVT::f64: Opc = X86::FCMOVE; ContainsFPCode = true; break; + } + } else { + // FIXME: CMP R, 0 -> TEST R, R + EmitCMP(Cond.getOperand(0), Cond.getOperand(1)); + } + BuildMI(BB, Opc, 2, RDest).addReg(RTrue).addReg(RFalse); +} + void ISel::EmitCMP(SDOperand LHS, SDOperand RHS) { unsigned Tmp1 = SelectExpr(LHS), Opc; if (ConstantSDNode *CN = dyn_cast(RHS)) { @@ -1232,19 +1344,7 @@ unsigned ISel::SelectExpr(SDOperand N) { if (N.getValueType() != MVT::i1 && N.getValueType() != MVT::i8) { Tmp2 = SelectExpr(N.getOperand(1)); Tmp3 = SelectExpr(N.getOperand(2)); - Tmp1 = SelectExpr(N.getOperand(0)); - - switch (N.getValueType()) { - default: assert(0 && "Cannot select this type!"); - case MVT::i16: Opc = X86::CMOVE16rr; break; - case MVT::i32: Opc = X86::CMOVE32rr; break; - case MVT::f32: - case MVT::f64: Opc = X86::FCMOVE; ContainsFPCode = true; break; - } - - // Get the condition into the zero flag. - BuildMI(BB, X86::TEST8rr, 2).addReg(Tmp1).addReg(Tmp1); - BuildMI(BB, Opc, 2, Result).addReg(Tmp2).addReg(Tmp3); + EmitSelectCC(N.getOperand(0), N.getValueType(), Tmp2, Tmp3, Result); return Result; } else { // FIXME: This should not be implemented here, it should be in the generic @@ -1253,11 +1353,9 @@ unsigned ISel::SelectExpr(SDOperand N) { N.getOperand(1))); Tmp3 = SelectExpr(CurDAG->getNode(ISD::ZERO_EXTEND, MVT::i16, N.getOperand(2))); - Tmp1 = SelectExpr(N.getOperand(0)); - BuildMI(BB, X86::TEST8rr, 2).addReg(Tmp1).addReg(Tmp1); - // FIXME: need subregs to do better than this! unsigned TmpReg = MakeReg(MVT::i16); - BuildMI(BB, X86::CMOVE16rr, 2, TmpReg).addReg(Tmp2).addReg(Tmp3); + EmitSelectCC(N.getOperand(0), MVT::i16, Tmp2, Tmp3, TmpReg); + // FIXME: need subregs to do better than this! BuildMI(BB, X86::MOV16rr, 1, X86::AX).addReg(TmpReg); BuildMI(BB, X86::MOV8rr, 1, Result).addReg(X86::AL); return Result; -- 2.34.1