[SystemZ] Generalize RxSBG SRA case
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Thu, 18 Jul 2013 10:14:55 +0000 (10:14 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Thu, 18 Jul 2013 10:14:55 +0000 (10:14 +0000)
The original code only folded SRA into ROTATE ... SELECTED BITS
if there was no outer shift.  This patch splits out that check
and generalises it slightly.  The extra cases aren't really that
interesting, but this is paving the way for RNSBG support.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186571 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
test/CodeGen/SystemZ/risbg-01.ll

index 67e9d217ee3a8298860147f41309bfe9089121df..0f9a37ed0cf87379dcdcdc7dc56f762530451836 100644 (file)
@@ -647,9 +647,29 @@ static bool refineRxSBGMask(RxSBGOperands &RxSBG, uint64_t Mask) {
   return false;
 }
 
+// RxSBG.Input is a shift of Count bits in the direction given by IsLeft.
+// Return true if the result depends on the signs or zeros that are
+// shifted in.
+static bool shiftedInBitsMatter(RxSBGOperands &RxSBG, uint64_t Count,
+                                bool IsLeft) {
+  // Work out which bits of the shift result are zeros or sign copies.
+  uint64_t ShiftedIn = allOnes(Count);
+  if (!IsLeft)
+    ShiftedIn <<= RxSBG.BitSize - Count;
+
+  // Rotate that mask in the same way as RxSBG.Input is rotated.
+  if (RxSBG.Rotate != 0)
+    ShiftedIn = ((ShiftedIn << RxSBG.Rotate) |
+                 (ShiftedIn >> (64 - RxSBG.Rotate)));
+
+  // Fail if any of the zero or sign bits are used.
+  return (ShiftedIn & RxSBG.Mask) != 0;
+}
+
 bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) {
   SDValue N = RxSBG.Input;
-  switch (N.getOpcode()) {
+  unsigned Opcode = N.getOpcode();
+  switch (Opcode) {
   case ISD::AND: {
     ConstantSDNode *MaskNode =
       dyn_cast<ConstantSDNode>(N.getOperand(1).getNode());
@@ -704,41 +724,30 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) {
     return true;
   }
 
-  case ISD::SRL: {
-    // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count),
-    // which is similar to SLL above.
-    ConstantSDNode *CountNode =
-      dyn_cast<ConstantSDNode>(N.getOperand(1).getNode());
-    if (!CountNode)
-      return false;
-
-    uint64_t Count = CountNode->getZExtValue();
-    if (Count < 1 ||
-        Count >= RxSBG.BitSize ||
-        !refineRxSBGMask(RxSBG, allOnes(RxSBG.BitSize - Count)))
-      return false;
-
-    RxSBG.Rotate = (RxSBG.Rotate - Count) & 63;
-    RxSBG.Input = N.getOperand(0);
-    return true;
-  }
-
+  case ISD::SRL:
   case ISD::SRA: {
-    // Treat (sra X, count) as (rotl X, size-count) as long as the top
-    // count bits from Ops.Input are ignored.
     ConstantSDNode *CountNode =
       dyn_cast<ConstantSDNode>(N.getOperand(1).getNode());
     if (!CountNode)
       return false;
 
     uint64_t Count = CountNode->getZExtValue();
-    if (RxSBG.Rotate != 0 ||
-        Count < 1 ||
-        Count >= RxSBG.BitSize ||
-        RxSBG.Start < 64 - (RxSBG.BitSize - Count))
+    if (Count < 1 || Count >= RxSBG.BitSize)
       return false;
 
-    RxSBG.Rotate = -Count & 63;
+    if (Opcode == ISD::SRA) {
+      // Treat (sra X, count) as (rotl X, size-count) as long as the top
+      // Count bits from RxSBG.Input are ignored.
+      if (shiftedInBitsMatter(RxSBG, Count, false))
+        return false;
+    } else {
+      // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count),
+      // which is similar to SLL above.
+      if (!refineRxSBGMask(RxSBG, allOnes(RxSBG.BitSize - Count)))
+        return false;
+    }
+
+    RxSBG.Rotate = (RxSBG.Rotate - Count) & 63;
     RxSBG.Input = N.getOperand(0);
     return true;
   }
index 0c6826ad1f331d017404279a77a88e05155d7271..6f89fefd9fe93ea30f658fb7e7c1e96604eb8465 100644 (file)
@@ -416,3 +416,41 @@ define i64 @f37(i64 %foo) {
   %shl = lshr i64 %and, 1
   ret i64 %shl
 }
+
+; Test a combination involving a large ASHR and a shift left.  We can't
+; use RISBG there.
+define i64 @f38(i64 %foo) {
+; CHECK-LABEL: f38:
+; CHECK: srag {{%r[0-5]}}
+; CHECK: sllg {{%r[0-5]}}
+; CHECK: br %r14
+  %ashr = ashr i64 %foo, 32
+  %shl = shl i64 %ashr, 5
+  ret i64 %shl
+}
+
+; Try a similar thing in which no shifted sign bits are kept.
+define i64 @f39(i64 %foo, i64 *%dest) {
+; CHECK-LABEL: f39:
+; CHECK: srag [[REG:%r[01345]]], %r2, 35
+; CHECK: risbg %r2, %r2, 33, 189, 31
+; CHECK: br %r14
+  %ashr = ashr i64 %foo, 35
+  store i64 %ashr, i64 *%dest
+  %shl = shl i64 %ashr, 2
+  %and = and i64 %shl, 2147483647
+  ret i64 %and
+}
+
+; ...and again with the next highest shift value, where one sign bit is kept.
+define i64 @f40(i64 %foo, i64 *%dest) {
+; CHECK-LABEL: f40:
+; CHECK: srag [[REG:%r[01345]]], %r2, 36
+; CHECK: risbg %r2, [[REG]], 33, 189, 2
+; CHECK: br %r14
+  %ashr = ashr i64 %foo, 36
+  store i64 %ashr, i64 *%dest
+  %shl = shl i64 %ashr, 2
+  %and = and i64 %shl, 2147483647
+  ret i64 %and
+}