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

Chris Lattner lattner at cs.uiuc.edu
Thu Sep 14 13:51:11 PDT 2006



Changes in directory llvm/lib/CodeGen/SelectionDAG:

DAGCombiner.cpp updated: 1.185 -> 1.186
---
Log message:

Split rotate matching code out to its own function.  Make it stronger, by
matching things like ((x >> c1) & c2) | ((x << c3) & c4) to (rot x, c5) & c6


---
Diffs of the changes:  (+143 -54)

 DAGCombiner.cpp |  197 ++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 143 insertions(+), 54 deletions(-)


Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.185 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.186
--- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.185	Thu Aug 31 02:41:12 2006
+++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp	Thu Sep 14 15:50:57 2006
@@ -230,7 +230,8 @@
                             ISD::CondCode Cond, bool foldBooleans = true);
     SDOperand ConstantFoldVBIT_CONVERTofVBUILD_VECTOR(SDNode *, MVT::ValueType);
     SDOperand BuildSDIV(SDNode *N);
-    SDOperand BuildUDIV(SDNode *N);    
+    SDOperand BuildUDIV(SDNode *N);
+    SDNode *MatchRotate(SDOperand LHS, SDOperand RHS);
 public:
     DAGCombiner(SelectionDAG &D)
       : DAG(D), TLI(D.getTargetLoweringInfo()), AfterLegalize(false) {}
@@ -1153,63 +1154,150 @@
     SDOperand Tmp = SimplifyBinOpWithSameOpcodeHands(N);
     if (Tmp.Val) return Tmp;
   }
+  
+  // See if this is some rotate idiom.
+  if (SDNode *Rot = MatchRotate(N0, N1))
+    return SDOperand(Rot, 0);
 
