[SystemZ] Make more use of TMHH
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Fri, 13 Dec 2013 15:46:55 +0000 (15:46 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Fri, 13 Dec 2013 15:46:55 +0000 (15:46 +0000)
This originally came about after noticing that InstCombine turns
some of the TMHH (icmp (and...), ...) tests into plain comparisons.
Since there is no instruction to compare with a 64-bit immediate,
TMHH is generally better than an ordered comparison for the cases
that it can handle.

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

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

index 49547d319ebdbd9cbdef59ed334a8208b28a457d..6c443b59f7982f6c766056ab4776c0daf98f3886 100644 (file)
@@ -1440,47 +1440,75 @@ static void adjustForTestUnderMask(SelectionDAG &DAG, Comparison &C) {
   uint64_t CmpVal = ConstOp1->getZExtValue();
 
   // Check whether the nonconstant input is an AND with a constant mask.
-  if (C.Op0.getOpcode() != ISD::AND)
-    return;
-  SDValue AndOp0 = C.Op0.getOperand(0);
-  SDValue AndOp1 = C.Op0.getOperand(1);
-  ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(AndOp1.getNode());
-  if (!Mask)
-    return;
-  uint64_t MaskVal = Mask->getZExtValue();
+  Comparison NewC(C);
+  uint64_t MaskVal;
+  ConstantSDNode *Mask = 0;
+  if (C.Op0.getOpcode() == ISD::AND) {
+    NewC.Op0 = C.Op0.getOperand(0);
+    NewC.Op1 = C.Op0.getOperand(1);
+    Mask = dyn_cast<ConstantSDNode>(NewC.Op1);
+    if (!Mask)
+      return;
+    MaskVal = Mask->getZExtValue();
+  } else {
+    // There is no instruction to compare with a 64-bit immediate
+    // so use TMHH instead if possible.  We need an unsigned ordered
+    // comparison with an i64 immediate.
+    if (NewC.Op0.getValueType() != MVT::i64 ||
+        NewC.CCMask == SystemZ::CCMASK_CMP_EQ ||
+        NewC.CCMask == SystemZ::CCMASK_CMP_NE ||
+        NewC.ICmpType == SystemZICMP::SignedOnly)
+      return;
+    // Convert LE and GT comparisons into LT and GE.
+    if (NewC.CCMask == SystemZ::CCMASK_CMP_LE ||
+        NewC.CCMask == SystemZ::CCMASK_CMP_GT) {
+      if (CmpVal == uint64_t(-1))
+        return;
+      CmpVal += 1;
+      NewC.CCMask ^= SystemZ::CCMASK_CMP_EQ;
+    }
+    // If the low N bits of Op1 are zero than the low N bits of Op0 can
+    // be masked off without changing the result.
+    MaskVal = -(CmpVal & -CmpVal);
+    NewC.ICmpType = SystemZICMP::UnsignedOnly;
+  }
 
   // Check whether the combination of mask, comparison value and comparison
   // type are suitable.
-  unsigned BitSize = C.Op0.getValueType().getSizeInBits();
+  unsigned BitSize = NewC.Op0.getValueType().getSizeInBits();
   unsigned NewCCMask, ShiftVal;
-  if (C.ICmpType != SystemZICMP::SignedOnly &&
-      AndOp0.getOpcode() == ISD::SHL &&
-      isSimpleShift(AndOp0, ShiftVal) &&
-      (NewCCMask = getTestUnderMaskCond(BitSize, C.CCMask, MaskVal >> ShiftVal,
+  if (NewC.ICmpType != SystemZICMP::SignedOnly &&
+      NewC.Op0.getOpcode() == ISD::SHL &&
+      isSimpleShift(NewC.Op0, ShiftVal) &&
+      (NewCCMask = getTestUnderMaskCond(BitSize, NewC.CCMask,
+                                        MaskVal >> ShiftVal,
                                         CmpVal >> ShiftVal,
                                         SystemZICMP::Any))) {
-    AndOp0 = AndOp0.getOperand(0);
-    AndOp1 = DAG.getConstant(MaskVal >> ShiftVal, AndOp0.getValueType());
-  } else if (C.ICmpType != SystemZICMP::SignedOnly &&
-             AndOp0.getOpcode() == ISD::SRL &&
-             isSimpleShift(AndOp0, ShiftVal) &&
-             (NewCCMask = getTestUnderMaskCond(BitSize, C.CCMask,
+    NewC.Op0 = NewC.Op0.getOperand(0);
+    MaskVal >>= ShiftVal;
+  } else if (NewC.ICmpType != SystemZICMP::SignedOnly &&
+             NewC.Op0.getOpcode() == ISD::SRL &&
+             isSimpleShift(NewC.Op0, ShiftVal) &&
+             (NewCCMask = getTestUnderMaskCond(BitSize, NewC.CCMask,
                                                MaskVal << ShiftVal,
                                                CmpVal << ShiftVal,
                                                SystemZICMP::UnsignedOnly))) {
-    AndOp0 = AndOp0.getOperand(0);
-    AndOp1 = DAG.getConstant(MaskVal << ShiftVal, AndOp0.getValueType());
+    NewC.Op0 = NewC.Op0.getOperand(0);
+    MaskVal <<= ShiftVal;
   } else {
-    NewCCMask = getTestUnderMaskCond(BitSize, C.CCMask, MaskVal, CmpVal,
-                                     C.ICmpType);
+    NewCCMask = getTestUnderMaskCond(BitSize, NewC.CCMask, MaskVal, CmpVal,
+                                     NewC.ICmpType);
     if (!NewCCMask)
       return;
   }
 
   // Go ahead and make the change.
   C.Opcode = SystemZISD::TM;
-  C.Op0 = AndOp0;
-  C.Op1 = AndOp1;
+  C.Op0 = NewC.Op0;
+  if (Mask && Mask->getZExtValue() == MaskVal)
+    C.Op1 = SDValue(Mask, 0);
+  else
+    C.Op1 = DAG.getConstant(MaskVal, C.Op0.getValueType());
   C.CCValid = SystemZ::CCMASK_TM;
   C.CCMask = NewCCMask;
 }
index 9ebcbfe525babda2c9fb5cd2a6113e6e7bc57a3c..038a25b2a6eda07f420706293f99dc75fce45ba0 100644 (file)
@@ -232,3 +232,112 @@ store:
 exit:
   ret void
 }
+
+; Check a case where TMHH can be used to implement a ult comparison.
+define void @f13(i64 %a) {
+; CHECK-LABEL: f13:
+; CHECK: tmhh %r2, 49152
+; CHECK: jno {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %cmp = icmp ult i64 %a, 13835058055282163712
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; And again with ule.
+define void @f14(i64 %a) {
+; CHECK-LABEL: f14:
+; CHECK: tmhh %r2, 49152
+; CHECK: jno {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %cmp = icmp ule i64 %a, 13835058055282163711
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; And again with ugt.
+define void @f15(i64 %a) {
+; CHECK-LABEL: f15:
+; CHECK: tmhh %r2, 49152
+; CHECK: jo {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %cmp = icmp ugt i64 %a, 13835058055282163711
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; And again with uge.
+define void @f16(i64 %a) {
+; CHECK-LABEL: f16:
+; CHECK: tmhh %r2, 49152
+; CHECK: jo {{\.L.*}}
+; CHECK: br %r14
+entry:
+  %cmp = icmp uge i64 %a, 13835058055282163712
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Decrease the constant from f13 to make TMHH invalid.
+define void @f17(i64 %a) {
+; CHECK-LABEL: f17:
+; CHECK-NOT: tmhh
+; CHECK: llihh {{%r[0-5]}}, 49151
+; CHECK-NOT: tmhh
+; CHECK: br %r14
+entry:
+  %cmp = icmp ult i64 %a, 13834776580305453056
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Check that we don't use TMHH just to test the top bit.
+define void @f18(i64 %a) {
+; CHECK-LABEL: f18:
+; CHECK-NOT: tmhh
+; CHECK: cgijhe %r2, 0,
+; CHECK: br %r14
+entry:
+  %cmp = icmp ult i64 %a, 9223372036854775808
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 1, i32 *@g
+  br label %exit
+
+exit:
+  ret void
+}