Implement SDIV by power of 2 as srawi/addze rather than load imm, divw
[oota-llvm.git] / lib / Target / PowerPC / PPCISelPattern.cpp
index 88ad79dbc8edfb3337838016553ddaa57ee758db..3b599c580ef04035395a61b345948f7be56e98f7 100644 (file)
@@ -25,6 +25,7 @@
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/ADT/Statistic.h"
@@ -172,8 +173,13 @@ PPC32TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
     // We need to load the argument to a virtual register if we determined above
     // that we ran out of physical registers of the appropriate type 
     if (needsLoad) {
+      unsigned SubregOffset = 0;
+      if (ObjectVT == MVT::i8 || ObjectVT == MVT::i1) SubregOffset = 3;
+      if (ObjectVT == MVT::i16) SubregOffset = 2;
       int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
       SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
+      FIN = DAG.getNode(ISD::ADD, MVT::i32, FIN, 
+                        DAG.getConstant(SubregOffset, MVT::i32));
       argt = newroot = DAG.getLoad(ObjectVT, DAG.getEntryNode(), FIN);
     }
     
@@ -192,8 +198,25 @@ PPC32TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
 
   // If the function takes variable number of arguments, make a frame index for
   // the start of the first vararg value... for expansion of llvm.va_start.
-  if (F.isVarArg())
+  if (F.isVarArg()) {
     VarArgsFrameIndex = MFI->CreateFixedObject(4, ArgOffset);
+    SDOperand FIN = DAG.getFrameIndex(VarArgsFrameIndex, MVT::i32);
+    // If this function is vararg, store any remaining integer argument regs
+    // to their spots on the stack so that they may be loaded by deferencing the
+    // result of va_next.
+    std::vector<SDOperand> MemOps;
+    for (; GPR_remaining > 0; --GPR_remaining, ++GPR_idx) {
+      BuildMI(&BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]);
+      SDOperand Val = DAG.getCopyFromReg(GPR[GPR_idx], MVT::i32, DAG.getRoot());
+      SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1), 
+                                    Val, FIN);
+      MemOps.push_back(Store);
+      // Increment the address by four for the next argument to store
+      SDOperand PtrOff = DAG.getConstant(4, getPointerTy());
+      FIN = DAG.getNode(ISD::ADD, MVT::i32, FIN, PtrOff);
+    }
+    DAG.setRoot(DAG.getNode(ISD::TokenFactor, MVT::Other, MemOps));
+  }
 
   return ArgValues;
 }
@@ -410,6 +433,7 @@ LowerFrameReturnAddress(bool isFrameAddress, SDOperand Chain, unsigned Depth,
 
 namespace {
 Statistic<>NotLogic("ppc-codegen", "Number of inverted logical ops");
+Statistic<>FusedFP("ppc-codegen", "Number of fused fp operations");
 //===--------------------------------------------------------------------===//
 /// ISel - PPC32 specific code to select PPC32 machine instructions for
 /// SelectionDAG operations.
@@ -461,6 +485,18 @@ public:
   void SelectBranchCC(SDOperand N);
 };
 
+/// ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N.  It
+/// returns zero when the input is not exactly a power of two.
+static unsigned ExactLog2(unsigned Val) {
+  if (Val == 0 || (Val & (Val-1))) return 0;
+  unsigned Count = 0;
+  while (Val != 1) {
+    Val >>= 1;
+    ++Count;
+  }
+  return Count;
+}
+
 /// canUseAsImmediateForOpcode - This method returns a value indicating whether
 /// the ConstantSDNode N can be used as an immediate to Opcode.  The return
 /// values are either 0, 1 or 2.  0 indicates that either N is not a
@@ -496,6 +532,9 @@ static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
     if (U && (v >= 0 && v <= 65535)) { Imm = v & 0xFFFF; return 1; }
     if (!U && (v <= 32767 && v >= -32768)) { Imm = v & 0xFFFF; return 1; }
     break;
+  case ISD::SDIV:
+    if (0 != ExactLog2(v)) { Imm = ExactLog2(v); return 1; }
+    break;
   }
   return 0;
 }
@@ -761,7 +800,29 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
   }
 
   case ISD::FNEG:
