diff options
author | Richard Sandiford <rsandifo@linux.vnet.ibm.com> | 2013-12-11 11:45:08 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@linux.vnet.ibm.com> | 2013-12-11 11:45:08 +0000 |
commit | e54c1060a6a3f2a30b26c3289c08ae1bc8a845b9 (patch) | |
tree | 9cdb87baabfdf2ab0619894ffef44de7212952dd /lib/Target/SystemZ | |
parent | 3c14ba596248d64cc3f464e244d23abf934cde3e (diff) |
[SystemZ] Optimize fcmp X, 0 in cases where X is also negated
In such cases it's often better to test the result of the negation instead,
since the negation also sets CC.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197032 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/SystemZ')
-rw-r--r-- | lib/Target/SystemZ/SystemZISelLowering.cpp | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index b0a8fca7de7..84b5009fd79 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1252,6 +1252,34 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, return false; } +// Return a version of comparison CC mask CCMask in which the LT and GT +// actions are swapped. +static unsigned reverseCCMask(unsigned CCMask) { + return ((CCMask & SystemZ::CCMASK_CMP_EQ) | + (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) | + (CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) | + (CCMask & SystemZ::CCMASK_CMP_UO)); +} + +// CmpOp0 and CmpOp1 are being compared using CC mask CCMask. Check whether +// CmpOp0 is a floating-point result that is also negated and if CmpOp1 +// is zero. In this case we can use the negation to set CC, so avoiding +// separate LOAD AND TEST and LOAD (NEGATIVE/COMPLEMENT) instructions. +static void adjustForFNeg(SDValue &CmpOp0, SDValue &CmpOp1, unsigned &CCMask) { + ConstantFPSDNode *C1 = dyn_cast<ConstantFPSDNode>(CmpOp1); + if (C1 && C1->isZero()) { + for (SDNode::use_iterator I = CmpOp0->use_begin(), E = CmpOp0->use_end(); + I != E; ++I) { + SDNode *N = *I; + if (N->getOpcode() == ISD::FNEG) { + CmpOp0 = SDValue(N, 0); + CCMask = reverseCCMask(CCMask); + 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) { @@ -1463,14 +1491,12 @@ static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG, if (shouldSwapCmpOperands(CmpOp0, CmpOp1, ICmpType)) { std::swap(CmpOp0, CmpOp1); - CCMask = ((CCMask & SystemZ::CCMASK_CMP_EQ) | - (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) | - (CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) | - (CCMask & SystemZ::CCMASK_CMP_UO)); + CCMask = reverseCCMask(CCMask); } adjustForTestUnderMask(DAG, Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType); + adjustForFNeg(CmpOp0, CmpOp1, CCMask); if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM) return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1, DAG.getConstant(ICmpType, MVT::i32)); |