[PATCH] DAGCombiner: Recognise rotates by X+C

Richard Sandiford rsandifo at linux.vnet.ibm.com
Fri Dec 6 02:17:11 PST 2013


The SystemZ tests check for rotates by X+10 using:

   %add = add i32 %amt, 10
   %sub = sub i32 32, %add
   %parta = shl i32 %a, %add
   %partb = lshr i32 %a, %sub
   %or = or i32 %parta, %partb

But instcombine turns this into:

   %add = add i32 %amt, 10
   %sub = sub i32 22, %amt
   %parta = shl i32 %a, %add
   %partb = lshr i32 %a, %sub
   %or = or i32 %parta, %partb

so that the subtraction isn't dependent on the addition.  This patch extends DAGCombiner to handle this pattern too.


http://llvm-reviews.chandlerc.com/D2347

Files:
  lib/CodeGen/SelectionDAG/DAGCombiner.cpp
  test/CodeGen/SystemZ/shift-04.ll

Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -3302,6 +3302,22 @@
   return false;
 }
 
+// Check whether C1 - X1 == C2 - X2, given that C1 - X1 comes directly
+// from a DAG node (and so is already simplified).
+static bool matchRotateSub(const APInt &C1, SDValue X1, unsigned C2,
+                           SDValue X2) {
+  if (X1 == X2)
+    return C1 == C2;
+
+  // Check for C1 - X1 == C2 - (X1 + C3).
+  if (X2.getOpcode() == ISD::ADD && X1 == X2.getOperand(0)) {
+    ConstantSDNode *C3 = dyn_cast<ConstantSDNode>(X2.getOperand(1));
+    return C3 && C1 + C3->getAPIntValue() == C2;
+  }
+
+  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].
@@ -3396,14 +3412,15 @@
     RExtOp0 = RHSShiftAmt.getOperand(0);
   }
 
-  if (RExtOp0.getOpcode() == ISD::SUB && RExtOp0.getOperand(1) == LExtOp0) {
+  if (RExtOp0.getOpcode() == ISD::SUB) {
     // fold (or (shl x, (*ext y)), (srl x, (*ext (sub 32, y)))) ->
     //   (rotl x, y)
     // fold (or (shl x, (*ext y)), (srl x, (*ext (sub 32, y)))) ->
     //   (rotr x, (sub 32, y))
     if (ConstantSDNode *SUBC =
             dyn_cast<ConstantSDNode>(RExtOp0.getOperand(0))) {
-      if (SUBC->getAPIntValue() == OpSizeInBits) {
+      if (matchRotateSub(SUBC->getAPIntValue(), RExtOp0.getOperand(1),
+                         OpSizeInBits, LExtOp0)) {
         return DAG.getNode(HasROTL ? ISD::ROTL : ISD::ROTR, DL, VT, LHSShiftArg,
                            HasROTL ? LHSShiftAmt : RHSShiftAmt).getNode();
       } else if (LHSShiftArg.getOpcode() == ISD::ZERO_EXTEND ||
@@ -3419,24 +3436,25 @@
         bool HasROTRWithLArg = TLI.isOperationLegalOrCustom(ISD::ROTR, LArgVT);
         bool HasROTLWithLArg = TLI.isOperationLegalOrCustom(ISD::ROTL, LArgVT);
         if (HasROTRWithLArg || HasROTLWithLArg) {
-          if (LArgVT.getSizeInBits() == SUBC->getAPIntValue()) {
+          if (matchRotateSub(SUBC->getAPIntValue(), RExtOp0.getOperand(1),
+                             LArgVT.getSizeInBits(), LExtOp0)) {
             SDValue V =
                 DAG.getNode(HasROTLWithLArg ? ISD::ROTL : ISD::ROTR, DL, LArgVT,
                             LArgExtOp0, HasROTL ? LHSShiftAmt : RHSShiftAmt);
             return DAG.getNode(LHSShiftArg.getOpcode(), DL, VT, V).getNode();
           }
         }
       }
     }
-  } else if (LExtOp0.getOpcode() == ISD::SUB &&
-             RExtOp0 == LExtOp0.getOperand(1)) {
+  } else if (LExtOp0.getOpcode() == ISD::SUB) {
     // fold (or (shl x, (*ext (sub 32, y))), (srl x, (*ext y))) ->
     //   (rotr x, y)
     // fold (or (shl x, (*ext (sub 32, y))), (srl x, (*ext y))) ->
     //   (rotl x, (sub 32, y))
     if (ConstantSDNode *SUBC =
             dyn_cast<ConstantSDNode>(LExtOp0.getOperand(0))) {
-      if (SUBC->getAPIntValue() == OpSizeInBits) {
+      if (matchRotateSub(SUBC->getAPIntValue(), LExtOp0.getOperand(1),
+                         OpSizeInBits, RExtOp0)) {
         return DAG.getNode(HasROTR ? ISD::ROTR : ISD::ROTL, DL, VT, LHSShiftArg,
                            HasROTR ? RHSShiftAmt : LHSShiftAmt).getNode();
       } else if (RHSShiftArg.getOpcode() == ISD::ZERO_EXTEND ||
@@ -3452,7 +3470,8 @@
         bool HasROTRWithRArg = TLI.isOperationLegalOrCustom(ISD::ROTR, RArgVT);
         bool HasROTLWithRArg = TLI.isOperationLegalOrCustom(ISD::ROTL, RArgVT);
         if (HasROTRWithRArg || HasROTLWithRArg) {
-          if (RArgVT.getSizeInBits() == SUBC->getAPIntValue()) {
+          if (matchRotateSub(SUBC->getAPIntValue(), LExtOp0.getOperand(1),
+                             RArgVT.getSizeInBits(), RExtOp0)) {
             SDValue V =
                 DAG.getNode(HasROTRWithRArg ? ISD::ROTR : ISD::ROTL, DL, RArgVT,
                             RArgExtOp0, HasROTR ? RHSShiftAmt : LHSShiftAmt);
Index: test/CodeGen/SystemZ/shift-04.ll
===================================================================
--- test/CodeGen/SystemZ/shift-04.ll
+++ test/CodeGen/SystemZ/shift-04.ll
@@ -187,3 +187,32 @@
   %or = or i32 %parta, %partb
   ret i32 %or
 }
+
+; Check another form of f5, which is the one produced by running f5 through
+; instcombine.
+define i32 @f15(i32 %a, i32 %amt) {
+; CHECK-LABEL: f15:
+; CHECK: rll %r2, %r2, 10(%r3)
+; CHECK: br %r14
+  %add = add i32 %amt, 10
+  %sub = sub i32 22, %amt
+  %parta = shl i32 %a, %add
+  %partb = lshr i32 %a, %sub
+  %or = or i32 %parta, %partb
+  ret i32 %or
+}
+
+; Likewise for f7.
+define i32 @f16(i32 %a, i64 %amt) {
+; CHECK-LABEL: f16:
+; CHECK: rll %r2, %r2, 10(%r3)
+; CHECK: br %r14
+  %add = add i64 %amt, 10
+  %sub = sub i64 22, %amt
+  %addtrunc = trunc i64 %add to i32
+  %subtrunc = trunc i64 %sub to i32
+  %parta = shl i32 %a, %addtrunc
+  %partb = lshr i32 %a, %subtrunc
+  %or = or i32 %parta, %partb
+  ret i32 %or
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2347.1.patch
Type: text/x-patch
Size: 5041 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131206/2a857b1b/attachment.bin>


More information about the llvm-commits mailing list