add options to view the dags before the first or second pass of dag combine.
[oota-llvm.git] / lib / CodeGen / SelectionDAG / DAGCombiner.cpp
index 46f14b98df13c126d3fa4bfa7302366c86f67fdf..96bf9cd43763719f0bb0b72758d3b50c94908712 100644 (file)
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/CommandLine.h"
 #include <algorithm>
-#include <iostream>
-#include <algorithm>
 using namespace llvm;
 
+STATISTIC(NodesCombined   , "Number of dag nodes combined");
+STATISTIC(PreIndexedNodes , "Number of pre-indexed nodes created");
+STATISTIC(PostIndexedNodes, "Number of post-indexed nodes created");
+
 namespace {
-  static Statistic<> NodesCombined ("dagcombiner", 
-                                   "Number of dag nodes combined");
-            
-  static Statistic<> PreIndexedNodes ("pre_indexed_ops", 
-                                      "Number of pre-indexed nodes created");
-  static Statistic<> PostIndexedNodes ("post_indexed_ops", 
-                                       "Number of post-indexed nodes created");
-            
+#ifndef NDEBUG
+  static cl::opt<bool>
+    ViewDAGCombine1("view-dag-combine1-dags", cl::Hidden,
+                    cl::desc("Pop up a window to show dags before the first "
+                             "dag combine pass"));
+  static cl::opt<bool>
+    ViewDAGCombine2("view-dag-combine2-dags", cl::Hidden,
+                    cl::desc("Pop up a window to show dags before the second "
+                             "dag combine pass"));
+#else
+  static const bool ViewDAGCombine1 = false;
+  static const bool ViewDAGCombine2 = false;
+#endif
+  
   static cl::opt<bool>
     CombinerAA("combiner-alias-analysis", cl::Hidden,
                cl::desc("Turn on alias analysis during testing"));
@@ -101,9 +110,9 @@ namespace {
                         bool AddTo = true) {
       assert(N->getNumValues() == NumTo && "Broken CombineTo call!");
       ++NodesCombined;
-      DEBUG(std::cerr << "\nReplacing.1 "; N->dump();
-            std::cerr << "\nWith: "; To[0].Val->dump(&DAG);
-            std::cerr << " and " << NumTo-1 << " other values\n");
+      DOUT << "\nReplacing.1 "; DEBUG(N->dump());
+      DOUT << "\nWith: "; DEBUG(To[0].Val->dump(&DAG));
+      DOUT << " and " << NumTo-1 << " other values\n";
       std::vector<SDNode*> NowDead;
       DAG.ReplaceAllUsesWith(N, To, &NowDead);
       
@@ -152,9 +161,9 @@ namespace {
       
       // Replace the old value with the new one.
       ++NodesCombined;
-      DEBUG(std::cerr << "\nReplacing.2 "; TLO.Old.Val->dump();
-            std::cerr << "\nWith: "; TLO.New.Val->dump(&DAG);
-            std::cerr << '\n');
+      DOUT << "\nReplacing.2 "; DEBUG(TLO.Old.Val->dump());
+      DOUT << "\nWith: "; DEBUG(TLO.New.Val->dump(&DAG));
+      DOUT << '\n';
 
       std::vector<SDNode*> NowDead;
       DAG.ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, NowDead);
@@ -455,9 +464,9 @@ void DAGCombiner::Run(bool RunningAfterLegalize) {
                RV.Val->getOpcode() != ISD::DELETED_NODE &&
                "Node was deleted but visit returned new node!");
 
-        DEBUG(std::cerr << "\nReplacing.3 "; N->dump();
-              std::cerr << "\nWith: "; RV.Val->dump(&DAG);
-              std::cerr << '\n');
+        DOUT << "\nReplacing.3 "; DEBUG(N->dump());
+        DOUT << "\nWith: "; DEBUG(RV.Val->dump(&DAG));
+        DOUT << '\n';
         std::vector<SDNode*> NowDead;
         if (N->getNumValues() == RV.Val->getNumValues())
           DAG.ReplaceAllUsesWith(N, RV.Val, &NowDead);
@@ -1945,13 +1954,15 @@ SDOperand DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   if ((ISD::isSEXTLoad(N0.Val) || ISD::isEXTLoad(N0.Val)) && N0.hasOneUse()) {
     LoadSDNode *LN0 = cast<LoadSDNode>(N0);
     MVT::ValueType EVT = LN0->getLoadedVT();
-    SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
-                                       LN0->getBasePtr(), LN0->getSrcValue(),
-                                       LN0->getSrcValueOffset(), EVT);
-    CombineTo(N, ExtLoad);
-    CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
-              ExtLoad.getValue(1));
-    return SDOperand(N, 0);   // Return N so it doesn't get rechecked!
+    if (!AfterLegalize || TLI.isLoadXLegal(ISD::SEXTLOAD, EVT)) {
+      SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
+                                         LN0->getBasePtr(), LN0->getSrcValue(),
+                                         LN0->getSrcValueOffset(), EVT);
+      CombineTo(N, ExtLoad);
+      CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
+                ExtLoad.getValue(1));
+      return SDOperand(N, 0);   // Return N so it doesn't get rechecked!
+    }
   }
   
   return SDOperand();
