summaryrefslogtreecommitdiff
path: root/lib/Target/SystemZ
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-12-13 15:07:39 +0000
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-12-13 15:07:39 +0000
commit204537e25ebd13e5386c3ed6f62a160c7aa8390c (patch)
tree8404fd8630a1926b0d1d12ab444080fa4f2c77d7 /lib/Target/SystemZ
parentfd2b2bd6b39dadf9051c0ca4c6cec8f562f8e0e4 (diff)
[SystemZ] Make more use of LTGFR
InstCombine turns (sext (trunc)) into (ashr (shl)), then converts any comparison of the ashr against zero into a comparison of the shl against zero. This makes sense in itself, but we want to undo it for z, since the sign- extension instruction has a CC-setting form. I've included tests for both the original and InstCombined variants, but the former already worked. The patch fixes the latter. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197234 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/SystemZ')
-rw-r--r--lib/Target/SystemZ/SystemZISelLowering.cpp31
1 files changed, 31 insertions, 0 deletions
diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp
index 84b5009fd79..7d7536bffbe 100644
--- a/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1280,6 +1280,36 @@ static void adjustForFNeg(SDValue &CmpOp0, SDValue &CmpOp1, unsigned &CCMask) {
}
}
+// Check whether CmpOp0 is (shl X, 32), CmpOp1 is 0, and whether X is
+// also sign-extended. In that case it is better to test the result
+// of the sign extension using LTGFR.
+//
+// This case is important because InstCombine transforms a comparison
+// with (sext (trunc X)) into a comparison with (shl X, 32).
+static void adjustForLTGFR(SDValue &CmpOp0, SDValue &CmpOp1,
+ unsigned &IcmpType) {
+ // Check for a comparison between (shl X, 32) and 0.
+ if (CmpOp0.getOpcode() == ISD::SHL &&
+ CmpOp0.getValueType() == MVT::i64 &&
+ CmpOp1.getOpcode() == ISD::Constant &&
+ cast<ConstantSDNode>(CmpOp1)->getZExtValue() == 0) {
+ ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(CmpOp0.getOperand(1));
+ if (C1 && C1->getZExtValue() == 32) {
+ SDValue ShlOp0 = CmpOp0.getOperand(0);
+ // See whether X has any SIGN_EXTEND_INREG uses.
+ for (SDNode::use_iterator I = ShlOp0->use_begin(), E = ShlOp0->use_end();
+ I != E; ++I) {
+ SDNode *N = *I;
+ if (N->getOpcode() == ISD::SIGN_EXTEND_INREG &&
+ cast<VTSDNode>(N->getOperand(1))->getVT() == MVT::i32) {
+ CmpOp0 = SDValue(N, 0);
+ return;
+ }
+ }
+ }
+ }
+}
+
// 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) {
@@ -1497,6 +1527,7 @@ static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG,
adjustForTestUnderMask(DAG, Opcode, CmpOp0, CmpOp1, CCValid, CCMask,
ICmpType);
adjustForFNeg(CmpOp0, CmpOp1, CCMask);
+ adjustForLTGFR(CmpOp0, CmpOp1, ICmpType);
if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM)
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1,
DAG.getConstant(ICmpType, MVT::i32));