fsel generation for f32 and f64 select
authorNate Begeman <natebegeman@mac.com>
Thu, 31 Mar 2005 23:55:40 +0000 (23:55 +0000)
committerNate Begeman <natebegeman@mac.com>
Thu, 31 Mar 2005 23:55:40 +0000 (23:55 +0000)
generate compare immediate for integer compare with constant
fold setcc into branch
fold setcc into select

Code generation quality for Shootout is now on par with the Simple ISel

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@20968 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/PowerPC/PPCISelPattern.cpp

index bfb03275eb8ed9b0af4e0f4fe3688438f1c8ac0d..22b3276bb5cd74dd87aaf0a052c8b3bfd9e317ac 100644 (file)
@@ -54,6 +54,9 @@ namespace {
       setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand);
       setOperationAction(ISD::SEXTLOAD, MVT::i8, Expand);
 
+      addLegalFPImmediate(+0.0); // Necessary for FSEL
+      addLegalFPImmediate(-0.0); // 
+
       computeRegisterProperties();
     }
 
@@ -478,7 +481,7 @@ public:
 /// placed in Imm.
 ///
 static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
-                                           unsigned& Imm) {
+                                           unsigned& Imm, bool U = false) {
   if (N.getOpcode() != ISD::Constant) return 0;
 
   int v = (int)cast<ConstantSDNode>(N)->getSignExtended();
@@ -498,9 +501,33 @@ static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
   case ISD::MUL:
     if (v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
     break;
+  case ISD::SETCC:
+    if (U && (v >= 0 && v <= 65535)) { Imm = v & 0xFFFF; return 1; }
+    if (!U && (v <= 32767 && v >= -32768)) { Imm = v & 0xFFFF; return 1; }
+    break;
   }
   return 0;
 }
+
+/// getBCCForSetCC - Returns the PowerPC condition branch mnemonic corresponding
+/// to Condition.  If the Condition is unordered or unsigned, the bool argument
+/// U is set to true, otherwise it is set to false.
+static unsigned getBCCForSetCC(unsigned Condition, bool& U) {
+  U = false;
+  switch (Condition) {
+  default: assert(0 && "Unknown condition!"); abort();
+  case ISD::SETEQ:  return PPC::BEQ;
+  case ISD::SETNE:  return PPC::BNE;
+  case ISD::SETULT: U = true;
+  case ISD::SETLT:  return PPC::BLT;
+  case ISD::SETULE: U = true;
+  case ISD::SETLE:  return PPC::BLE;
+  case ISD::SETUGT: U = true;
+  case ISD::SETGT:  return PPC::BGT;
+  case ISD::SETUGE: U = true;
+  case ISD::SETGE:  return PPC::BGE;
+  }
+}
 }
 
 /// getGlobalBaseReg - Output the instructions required to put the
@@ -539,15 +566,39 @@ void ISel::SelectBranchCC(SDOperand N)
   assert(N.getOpcode() == ISD::BRCOND && "Not a BranchCC???");
   MachineBasicBlock *Dest = 
     cast<BasicBlockSDNode>(N.getOperand(2))->getBasicBlock();
-  unsigned Opc;
-  
+
+  unsigned Opc, Tmp1, Tmp2;
   Select(N.getOperand(0));  //chain
-  SDOperand CC = N.getOperand(1);
-  
-  //Give up and do the stupid thing
-  unsigned Tmp1 = SelectExpr(CC);
-  BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
-  BuildMI(BB, PPC::BNE, 2).addReg(PPC::CR0).addMBB(Dest);
+
+  // If the first operand to the select is a SETCC node, then we can fold it
+  // into the branch that selects which value to return.
+  SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(1).Val);
+  if (SetCC && N.getOperand(1).getOpcode() == ISD::SETCC &&
+      MVT::isInteger(SetCC->getOperand(0).getValueType())) {
+    bool U;
+    Opc = getBCCForSetCC(SetCC->getCondition(), U);
+    Tmp1 = SelectExpr(SetCC->getOperand(0));
+
+    // Pass the optional argument U to canUseAsImmediateForOpcode for SETCC,
+    // so that it knows whether the SETCC immediate range is signed or not.
+    if (1 == canUseAsImmediateForOpcode(SetCC->getOperand(1), ISD::SETCC, 
+                                        Tmp2, U)) {
+      if (U)
+        BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(Tmp2);
+      else
+        BuildMI(BB, PPC::CMPWI, 2, PPC::CR0).addReg(Tmp1).addSImm(Tmp2);
+    } else {
+      Tmp2 = SelectExpr(SetCC->getOperand(1));
+      BuildMI(BB, U ? PPC::CMPLW : PPC::CMPW, 2, PPC::CR0).addReg(Tmp1)
+      .addReg(Tmp2);
+    }
+  } else {
+    Tmp1 = SelectExpr(N.getOperand(1));
+    BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
+    Opc = PPC::BNE;
+  }
+
+  BuildMI(BB, Opc, 2).addReg(PPC::CR0).addMBB(Dest);
   return;
 }
 
