[llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Jim Laskey jlaskey at apple.com
Mon Sep 25 09:30:08 PDT 2006



Changes in directory llvm/lib/CodeGen/SelectionDAG:

DAGCombiner.cpp updated: 1.197 -> 1.198
---
Log message:

Core antialiasing for load and store.

---
Diffs of the changes:  (+282 -53)

 DAGCombiner.cpp |  335 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 282 insertions(+), 53 deletions(-)


Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.197 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.198
--- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.197	Thu Sep 21 14:04:05 2006
+++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp	Mon Sep 25 11:29:54 2006
@@ -39,6 +39,7 @@
 #include <algorithm>
 #include <cmath>
 #include <iostream>
+#include <algorithm>
 using namespace llvm;
 
 namespace {
@@ -132,7 +133,8 @@
       // Replace the old value with the new one.
       ++NodesCombined;
       DEBUG(std::cerr << "\nReplacing "; TLO.Old.Val->dump();
-            std::cerr << "\nWith: "; TLO.New.Val->dump(&DAG));
+            std::cerr << "\nWith: "; TLO.New.Val->dump(&DAG);
+            std::cerr << '\n');
 
       std::vector<SDNode*> NowDead;
       DAG.ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, NowDead);
@@ -237,7 +239,31 @@
     SDOperand BuildSDIV(SDNode *N);
     SDOperand BuildUDIV(SDNode *N);
     SDNode *MatchRotate(SDOperand LHS, SDOperand RHS);
-    bool isNotAlias(SDOperand Ptr1, SDOperand Ptr2);
+    
+    /// FindBaseOffset - Return true if we can determine base and offset
+    /// information from a given pointer operand.  Provides base and offset as a
+    /// result.
+    static bool FindBaseOffset(SDOperand Ptr,
+                               SDOperand &Object, int64_t &Offset);
+    
+    /// isAlias - Return true if there is the possibility that the two addresses
+    /// overlap.
+    static bool isAlias(SDOperand Ptr1, int64_t Size1, SDOperand SrcValue1,
+                        SDOperand Ptr2, int64_t Size2, SDOperand SrcValue2);
+    
+    /// FindAliasInfo - Extracts the relevant alias information from the memory
+    /// node.
+    static void FindAliasInfo(SDNode *N,
+                           SDOperand &Ptr, int64_t &Size, SDOperand &SrcValue);
+    
+    /// hasChain - Return true if Op has a chain.  Provides chain if present.
+    ///
+    static bool hasChain(SDOperand Op, SDOperand &Chain);
+ 
+    /// FindBetterChain - Walk up chain skipping non-aliasing memory nodes,
+    /// looking for a better chain.
+    SDOperand FindBetterChain(SDNode *N, SDOperand Chain);
+    
 public:
     DAGCombiner(SelectionDAG &D)
       : DAG(D), TLI(D.getTargetLoweringInfo()), AfterLegalize(false) {}
