[SystemZ] Try to fold shifts into TMxx
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Fri, 13 Sep 2013 09:09:50 +0000 (09:09 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Fri, 13 Sep 2013 09:09:50 +0000 (09:09 +0000)
E.g. "SRL %r2, 2; TMLL %r2, 1" => "TMLL %r2, 4".

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

lib/Target/SystemZ/SystemZISelLowering.cpp
test/CodeGen/SystemZ/int-cmp-46.ll
test/CodeGen/SystemZ/int-cmp-47.ll

index 5528404a19579827f478e5b6812dee802311f0b6..131fd5cf7aeb42917de373845432e42f453a4d43 100644 (file)
@@ -1135,17 +1135,37 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
   return false;
 }
 
-// Check whether the CC value produced by TEST UNDER MASK is descriptive
-// enough to handle an AND with Mask followed by a comparison of type Opcode
-// with CmpVal.  CCMask says which comparison result is being tested and
-// BitSize is the number of bits in the operands.  Return the CC mask that
-// should be used for the TEST UNDER MASK result, or 0 if the condition is
-// too complex.
+// Return true if shift operation N has an in-range constant shift value.
+// Store it in ShiftVal if so.
+static bool isSimpleShift(SDValue N, unsigned &ShiftVal) {
+  ConstantSDNode *Shift = dyn_cast<ConstantSDNode>(N.getOperand(1));
+  if (!Shift)
+    return false;
+
+  uint64_t Amount = Shift->getZExtValue();
+  if (Amount >= N.getValueType().getSizeInBits())
+    return false;
+
+  ShiftVal = Amount;
+  return true;
+}
+
+// Check whether an AND with Mask is suitable for a TEST UNDER MASK
+// instruction and whether the CC value is descriptive enough to handle
+// a comparison of type Opcode between the AND result and CmpVal.
+// CCMask says which comparison result is being tested and BitSize is
+// the number of bits in the operands.  If TEST UNDER MASK can be used,
+// return the corresponding CC mask, otherwise return 0.
 static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
                                      uint64_t Mask, uint64_t CmpVal,
                                      unsigned ICmpType) {
   assert(Mask != 0 && "ANDs with zero should have been removed by now");
 
+  // Check whether the mask is suitable for TMHH, TMHL, TMLH or TMLL.
+  if (!SystemZ::isImmLL(Mask) && !SystemZ::isImmLH(Mask) &&
+      !SystemZ::isImmHL(Mask) && !SystemZ::isImmHH(Mask))
+    return 0;
+
   // Work out the masks for the lowest and highest bits.
   unsigned HighShift = 63 - countLeadingZeros(Mask);
   uint64_t High = uint64_t(1) << HighShift;
@@ -1230,13 +1250,15 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
 // implemented as a TEST UNDER MASK instruction when the condition being
 // tested is as described by CCValid and CCMask.  Update the arguments
 // with the TM version if so.
-static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
-                                   SDValue &CmpOp1, unsigned &CCValid,
-                                   unsigned &CCMask, unsigned &ICmpType) {
+static void adjustForTestUnderMask(SelectionDAG &DAG, unsigned &Opcode,
+                                   SDValue &CmpOp0, SDValue &CmpOp1,
+                                   unsigned &CCValid, unsigned &CCMask,
+                                   unsigned &ICmpType) {
   // Check that we have a comparison with a constant.
   ConstantSDNode *ConstCmpOp1 = dyn_cast<ConstantSDNode>(CmpOp1);
   if (!ConstCmpOp1)
     return;
+  uint64_t CmpVal = ConstCmpOp1->getZExtValue();
 
   // Check whether the nonconstant input is an AND with a constant mask.
   if (CmpOp0.getOpcode() != ISD::AND)
@@ -1246,21 +1268,35 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
   ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(AndOp1.getNode());
   if (!Mask)
     return;
-
-  // Check whether the mask is suitable for TMHH, TMHL, TMLH or TMLL.
   uint64_t MaskVal = Mask->getZExtValue();
-  if (!SystemZ::isImmLL(MaskVal) && !SystemZ::isImmLH(MaskVal) &&
-      !SystemZ::isImmHL(MaskVal) && !SystemZ::isImmHH(MaskVal))
-    return;
 
   // Check whether the combination of mask, comparison value and comparison
   // type are suitable.
   unsigned BitSize = CmpOp0.getValueType().getSizeInBits();
-  unsigned NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal,
-                                            ConstCmpOp1->getZExtValue(),
-                                            ICmpType);
-  if (!NewCCMask)
-    return;
+  unsigned NewCCMask, ShiftVal;
+  if (ICmpType != SystemZICMP::SignedOnly &&
+      AndOp0.getOpcode() == ISD::SHL &&
+      isSimpleShift(AndOp0, ShiftVal) &&
+      (NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal >> ShiftVal,
+                                        CmpVal >> ShiftVal,
+                                        SystemZICMP::Any))) {
+    AndOp0 = AndOp0.getOperand(0);
+    AndOp1 = DAG.getConstant(MaskVal >> ShiftVal, AndOp0.getValueType());
+  } else if (ICmpType != SystemZICMP::SignedOnly &&
+             AndOp0.getOpcode() == ISD::SRL &&
+             isSimpleShift(AndOp0, ShiftVal) &&
+             (NewCCMask = getTestUnderMaskCond(BitSize, CCMask,
+                                               MaskVal << ShiftVal,
+                                               CmpVal << ShiftVal,
+                                               SystemZICMP::UnsignedOnly))) {
+    AndOp0 = AndOp0.getOperand(0);
+    AndOp1 = DAG.getConstant(MaskVal << ShiftVal, AndOp0.getValueType());
+  } else {
+    NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal, CmpVal,
+                                     ICmpType);
+    if (!NewCCMask)
+      return;
+  }
 
   // Go ahead and make the change.
   Opcode = SystemZISD::TM;