-  // canonicalize shl to left side in a shl/srl pair, to match rotate
-  if (N0.getOpcode() == ISD::SRL && N1.getOpcode() == ISD::SHL)
-    std::swap(N0, N1);
-  // check for rotl, rotr
-  if (N0.getOpcode() == ISD::SHL && N1.getOpcode() == ISD::SRL &&
-      N0.getOperand(0) == N1.getOperand(0) &&
-      TLI.isTypeLegal(VT)) {
-    bool HasROTL = TLI.isOperationLegal(ISD::ROTL, VT);
-    bool HasROTR = TLI.isOperationLegal(ISD::ROTR, VT);
-    if (HasROTL || HasROTR) {
-      // fold (or (shl x, C1), (srl x, C2)) -> (rotl x, C1)
-      // fold (or (shl x, C1), (srl x, C2)) -> (rotr x, C2)
-      if (N0.getOperand(1).getOpcode() == ISD::Constant &&
-          N1.getOperand(1).getOpcode() == ISD::Constant) {
-        uint64_t c1val = cast<ConstantSDNode>(N0.getOperand(1))->getValue();
-        uint64_t c2val = cast<ConstantSDNode>(N1.getOperand(1))->getValue();
-        if ((c1val + c2val) == OpSizeInBits)
-          if (HasROTL)
-            return DAG.getNode(ISD::ROTL, VT, N0.getOperand(0),
-                               N0.getOperand(1));
-          else
-            return DAG.getNode(ISD::ROTR, VT, N0.getOperand(0),
-                               N1.getOperand(1));
-            
-      }
-      // fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotl x, y)
-      // fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotr x, (sub 32, y))
-      if (N1.getOperand(1).getOpcode() == ISD::SUB &&
-          N0.getOperand(1) == N1.getOperand(1).getOperand(1))
-        if (ConstantSDNode *SUBC = 
-            dyn_cast<ConstantSDNode>(N1.getOperand(1).getOperand(0)))
-          if (SUBC->getValue() == OpSizeInBits)
-            if (HasROTL)
-              return DAG.getNode(ISD::ROTL, VT, N0.getOperand(0),
-                                 N0.getOperand(1));
-            else
-              return DAG.getNode(ISD::ROTR, VT, N0.getOperand(0),
-                                 N1.getOperand(1));
-      // fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotr x, y)
-      // fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotl x, (sub 32, y))
-      if (N0.getOperand(1).getOpcode() == ISD::SUB &&
-          N1.getOperand(1) == N0.getOperand(1).getOperand(1))
-        if (ConstantSDNode *SUBC = 
-            dyn_cast<ConstantSDNode>(N0.getOperand(1).getOperand(0)))
-          if (SUBC->getValue() == OpSizeInBits)
-            if (HasROTR)
-              return DAG.getNode(ISD::ROTR, VT, N0.getOperand(0), 
-                                 N1.getOperand(1));
-            else
-              return DAG.getNode(ISD::ROTL, VT, N0.getOperand(0),
-                                 N0.getOperand(1));
+  return SDOperand();
+}
+
+
+/// MatchRotateHalf - Match "(X shl/srl V1) & V2" where V2 may not be present.
+static bool MatchRotateHalf(SDOperand Op, SDOperand &Shift, SDOperand &Mask) {
+  if (Op.getOpcode() == ISD::AND) {
+    if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
+      Mask = Op.getOperand(1);
+      Op = Op.getOperand(0);
+    } else {
+      return false;
     }
   }
-  return SDOperand();
+  
+  if (Op.getOpcode() == ISD::SRL || Op.getOpcode() == ISD::SHL) {
+    Shift = Op;
+    return true;
+  }
+  return false;  
+}
+
+
+// MatchRotate - Handle an 'or' of two operands.  If this is one of the many
+// idioms for rotate, and if the target supports rotation instructions, generate
+// a rot[lr].
+SDNode *DAGCombiner::MatchRotate(SDOperand LHS, SDOperand RHS) {
+  // Must be a legal type.  Expanded an promoted things won't work with rotates.
+  MVT::ValueType VT = LHS.getValueType();
+  if (!TLI.isTypeLegal(VT)) return 0;
+
+  // The target must have at least one rotate flavor.
+  bool HasROTL = TLI.isOperationLegal(ISD::ROTL, VT);
+  bool HasROTR = TLI.isOperationLegal(ISD::ROTR, VT);
+  if (!HasROTL && !HasROTR) return 0;
+  
+  // Match "(X shl/srl V1) & V2" where V2 may not be present.
+  SDOperand LHSShift;   // The shift.
+  SDOperand LHSMask;    // AND value if any.
+  if (!MatchRotateHalf(LHS, LHSShift, LHSMask))
+    return 0; // Not part of a rotate.
+
+  SDOperand RHSShift;   // The shift.
+  SDOperand RHSMask;    // AND value if any.
+  if (!MatchRotateHalf(RHS, RHSShift, RHSMask))
+    return 0; // Not part of a rotate.
+  
+  if (LHSShift.getOperand(0) != RHSShift.getOperand(0))
+    return 0;   // Not shifting the same value.
+
+  if (LHSShift.getOpcode() == RHSShift.getOpcode())
+    return 0;   // Shifts must disagree.
+    
+  // Canonicalize shl to left side in a shl/srl pair.
+  if (RHSShift.getOpcode() == ISD::SHL) {
+    std::swap(LHS, RHS);
+    std::swap(LHSShift, RHSShift);
+    std::swap(LHSMask , RHSMask );
+  }
+
+  unsigned OpSizeInBits = MVT::getSizeInBits(VT);
+
+  // fold (or (shl x, C1), (srl x, C2)) -> (rotl x, C1)
+  // fold (or (shl x, C1), (srl x, C2)) -> (rotr x, C2)
+  if (LHSShift.getOperand(1).getOpcode() == ISD::Constant &&
+      RHSShift.getOperand(1).getOpcode() == ISD::Constant) {
+    uint64_t LShVal = cast<ConstantSDNode>(LHSShift.getOperand(1))->getValue();
+    uint64_t RShVal = cast<ConstantSDNode>(RHSShift.getOperand(1))->getValue();
+    if ((LShVal + RShVal) != OpSizeInBits)
+      return 0;
+
+    SDOperand Rot;
+    if (HasROTL)
+      Rot = DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0),
+                        LHSShift.getOperand(1));
+    else
+      Rot = DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0),
+                        RHSShift.getOperand(1));
+    
+    // If there is an AND of either shifted operand, apply it to the result.
+    if (LHSMask.Val || RHSMask.Val) {
+      uint64_t Mask = MVT::getIntVTBitMask(VT);
+      
+      if (LHSMask.Val) {
+        uint64_t RHSBits = (1ULL << LShVal)-1;
+        Mask &= cast<ConstantSDNode>(LHSMask)->getValue() | RHSBits;
+      }
+      if (RHSMask.Val) {
+        uint64_t LHSBits = ~((1ULL << (OpSizeInBits-RShVal))-1);
+        Mask &= cast<ConstantSDNode>(RHSMask)->getValue() | LHSBits;
+      }
+        
+      Rot = DAG.getNode(ISD::AND, VT, Rot, DAG.getConstant(Mask, VT));
+    }
+    
+    return Rot.Val;
+  }
+  
+  // If there is a mask here, and we have a variable shift, we can't be sure
+  // that we're masking out the right stuff.
+  if (LHSMask.Val || RHSMask.Val)
+    return 0;
+  
+  // fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotl x, y)
+  // fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotr x, (sub 32, y))
+  if (RHSShift.getOperand(1).getOpcode() == ISD::SUB &&
+      LHSShift.getOperand(1) == RHSShift.getOperand(1).getOperand(1)) {
+    if (ConstantSDNode *SUBC = 
+          dyn_cast<ConstantSDNode>(RHSShift.getOperand(1).getOperand(0))) {
+      if (SUBC->getValue() == OpSizeInBits)
+        if (HasROTL)
+          return DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0),
+                             LHSShift.getOperand(1)).Val;
+        else
+          return DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0),
+                             LHSShift.getOperand(1)).Val;
+    }
+  }
+  
+  // fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotr x, y)
+  // fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotl x, (sub 32, y))
+  if (LHSShift.getOperand(1).getOpcode() == ISD::SUB &&
+      RHSShift.getOperand(1) == LHSShift.getOperand(1).getOperand(1)) {
+    if (ConstantSDNode *SUBC = 
+          dyn_cast<ConstantSDNode>(LHSShift.getOperand(1).getOperand(0))) {
+      if (SUBC->getValue() == OpSizeInBits)
+        if (HasROTL)
+          return DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0),
+                             LHSShift.getOperand(1)).Val;
+        else
+          return DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0), 
+                             RHSShift.getOperand(1)).Val;
+    }
+  }
+  
+  return 0;
 }
 
+
 SDOperand DAGCombiner::visitXOR(SDNode *N) {
   SDOperand N0 = N->getOperand(0);
   SDOperand N1 = N->getOperand(1);
@@ -2864,7 +2952,8 @@
       SDOperand NumEltsNode = DAG.getConstant(NumElts, MVT::i32);
       SDOperand EVTNode = DAG.getValueType(EVT);
       std::vector<SDOperand> Ops;
-      LHS = DAG.getNode(ISD::VBIT_CONVERT, MVT::Vector, LHS, NumEltsNode, EVTNode);
+      LHS = DAG.getNode(ISD::VBIT_CONVERT, MVT::Vector, LHS, NumEltsNode,
+                        EVTNode);
       Ops.push_back(LHS);
       AddToWorkList(LHS.Val);
       std::vector<SDOperand> ZeroOps(NumElts, DAG.getConstant(0, EVT));






More information about the llvm-commits mailing list