@@ -507,9 +533,6 @@
 }
 
 SDOperand DAGCombiner::visitTokenFactor(SDNode *N) {
-  SmallVector<SDOperand, 8> Ops;
-  bool Changed = false;
-
   // If the token factor has two operands and one is the entry token, replace
   // the token factor with the other operand.
   if (N->getNumOperands() == 2) {
@@ -520,23 +543,69 @@
       return N->getOperand(0);
   }
   
-  // fold (tokenfactor (tokenfactor)) -> tokenfactor
-  for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
+  SmallVector<SDNode *, 8> TFs;   // Set of token factor nodes.
+  SmallVector<SDOperand, 8> Ops;  // Ops for replacing token factor.
+
+  // Add this ndoe to the token factor set.
+  TFs.push_back(N);
+
+  // Separate token factors from other operands.
+  for (unsigned i = 0, ie = N->getNumOperands(); i != ie; ++i) {
     SDOperand Op = N->getOperand(i);
-    if (Op.getOpcode() == ISD::TokenFactor && Op.hasOneUse()) {
-      AddToWorkList(Op.Val);  // Remove dead node.
-      Changed = true;
-      for (unsigned j = 0, e = Op.getNumOperands(); j != e; ++j)
-        Ops.push_back(Op.getOperand(j));
-    } else if (i == 0 || N->getOperand(i) != N->getOperand(i-1)) {
+    if (Op.getOpcode() == ISD::TokenFactor)
+      TFs.push_back(Op.Val);
+    else if (Op.getOpcode() != ISD::EntryToken)
       Ops.push_back(Op);
-    } else {
-      // Deleted an operand that was the same as the last one.
-      Changed = true;
+  }
+  
+  // If there are token factor operands.
+  if (TFs.size() > 1) {
+    bool Changed = false; // If we should replace this token factor.
+    
+    // For each token factor.
+    for (unsigned j = 1, je = TFs.size(); j != je; ++j) {
+      SDNode *TF = TFs[j];
+      bool CanMerge = true; // Can we merge this token factor.
+      
+      if (CombinerAA) {
+        if (!TF->hasOneUse()) {
+          // Check to see if all users point to members of the token factor set.
+          for (SDNode::use_iterator UI = TF->use_begin(), UE = TF->use_end();
+               CanMerge && UI != UE; ++UI) {
+            SDNode *User = *UI;
+            CanMerge = User->getOpcode() == ISD::TokenFactor &&
+                       std::find(TFs.begin(), TFs.end(), User) != TFs.end();
+          }
+        }
+      } else {
+        CanMerge = TF->hasOneUse();
+      }
+      
+      // If it's valid to merge.
+      if (CanMerge) {
+        // Remove dead token factor node.
+        AddToWorkList(TF); 
+        
+        // Make sure we don't duplicate operands.
+        unsigned m = Ops.size(); // Number of prior operands.
+        for (unsigned l = 0, le = TF->getNumOperands(); l != le; ++l) {
+          SDOperand Op = TF->getOperand(l);
+          if (std::find(Ops.begin(), Ops.end(), Op) == Ops.end())
+            Ops.push_back(Op);
+        }
+        Changed = true;
+      } else  {
+        // Can't merge this token factor.
+        Ops.push_back(SDOperand(TF, 0));
+      }
+    }
+    
+    // If we've change things around then replace token factor.
+    if (Changed) {
+      return DAG.getNode(ISD::TokenFactor, MVT::Other, &Ops[0], Ops.size());
     }
   }
-  if (Changed)
-    return DAG.getNode(ISD::TokenFactor, MVT::Other, &Ops[0], Ops.size());
+  
   return SDOperand();
 }
 
@@ -2571,6 +2640,27 @@
       Chain.getOperand(1).getValueType() == N->getValueType(0))
     return CombineTo(N, Chain.getOperand(1), Chain);
   
+  if (CombinerAA) { 
+    // Walk up chain skipping non-aliasing memory nodes.
+    SDOperand BetterChain = FindBetterChain(N, Chain);
+    
+    // If the there is a better chain.
+    if (Chain != BetterChain) {
+      // Replace the chain to void dependency.
+      SDOperand ReplLoad = DAG.getLoad(N->getValueType(0), BetterChain, Ptr,
+                                       SrcValue);
+
+      // Replace uses with token.
+      CombineTo(N, ReplLoad.getValue(0), ReplLoad.getValue(1));
+      
+      // Old chain needs to be cleaned up.
+      AddToWorkList(Chain.Val);
+      
+      // Don't recombine on token.
+      return SDOperand(N, 0);
+    }
+  }
+
   return SDOperand();
 }
 
@@ -2589,27 +2679,6 @@
   return SDOperand();
 }
 