@@ -1316,7 +1352,8 @@ static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG,
               (CCMask & SystemZ::CCMASK_CMP_UO));
   }
 
-  adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType);
+  adjustForTestUnderMask(DAG, Opcode, CmpOp0, CmpOp1, CCValid, CCMask,
+                         ICmpType);
   if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM)
     return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1,
                        DAG.getConstant(ICmpType, MVT::i32));
index 339ba11694a4dc0aa0a0eb774b380d9c47277484..f311942b9f8624b587f373f95574e308f11d8bd2 100644 (file)
@@ -449,3 +449,43 @@ store:
 exit:
   ret void
 }
+
+; Check that we can fold an SHL into a TMxx mask.
+define void @f24(i32 %a) {
+; CHECK-LABEL: f24:
+; CHECK: tmll %r2, 255
+; CHECK: jne {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %shl = shl i32 %a, 12
+  %and = and i32 %shl, 1044480
+  %cmp = icmp ne i32 %and, 0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Check that we can fold an SHR into a TMxx mask.
+define void @f25(i32 %a) {
+; CHECK-LABEL: f25:
+; CHECK: tmlh %r2, 512
+; CHECK: jne {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %shr = lshr i32 %a, 25
+  %and = and i32 %shr, 1
+  %cmp = icmp ne i32 %and, 0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
index bf206ed9db60d5fc640d6c1cad89aa3c93efebad..c770ccdbb96968d9136058a0a0deef3ec8241f4a 100644 (file)
@@ -191,3 +191,43 @@ store:
 exit:
   ret void
 }
+
+; Check that we can fold an SHL into a TMxx mask.
+define void @f11(i64 %a) {
+; CHECK-LABEL: f11:
+; CHECK: tmhl %r2, 32768
+; CHECK: jne {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %shl = shl i64 %a, 1
+  %and = and i64 %shl, 281474976710656
+  %cmp = icmp ne i64 %and, 0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Check that we can fold an SHR into a TMxx mask.
+define void @f12(i64 %a) {
+; CHECK-LABEL: f12:
+; CHECK: tmhh %r2, 256
+; CHECK: jne {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %shr = lshr i64 %a, 56
+  %and = and i64 %shr, 1
+  %cmp = icmp ne i64 %and, 0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}