-    if (ISD::FABS == N.getOperand(0).getOpcode()) {
+    if (!NoExcessFPPrecision && 
+        ISD::ADD == N.getOperand(0).getOpcode() &&
+        N.getOperand(0).Val->hasOneUse() &&
+        ISD::MUL == N.getOperand(0).getOperand(0).getOpcode() &&
+        N.getOperand(0).getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(0).getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FNMADD : PPC::FNMADDS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+    } else if (!NoExcessFPPrecision && 
+        ISD::SUB == N.getOperand(0).getOpcode() &&
+        N.getOperand(0).Val->hasOneUse() &&
+        ISD::MUL == N.getOperand(0).getOperand(0).getOpcode() &&
+        N.getOperand(0).getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(0).getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FNMSUB : PPC::FNMSUBS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+    } else if (ISD::FABS == N.getOperand(0).getOpcode()) {
       Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
       BuildMI(BB, PPC::FNABS, 1, Result).addReg(Tmp1);
     } else {
@@ -804,14 +865,44 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
     return Result;
   }
     
-  case ISD::MUL:
   case ISD::ADD:
+    if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::MUL &&
+        N.getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FMADD : PPC::FMADDS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+      return Result;
+    }
+    Opc = DestType == MVT::f64 ? PPC::FADD : PPC::FADDS;
+    Tmp1 = SelectExpr(N.getOperand(0));
+    Tmp2 = SelectExpr(N.getOperand(1));
+    BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
+    return Result;
+
   case ISD::SUB:
+    if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::MUL &&
+        N.getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FMSUB : PPC::FMSUBS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+      return Result;
+    }
+    Opc = DestType == MVT::f64 ? PPC::FSUB : PPC::FSUBS;
+    Tmp1 = SelectExpr(N.getOperand(0));
+    Tmp2 = SelectExpr(N.getOperand(1));
+    BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
+    return Result;
+
+  case ISD::MUL:
   case ISD::SDIV:
     switch( opcode ) {
     case ISD::MUL:  Opc = DestType == MVT::f64 ? PPC::FMUL : PPC::FMULS; break;
-    case ISD::ADD:  Opc = DestType == MVT::f64 ? PPC::FADD : PPC::FADDS; break;
-    case ISD::SUB:  Opc = DestType == MVT::f64 ? PPC::FSUB : PPC::FSUBS; break;
     case ISD::SDIV: Opc = DestType == MVT::f64 ? PPC::FDIV : PPC::FDIVS; break;
     };
     Tmp1 = SelectExpr(N.getOperand(0));
@@ -916,6 +1007,9 @@ unsigned ISel::SelectExpr(SDOperand N) {
     break;
   }
 
+  if (ISD::CopyFromReg == opcode)
+    DestType = N.getValue(0).getValueType();
+    
   if (DestType == MVT::f64 || DestType == MVT::f32)
     if (ISD::LOAD != opcode && ISD::EXTLOAD != opcode && ISD::UNDEF != opcode)
       return SelectExprFP(N, Result);
@@ -1044,6 +1138,24 @@ unsigned ISel::SelectExpr(SDOperand N) {
     Select(N.getOperand(0));
     ExprMap[N.getValue(Node->getNumValues()-1)] = 1;
 
+    MachineInstr *CallMI;
+    // Emit the correct call instruction based on the type of symbol called.
+    if (GlobalAddressSDNode *GASD = 
+        dyn_cast<GlobalAddressSDNode>(N.getOperand(1))) {
+      CallMI = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(GASD->getGlobal(), 
+                                                           true);
+    } else if (ExternalSymbolSDNode *ESSDN = 
+               dyn_cast<ExternalSymbolSDNode>(N.getOperand(1))) {
+      CallMI = BuildMI(PPC::CALLpcrel, 1).addExternalSymbol(ESSDN->getSymbol(), 
+                                                            true);
+    } else {
+      Tmp1 = SelectExpr(N.getOperand(1));
+      BuildMI(BB, PPC::OR, 2, PPC::R12).addReg(Tmp1).addReg(Tmp1);
+      BuildMI(BB, PPC::MTCTR, 1).addReg(PPC::R12);
+      CallMI = BuildMI(PPC::CALLindirect, 3).addImm(20).addImm(0)
+        .addReg(PPC::R12);
+    }
+       
     // Load the register args to virtual regs
     std::vector<unsigned> ArgVR;
     for(int i = 2, e = Node->getNumOperands(); i < e; ++i)
@@ -1058,32 +1170,24 @@ unsigned ISel::SelectExpr(SDOperand N) {
       case MVT::i16:
       case MVT::i32:
         assert(GPR_idx < 8 && "Too many int args");
-        if (N.getOperand(i+2).getOpcode() != ISD::UNDEF)
+        if (N.getOperand(i+2).getOpcode() != ISD::UNDEF) {
           BuildMI(BB, PPC::OR,2,GPR[GPR_idx]).addReg(ArgVR[i]).addReg(ArgVR[i]);
+          CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
+        }
         ++GPR_idx;
         break;
       case MVT::f64:
       case MVT::f32:
         assert(FPR_idx < 13 && "Too many fp args");
         BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgVR[i]);
+        CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use);
         ++FPR_idx;
         break;
       }
     }