@@ -565,10 +616,77 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
     assert(0 && "Node not handled!\n");
 
   case ISD::SELECT: {
-    Tmp1 = SelectExpr(N.getOperand(0)); //Cond
-
-    // FIXME: generate FSEL here
-
+    // Attempt to generate FSEL.  We can do this whenever we have an FP result,
+    // and an FP comparison in the SetCC node.
+    SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(0).Val);
+    if (SetCC && N.getOperand(0).getOpcode() == ISD::SETCC &&
+        !MVT::isInteger(SetCC->getOperand(0).getValueType()) &&
+        SetCC->getCondition() != ISD::SETEQ &&
+        SetCC->getCondition() != ISD::SETNE) {
+      MVT::ValueType VT = SetCC->getOperand(0).getValueType();
+      Tmp1 = SelectExpr(SetCC->getOperand(0));   // Val to compare against
+      unsigned TV = SelectExpr(N.getOperand(1)); // Use if TRUE
+      unsigned FV = SelectExpr(N.getOperand(2)); // Use if FALSE
+      
+      ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(SetCC->getOperand(1));
+      if (CN && (CN->isExactlyValue(-0.0) || CN->isExactlyValue(0.0))) {
+        switch(SetCC->getCondition()) {
+        default: assert(0 && "Invalid FSEL condition"); abort();
+        case ISD::SETULT:
+        case ISD::SETLT:
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp1).addReg(FV).addReg(TV);
+          return Result;
+        case ISD::SETUGE:
+        case ISD::SETGE:
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp1).addReg(TV).addReg(FV);
+          return Result;
+        case ISD::SETUGT:
+        case ISD::SETGT: {
+          Tmp2 = MakeReg(VT);
+          BuildMI(BB, PPC::FNEG, 1, Tmp2).addReg(Tmp1);
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp2).addReg(FV).addReg(TV);
+          return Result;
+        }
+        case ISD::SETULE:
+        case ISD::SETLE: {
+          Tmp2 = MakeReg(VT);
+          BuildMI(BB, PPC::FNEG, 1, Tmp2).addReg(Tmp1);
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp2).addReg(TV).addReg(FV);
+          return Result;
+        }
+        }
+      } else {
+        Opc = (MVT::f64 == VT) ? PPC::FSUB : PPC::FSUBS;
+        Tmp2 = SelectExpr(SetCC->getOperand(1));
+        Tmp3 =  MakeReg(VT);
+        switch(SetCC->getCondition()) {
+        default: assert(0 && "Invalid FSEL condition"); abort();
+        case ISD::SETULT:
+        case ISD::SETLT:
+          BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(FV).addReg(TV);
+          return Result;
+        case ISD::SETUGE:
+        case ISD::SETGE:
+          BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(TV).addReg(FV);
+          return Result;
+        case ISD::SETUGT:
+        case ISD::SETGT:
+          BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(FV).addReg(TV);
+          return Result;
+        case ISD::SETULE:
+        case ISD::SETLE:
+          BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
+          BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(TV).addReg(FV);
+          return Result;
+        }
+      }
+      assert(0 && "Should never get here");
+      return 0;
+    }
+    
     // Create an iterator with which to insert the MBB for copying the false 
     // value and the MBB to hold the PHI instruction for this SetCC.
     MachineBasicBlock *thisMBB = BB;
@@ -582,6 +700,7 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
     //   cmpTY cr0, r1, r2
     //   bCC copy1MBB
     //   fallthrough --> copy0MBB
+    Tmp1 = SelectExpr(N.getOperand(0)); //Cond
     BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
     MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
     MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
