summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/SystemZ/SystemZISelLowering.cpp77
-rw-r--r--test/CodeGen/SystemZ/int-cmp-46.ll40
-rw-r--r--test/CodeGen/SystemZ/int-cmp-47.ll40
3 files changed, 137 insertions, 20 deletions
diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp
index 5528404a19..131fd5cf7a 100644
--- a/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -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));
diff --git a/test/CodeGen/SystemZ/int-cmp-46.ll b/test/CodeGen/SystemZ/int-cmp-46.ll
index 339ba11694..f311942b9f 100644
--- a/test/CodeGen/SystemZ/int-cmp-46.ll
+++ b/test/CodeGen/SystemZ/int-cmp-46.ll
@@ -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
+}
diff --git a/test/CodeGen/SystemZ/int-cmp-47.ll b/test/CodeGen/SystemZ/int-cmp-47.ll
index bf206ed9db..c770ccdbb9 100644
--- a/test/CodeGen/SystemZ/int-cmp-47.ll
+++ b/test/CodeGen/SystemZ/int-cmp-47.ll
@@ -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
+}