-
-    // Emit the correct call instruction based on the type of symbol called.
-    if (GlobalAddressSDNode *GASD = 
-        dyn_cast<GlobalAddressSDNode>(N.getOperand(1))) {
-      BuildMI(BB, PPC::CALLpcrel, 1).addGlobalAddress(GASD->getGlobal(), true);
-    } else if (ExternalSymbolSDNode *ESSDN = 
-               dyn_cast<ExternalSymbolSDNode>(N.getOperand(1))) {
-      BuildMI(BB, PPC::CALLpcrel, 1).addExternalSymbol(ESSDN->getSymbol(), true);
-    } else {
-      Tmp1 = SelectExpr(N.getOperand(1));
-      BuildMI(BB, PPC::OR, 2, PPC::R12).addReg(Tmp1).addReg(Tmp1);
-      BuildMI(BB, PPC::MTCTR, 1).addReg(PPC::R12);
-      BuildMI(BB, PPC::CALLindirect, 3).addImm(20).addImm(0).addReg(PPC::R12);
-    }
+    
+    // Put the call instruction in the correct place in the MachineBasicBlock
+    BB->push_back(CallMI);
 
     switch (Node->getValueType(0)) {
     default: assert(0 && "Unknown value type for call result!");
@@ -1092,9 +1196,12 @@ unsigned ISel::SelectExpr(SDOperand N) {
     case MVT::i8:
     case MVT::i16:
     case MVT::i32:
-      BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R3).addReg(PPC::R3);
-      if (Node->getValueType(1) == MVT::i32)
-        BuildMI(BB, PPC::OR, 2, Result+1).addReg(PPC::R4).addReg(PPC::R4);
+      if (Node->getValueType(1) == MVT::i32) {
+        BuildMI(BB, PPC::OR, 2, Result+1).addReg(PPC::R3).addReg(PPC::R3);
+        BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R4).addReg(PPC::R4);
+      } else {
+        BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R3).addReg(PPC::R3);
+      }
       break;
     case MVT::f32:
     case MVT::f64:
@@ -1295,6 +1402,13 @@ unsigned ISel::SelectExpr(SDOperand N) {
 
   case ISD::SDIV:
   case ISD::UDIV:
+    if (1 == canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp3)) {
+      Tmp1 = MakeReg(MVT::i32);
+      Tmp2 = SelectExpr(N.getOperand(0));
+      BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3);
+      BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp1);
+      return Result;
+    }
     Tmp1 = SelectExpr(N.getOperand(0));
     Tmp2 = SelectExpr(N.getOperand(1));
     Opc = (ISD::UDIV == opcode) ? PPC::DIVWU : PPC::DIVW;
@@ -1352,7 +1466,7 @@ unsigned ISel::SelectExpr(SDOperand N) {
       BuildMI(BB, PPC::SRW, 2, Tmp3).addReg(ShiftOpLo).addReg(Tmp1);
       BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
       BuildMI(BB, PPC::ADDI, 2, Tmp5).addReg(SHReg).addSImm(-32);
-      BuildMI(BB, PPC::SLW, 2, Tmp6).addReg(ShiftOpHi).addReg(Tmp5);
+      BuildMI(BB, PPC::SLW, 2, Tmp6).addReg(ShiftOpLo).addReg(Tmp5);
       BuildMI(BB, PPC::OR, 2, Result+1).addReg(Tmp4).addReg(Tmp6);
       BuildMI(BB, PPC::SLW, 2, Result).addReg(ShiftOpLo).addReg(SHReg);
     } else if (ISD::SRL_PARTS == opcode) {