diff options
author | Richard Sandiford <rsandifo@linux.vnet.ibm.com> | 2013-12-13 15:07:39 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@linux.vnet.ibm.com> | 2013-12-13 15:07:39 +0000 |
commit | 204537e25ebd13e5386c3ed6f62a160c7aa8390c (patch) | |
tree | 8404fd8630a1926b0d1d12ab444080fa4f2c77d7 /lib/Target/SystemZ | |
parent | fd2b2bd6b39dadf9051c0ca4c6cec8f562f8e0e4 (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.cpp | 31 |
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)); |