-/// isNotAlias - Return true if we have definitive knowlege that the two
-/// addresses don't overlap.
-bool DAGCombiner::isNotAlias(SDOperand Ptr1, SDOperand Ptr2) {
-  // Mind the flag.
-  if (!CombinerAA) return false;
-  
-  // If they are the same then they must be aliases.
-  if (Ptr1 == Ptr2) return false;
-  
-  // If both operands are frame values (not the same location from above test)
-  // then they can't alias.
-  FrameIndexSDNode *FI1 = dyn_cast<FrameIndexSDNode>(Ptr1);
-  FrameIndexSDNode *FI2 = dyn_cast<FrameIndexSDNode>(Ptr2);
-  if (FI1 && FI2) {
-    return true;
-  }
-  
-  // Otherwise we don't know and have to play it safe.
-  return false;
-}
-
 SDOperand DAGCombiner::visitSTORE(SDNode *N) {
   SDOperand Chain    = N->getOperand(0);
   SDOperand Value    = N->getOperand(1);
@@ -2637,22 +2706,33 @@
   // If this is a store of a bit convert, store the input value.
   // FIXME: This needs to know that the resultant store does not need a 
   // higher alignment than the original.
-  if (0 && Value.getOpcode() == ISD::BIT_CONVERT)
+  if (Value.getOpcode() == ISD::BIT_CONVERT) {
     return DAG.getNode(ISD::STORE, MVT::Other, Chain, Value.getOperand(0),
                        Ptr, SrcValue);
-                       
-  // If the previous store is not an alias then break artificial chain.
-  if (Chain.getOpcode() == ISD::STORE && isNotAlias(Ptr, Chain.getOperand(2))) {
-    // Replace the chain to void dependency.
-    SDNode *PrevStore = Chain.Val;
-    SDOperand ReplStore = DAG.getNode(ISD::STORE, MVT::Other,
-                                     PrevStore->getOperand(0), Value, Ptr,
-                                     SrcValue);
-    // Create token to keep both stores around.
-    SDOperand Token = DAG.getNode(ISD::TokenFactor, MVT::Other,
-                      Chain, ReplStore);
-    // Replace uses with token.
-    return Token;
+  }
+  
+  if (CombinerAA) { 
+    // Walk up chain skipping non-aliasing memory nodes.
+    SDOperand BetterChain = FindBetterChain(N, Chain);
+    
+    // If the there is a better chain.
+    if (Chain != BetterChain) {
+      // Replace the chain to void dependency.
+      SDOperand ReplStore = DAG.getNode(ISD::STORE, MVT::Other,
+                                        BetterChain, Value, Ptr,
+                                        SrcValue);
+      // Create token to keep both nodes around.
+      SDOperand Token = DAG.getNode(ISD::TokenFactor, MVT::Other,
+                                    Chain, ReplStore);
+
+      // Make sure we merge token factors.
+      AddUsersToWorkList(N);
+      
+      // Old chain needs to be cleaned up.
+      AddToWorkList(Chain.Val);
+         
+      return Token;
+    }
   }
   
   return SDOperand();
@@ -3860,6 +3940,155 @@
   return S;
 }
 
+/// FindBaseOffset - Return true if we can determine base and offset information
+/// from a given pointer operand.  Provides base and offset as a result.
+bool DAGCombiner::FindBaseOffset(SDOperand Ptr,
+                                 SDOperand &Object, int64_t &Offset) {
+  
+  // Is it a frame variable, global or constant.
+  if (isa<FrameIndexSDNode>(Ptr) ||
+      isa<ConstantPoolSDNode>(Ptr) ||
+      isa<GlobalAddressSDNode>(Ptr)) {
+    Object = Ptr; Offset = 0;
+    return true;
+  } else if (Ptr.getOpcode() == ISD::ADD &&
+             FindBaseOffset(Ptr.getOperand(0), Object, Offset)) {
+    // If it's an add of an simple constant then include it in the offset.
+    if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Ptr.getOperand(1))) {
+      Offset += C->getValue();
+      return true;
+    }
+  }
+                                 
+  return false;                               
+}
+
+/// isAlias - Return true if there is the possibility that the two addresses
+/// overlap.
+bool DAGCombiner::isAlias(SDOperand Ptr1, int64_t Size1,
+                          SDOperand SrcValue1,
+                          SDOperand Ptr2, int64_t Size2,
+                          SDOperand SrcValue2) {
+  // If they are the same then they must be aliases.
+  if (Ptr1 == Ptr2) return true;
+  
+  // Gather base offset information.  Objects can be frame variables, globals
+  // or constants.
+  SDOperand Object1, Object2;
+  int64_t Offset1, Offset2;
+  if (FindBaseOffset(Ptr1, Object1, Offset1) &&
+      FindBaseOffset(Ptr2, Object2, Offset2)) {
+    // If they have a different base address, then they can't alias.
+    if (Object1 != Object2) return false;
+    
+    // Check to see if the addresses overlap.
+    if ((Offset1 + Size1) <= Offset2 || (Offset2 + Size2) <= Offset1)
+      return false;
+  }
+  
+  // Otherwise we don't know and have to play it safe.
+  return true;
+}
+
+/// FindAliasInfo - Extracts the relevant alias information from the memory
+/// node.
+void DAGCombiner::FindAliasInfo(SDNode *N,
+                          SDOperand &Ptr, int64_t &Size, SDOperand &SrcValue) {
+  switch (N->getOpcode()) {
+  case ISD::LOAD:
+    Ptr = N->getOperand(1);
+    Size = MVT::getSizeInBits(N->getOperand(1).getValueType()) >> 3;
+    SrcValue = N->getOperand(2);
+    break;
+  case ISD::STORE:
+    Ptr = N->getOperand(2);
+    Size = MVT::getSizeInBits(N->getOperand(1).getValueType()) >> 3;
+    SrcValue = N->getOperand(3);
+    break;
+  default:
+    assert(0 && "getAliasInfo expected a memory op");
+  }
+}
+
+/// hasChain - Return true if Op has a chain.  Provides chain if present.
+///
+bool DAGCombiner::hasChain(SDOperand Op, SDOperand &Chain) {
+  if (Op.getNumOperands() == 0) return false;
+  Chain = Op.getOperand(0);
+  return Chain.getValueType() == MVT::Other;
+}
+
+/// FindBetterChain - Walk up chain skipping non-aliasing memory nodes, looking
+/// for a better chain.
+SDOperand DAGCombiner::FindBetterChain(SDNode *N, SDOperand Chain) {
+  // Get alias information for node.
+  SDOperand Ptr;
+  int64_t Size;
+  SDOperand SrcValue;
+  FindAliasInfo(N, Ptr, Size, SrcValue);
+
+  // While we don't encounter any aliasing memory nodes walk up chain.
+  while (true) {
+    switch (Chain.getOpcode()) {
+    case ISD::EntryToken:
+      // Entry token is ideal chain operand.
+      return Chain;
+    case ISD::LOAD:
+    case ISD::STORE: {
+      // Get alias information for chain.
+      SDOperand ChainPtr;
+      int64_t ChainSize;
+      SDOperand ChainSrcValue;
+      FindAliasInfo(Chain.Val, ChainPtr, ChainSize, ChainSrcValue);
+      
+      // If chain is alias then stop here, otherwise continue up chain.
+      if (isAlias(Ptr, Size, SrcValue, ChainPtr, ChainSize, ChainSrcValue))
+        return Chain;
+      else
+        Chain = Chain.getOperand(0);
+      
+      break;
+    }
+    case ISD::TokenFactor: {
+      // Continue up each of token factor operand and accumulate results in
+      // a new token factor.  CSE will handle duplicate elimination.
+      SmallVector<SDOperand, 8> Ops;  // Ops for replacing token factor.
+      bool Change = false;
+      
+      // For each token factor operand. 
+      for (unsigned i = 0, e = Chain.getNumOperands(); i != e; ++i) {
+        SDOperand Op = Chain.getOperand(i);
+        SDOperand OpChain = FindBetterChain(N, Op);
+        
+        // Make sure we don't duplicate an operand.
+        if (OpChain.getOpcode() != ISD::EntryToken &&
+            std::find(Ops.begin(), Ops.end(), OpChain) == Ops.end()) {
+          Ops.push_back(OpChain);
+        }
+        
+        // If we added a new operand.
+        Change = Change || Op != OpChain; 
+      }
+      
+      // If we have new operands.
+      if (Change) {
+        // Create a specialized token factor for this chain. getNode CSE will
+        // handle duplicates. If it's a single operand, getNode will just
+        // return the opernand instead of a new token factor.
+        return DAG.getNode(ISD::TokenFactor, MVT::Other, &Ops[0], Ops.size());
+      }
+      
+      // Leave things alone.
+      return Chain;
+    }
+    // For all other instructions we will just have to take what we can get.
+    default: return Chain;
+    }
+  }
+  
+  return Chain;
+}
+
 // SelectionDAG::Combine - This is the entry point for the file.
 //
 void SelectionDAG::Combine(bool RunningAfterLegalize) {






More information about the llvm-commits mailing list