@@ -2180,10 +2191,10 @@ SDOperand DAGCombiner::visitTRUNCATE(SDNode *N) {
   // fold (truncate (ext x)) -> (ext x) or (truncate x) or x
   if (N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::SIGN_EXTEND||
       N0.getOpcode() == ISD::ANY_EXTEND) {
-    if (N0.getValueType() < VT)
+    if (N0.getOperand(0).getValueType() < VT)
       // if the source is smaller than the dest, we still need an extend
       return DAG.getNode(N0.getOpcode(), VT, N0.getOperand(0));
-    else if (N0.getValueType() > VT)
+    else if (N0.getOperand(0).getValueType() > VT)
       // if the source is larger than the dest, than we just need the truncate
       return DAG.getNode(ISD::TRUNCATE, VT, N0.getOperand(0));
     else
@@ -2192,7 +2203,12 @@ SDOperand DAGCombiner::visitTRUNCATE(SDNode *N) {
       return N0.getOperand(0);
   }
   // fold (truncate (load x)) -> (smaller load x)
-  if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse()) {
+  if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
+      // Do not allow folding to i1 here.  i1 is implicitly stored in memory in
+      // zero extended form: by shrinking the load, we lose track of the fact
+      // that it is already zero extended.
+      // FIXME: This should be reevaluated.
+      VT != MVT::i1) {
     assert(MVT::getSizeInBits(N0.getValueType()) > MVT::getSizeInBits(VT) &&
            "Cannot truncate to larger type!");
     LoadSDNode *LN0 = cast<LoadSDNode>(N0);
@@ -2400,6 +2416,13 @@ SDOperand DAGCombiner::visitFADD(SDNode *N) {
   // fold ((-A) + B) -> B-A
   if (N0.getOpcode() == ISD::FNEG)
     return DAG.getNode(ISD::FSUB, VT, N1, N0.getOperand(0));
+  
+  // If allowed, fold (fadd (fadd x, c1), c2) -> (fadd x, (fadd c1, c2))
+  if (UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FADD &&
+      N0.Val->hasOneUse() && isa<ConstantFPSDNode>(N0.getOperand(1)))
+    return DAG.getNode(ISD::FADD, VT, N0.getOperand(0),
+                       DAG.getNode(ISD::FADD, VT, N0.getOperand(1), N1));
+  
   return SDOperand();
 }
 
@@ -2435,6 +2458,13 @@ SDOperand DAGCombiner::visitFMUL(SDNode *N) {
   // fold (fmul X, 2.0) -> (fadd X, X)
   if (N1CFP && N1CFP->isExactlyValue(+2.0))
     return DAG.getNode(ISD::FADD, VT, N0, N0);
+  
+  // If allowed, fold (fmul (fmul x, c1), c2) -> (fmul x, (fmul c1, c2))
+  if (UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FMUL &&
+      N0.Val->hasOneUse() && isa<ConstantFPSDNode>(N0.getOperand(1)))
+    return DAG.getNode(ISD::FMUL, VT, N0.getOperand(0),
+                       DAG.getNode(ISD::FMUL, VT, N0.getOperand(1), N1));
+  
   return SDOperand();
 }
 
@@ -2722,12 +2752,17 @@ bool DAGCombiner::CombineToPreIndexedLoadStore(SDNode *N) {
   SDOperand Ptr;
   MVT::ValueType VT;
   if (LoadSDNode *LD  = dyn_cast<LoadSDNode>(N)) {
+    if (LD->getAddressingMode() != ISD::UNINDEXED)
+      return false;
     VT = LD->getLoadedVT();
-    if (!TLI.isIndexedLoadLegal(ISD::PRE_INC, VT) &&
+    if (LD->getAddressingMode() != ISD::UNINDEXED &&
+        !TLI.isIndexedLoadLegal(ISD::PRE_INC, VT) &&
         !TLI.isIndexedLoadLegal(ISD::PRE_DEC, VT))
       return false;
     Ptr = LD->getBasePtr();
   } else if (StoreSDNode *ST  = dyn_cast<StoreSDNode>(N)) {
+    if (ST->getAddressingMode() != ISD::UNINDEXED)
+      return false;
     VT = ST->getStoredVT();
     if (!TLI.isIndexedStoreLegal(ISD::PRE_INC, VT) &&
         !TLI.isIndexedStoreLegal(ISD::PRE_DEC, VT))
@@ -2796,9 +2831,9 @@ bool DAGCombiner::CombineToPreIndexedLoadStore(SDNode *N) {
     Result = DAG.getIndexedStore(SDOperand(N,0), BasePtr, Offset, AM);
   ++PreIndexedNodes;
   ++NodesCombined;
-  DEBUG(std::cerr << "\nReplacing.4 "; N->dump();
-        std::cerr << "\nWith: "; Result.Val->dump(&DAG);
-        std::cerr << '\n');
+  DOUT << "\nReplacing.4 "; DEBUG(N->dump());
+  DOUT << "\nWith: "; DEBUG(Result.Val->dump(&DAG));
+  DOUT << '\n';
   std::vector<SDNode*> NowDead;
   if (isLoad) {
     DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
@@ -2841,12 +2876,16 @@ bool DAGCombiner::CombineToPostIndexedLoadStore(SDNode *N) {
   SDOperand Ptr;
   MVT::ValueType VT;
   if (LoadSDNode *LD  = dyn_cast<LoadSDNode>(N)) {
+    if (LD->getAddressingMode() != ISD::UNINDEXED)
+      return false;
     VT = LD->getLoadedVT();
     if (!TLI.isIndexedLoadLegal(ISD::POST_INC, VT) &&
         !TLI.isIndexedLoadLegal(ISD::POST_DEC, VT))
       return false;
     Ptr = LD->getBasePtr();
   } else if (StoreSDNode *ST  = dyn_cast<StoreSDNode>(N)) {
+    if (ST->getAddressingMode() != ISD::UNINDEXED)
+      return false;
     VT = ST->getStoredVT();
     if (!TLI.isIndexedStoreLegal(ISD::POST_INC, VT) &&
         !TLI.isIndexedStoreLegal(ISD::POST_DEC, VT))
@@ -2856,7 +2895,7 @@ bool DAGCombiner::CombineToPostIndexedLoadStore(SDNode *N) {
   } else
     return false;
 
-  if (!Ptr.Val->hasOneUse())
+  if (Ptr.Val->hasOneUse())
     return false;
   
   for (SDNode::use_iterator I = Ptr.Val->use_begin(),
@@ -2919,9 +2958,9 @@ bool DAGCombiner::CombineToPostIndexedLoadStore(SDNode *N) {
           : DAG.getIndexedStore(SDOperand(N,0), BasePtr, Offset, AM);
         ++PostIndexedNodes;
         ++NodesCombined;
-        DEBUG(std::cerr << "\nReplacing.5 "; N->dump();
-              std::cerr << "\nWith: "; Result.Val->dump(&DAG);
-              std::cerr << '\n');
+        DOUT << "\nReplacing.5 "; DEBUG(N->dump());
+        DOUT << "\nWith: "; DEBUG(Result.Val->dump(&DAG));
+        DOUT << '\n';
         std::vector<SDNode*> NowDead;
         if (isLoad) {
           DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
@@ -3031,6 +3070,46 @@ SDOperand DAGCombiner::visitSTORE(SDNode *N) {
                         ST->getSrcValueOffset());
   }
   
+  // Turn 'store float 1.0, Ptr' -> 'store int 0x12345678, Ptr'
+  if (ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(Value)) {
+    if (Value.getOpcode() != ISD::TargetConstantFP) {
+      SDOperand Tmp;
+      switch (CFP->getValueType(0)) {
+      default: assert(0 && "Unknown FP type");
+      case MVT::f32:
+        if (!AfterLegalize || TLI.isTypeLegal(MVT::i32)) {
+          Tmp = DAG.getConstant(FloatToBits(CFP->getValue()), MVT::i32);
+          return DAG.getStore(Chain, Tmp, Ptr, ST->getSrcValue(),
+                              ST->getSrcValueOffset());
+        }
+        break;
+      case MVT::f64:
+        if (!AfterLegalize || TLI.isTypeLegal(MVT::i64)) {
+          Tmp = DAG.getConstant(DoubleToBits(CFP->getValue()), MVT::i64);
+          return DAG.getStore(Chain, Tmp, Ptr, ST->getSrcValue(),
+                              ST->getSrcValueOffset());
+        } else if (TLI.isTypeLegal(MVT::i32)) {
+          // Many FP stores are not make apparent until after legalize, e.g. for
+          // argument passing.  Since this is so common, custom legalize the
+          // 64-bit integer store into two 32-bit stores.
+          uint64_t Val = DoubleToBits(CFP->getValue());
+          SDOperand Lo = DAG.getConstant(Val & 0xFFFFFFFF, MVT::i32);
+          SDOperand Hi = DAG.getConstant(Val >> 32, MVT::i32);
+          if (!TLI.isLittleEndian()) std::swap(Lo, Hi);
+
+          SDOperand St0 = DAG.getStore(Chain, Lo, Ptr, ST->getSrcValue(),
+                                       ST->getSrcValueOffset());
+          Ptr = DAG.getNode(ISD::ADD, Ptr.getValueType(), Ptr,
+                            DAG.getConstant(4, Ptr.getValueType()));
+          SDOperand St1 = DAG.getStore(Chain, Hi, Ptr, ST->getSrcValue(),
+                                       ST->getSrcValueOffset()+4);
+          return DAG.getNode(ISD::TokenFactor, MVT::Other, St0, St1);
+        }
+        break;
+      }
+    }
+  }
+
   if (CombinerAA) { 
     // Walk up chain skipping non-aliasing memory nodes.
     SDOperand BetterChain = FindBetterChain(N, Chain);
@@ -3752,7 +3831,10 @@ SDOperand DAGCombiner::SimplifySelectCC(SDOperand N0, SDOperand N1,
     // cast from setcc result type to select result type
     if (AfterLegalize) {
       SCC  = DAG.getSetCC(TLI.getSetCCResultTy(), N0, N1, CC);
-      Temp = DAG.getZeroExtendInReg(SCC, N2.getValueType());
+      if (N2.getValueType() < SCC.getValueType())
+        Temp = DAG.getZeroExtendInReg(SCC, N2.getValueType());
+      else
+        Temp = DAG.getNode(ISD::ZERO_EXTEND, N2.getValueType(), SCC);
     } else {
       SCC  = DAG.getSetCC(MVT::i1, N0, N1, CC);
       Temp = DAG.getNode(ISD::ZERO_EXTEND, N2.getValueType(), SCC);
@@ -4444,6 +4526,10 @@ SDOperand DAGCombiner::FindBetterChain(SDNode *N, SDOperand OldChain) {
 // SelectionDAG::Combine - This is the entry point for the file.
 //
 void SelectionDAG::Combine(bool RunningAfterLegalize, AliasAnalysis &AA) {
+  if (!RunningAfterLegalize && ViewDAGCombine1)
+    viewGraph();
+  if (RunningAfterLegalize && ViewDAGCombine2)
+    viewGraph();
   /// run - This is the main entry point to this class.
   ///
   DAGCombiner(*this, AA).Run(RunningAfterLegalize);