@@ -1085,24 +1204,29 @@ unsigned ISel::SelectExpr(SDOperand N) {
       bool U = false;
       bool IsInteger = MVT::isInteger(SetCC->getOperand(0).getValueType());
       
-      switch (SetCC->getCondition()) {
-      default: Node->dump(); assert(0 && "Unknown comparison!");
-      case ISD::SETEQ:  Opc = PPC::BEQ; break;
-      case ISD::SETNE:  Opc = PPC::BNE; break;
-      case ISD::SETULT: U = true;
-      case ISD::SETLT:  Opc = PPC::BLT; break;
-      case ISD::SETULE: U = true;
-      case ISD::SETLE:  Opc = PPC::BLE; break;
-      case ISD::SETUGT: U = true;
-      case ISD::SETGT:  Opc = PPC::BGT; break;
-      case ISD::SETUGE: U = true;
-      case ISD::SETGE:  Opc = PPC::BGE; break;
-      }
-      
       // FIXME: Is there a situation in which we would ever need to emit fcmpo?
       static const unsigned CompareOpcodes[] = 
         { PPC::FCMPU, PPC::FCMPU, PPC::CMPW, PPC::CMPLW };
-      unsigned CompareOpc = CompareOpcodes[2 * IsInteger + U];
+
+      // Set the branch opcode to use below
+      Opc = getBCCForSetCC(SetCC->getCondition(), U);
+
+      // Try and use an integer compare with immediate, if applicable.  
+      // Normal setcc uses the sign-extended immediate range, unsigned setcc
+      // uses the zero extended immediate range.
+      if (IsInteger && 
+          1 == canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp2, U)) {
+        Tmp1 = SelectExpr(N.getOperand(0));
+        if (U)
+          BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(Tmp2);
+        else
+          BuildMI(BB, PPC::CMPWI, 2, PPC::CR0).addReg(Tmp1).addSImm(Tmp2);
+      } else {
+        Tmp1 = SelectExpr(N.getOperand(0));
+        Tmp2 = SelectExpr(N.getOperand(1));
+        unsigned CompareOpc = CompareOpcodes[2 * IsInteger + U];
+        BuildMI(BB, CompareOpc, 2, PPC::CR0).addReg(Tmp1).addReg(Tmp2);
+      }
       
       // Create an iterator with which to insert the MBB for copying the false 
       // value and the MBB to hold the PHI instruction for this SetCC.
@@ -1116,9 +1240,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
       //   cmpTY cr0, r1, r2
       //   %TrueValue = li 1
       //   bCC sinkMBB
-      Tmp1 = SelectExpr(N.getOperand(0));
-      Tmp2 = SelectExpr(N.getOperand(1));
-      BuildMI(BB, CompareOpc, 2, PPC::CR0).addReg(Tmp1).addReg(Tmp2);
       unsigned TrueValue = MakeReg(MVT::i32);
       BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1);
       MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
@@ -1152,8 +1273,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
     return 0;
     
   case ISD::SELECT: {
-    Tmp1 = SelectExpr(N.getOperand(0)); //Cond
-
     // Create an iterator with which to insert the MBB for copying the false 
     // value and the MBB to hold the PHI instruction for this SetCC.
     MachineBasicBlock *thisMBB = BB;
@@ -1161,17 +1280,44 @@ unsigned ISel::SelectExpr(SDOperand N) {
     ilist<MachineBasicBlock>::iterator It = BB;
     ++It;
 
+    // If the first operand to the select is a SETCC node, then we can fold it
+    // into the branch that selects which value to return.
+    SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(0).Val);
+    if (SetCC && N.getOperand(0).getOpcode() == ISD::SETCC &&
+        MVT::isInteger(SetCC->getOperand(0).getValueType())) {
+      bool U;
+      Opc = getBCCForSetCC(SetCC->getCondition(), U);
+      Tmp1 = SelectExpr(SetCC->getOperand(0));
+
+      // Pass the optional argument U to canUseAsImmediateForOpcode for SETCC,
+      // so that it knows whether the SETCC immediate range is signed or not.
+      if (1 == canUseAsImmediateForOpcode(SetCC->getOperand(1), ISD::SETCC, 
+                                          Tmp2, U)) {
+        if (U)
+          BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(Tmp2);
+        else
+          BuildMI(BB, PPC::CMPWI, 2, PPC::CR0).addReg(Tmp1).addSImm(Tmp2);
+      } else {
+        Tmp2 = SelectExpr(SetCC->getOperand(1));
+        BuildMI(BB, U ? PPC::CMPLW : PPC::CMPW, 2, PPC::CR0).addReg(Tmp1)
+          .addReg(Tmp2);
+      }
+    } else {
+      Tmp1 = SelectExpr(N.getOperand(0)); //Cond
+      BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
+      Opc = PPC::BNE;
+    }
+
     //  thisMBB:
     //  ...
     //   TrueVal = ...
     //   cmpTY cr0, r1, r2
     //   bCC copy1MBB
     //   fallthrough --> copy0MBB
-    BuildMI(BB, PPC::CMPLWI, 2, PPC::CR0).addReg(Tmp1).addImm(0);
     MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
     MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
     unsigned TrueValue = SelectExpr(N.getOperand(1)); //Use if TRUE
-    BuildMI(BB, PPC::BNE, 2).addReg(PPC::CR0).addMBB(sinkMBB);
+    BuildMI(BB, Opc, 2).addReg(PPC::CR0).addMBB(sinkMBB);
     MachineFunction *F = BB->getParent();
     F->getBasicBlockList().insert(It, copy0MBB);
     F->getBasicBlockList().insert(It, sinkMBB);