[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
This commit is contained in:
Richard Sandiford 2013-12-11 11:45:08 +00:00
parent 3c14ba5962
commit e54c1060a6
2 changed files with 70 additions and 4 deletions

View File

@ -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));

View File

@ -365,3 +365,43 @@ store:
exit:
ret float %res
}
; Test another form of f7 in which the condition is based on the unnegated
; result. This is what InstCombine would produce.
define float @f18(float %dummy, float %a, float *%dest) {
; CHECK-LABEL: f18:
; CHECK: lnebr %f0, %f2
; CHECK-NEXT: jl .L{{.*}}
; CHECK: br %r14
entry:
%abs = call float @llvm.fabs.f32(float %a)
%res = fsub float -0.0, %abs
%cmp = fcmp ogt float %abs, 0.0
br i1 %cmp, label %exit, label %store
store:
store float %res, float *%dest
br label %exit
exit:
ret float %res
}
; Similarly for f8.
define float @f19(float %dummy, float %a, float *%dest) {
; CHECK-LABEL: f19:
; CHECK: lcebr %f0, %f2
; CHECK-NEXT: jle .L{{.*}}
; CHECK: br %r14
entry:
%res = fsub float -0.0, %a
%cmp = fcmp oge float %a, 0.0
br i1 %cmp, label %exit, label %store
store:
store float %res, float *%dest
br label %exit
exit:
ret float %res
}