Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -10311,14 +10311,11 @@ DAG.isKnownNeverNaN(LHS) && DAG.isKnownNeverNaN(RHS); } -/// Generate Min/Max node -static SDValue combineMinNumMaxNum(const SDLoc &DL, EVT VT, SDValue LHS, - SDValue RHS, SDValue True, SDValue False, - ISD::CondCode CC, const TargetLowering &TLI, - SelectionDAG &DAG) { - if (!(LHS == True && RHS == False) && !(LHS == False && RHS == True)) - return SDValue(); - +static SDValue combineMinNumMaxNumImpl(const SDLoc &DL, EVT VT, SDValue LHS, + SDValue RHS, SDValue True, SDValue False, + ISD::CondCode CC, + const TargetLowering &TLI, + SelectionDAG &DAG) { EVT TransformVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); switch (CC) { case ISD::SETOLT: @@ -10359,6 +10356,43 @@ } } +/// Generate Min/Max node +static SDValue combineMinNumMaxNum(const SDLoc &DL, EVT VT, SDValue LHS, + SDValue RHS, SDValue True, SDValue False, + ISD::CondCode CC, const TargetLowering &TLI, + SelectionDAG &DAG) { + if ((LHS == True && RHS == False) || (LHS == False && RHS == True)) + return combineMinNumMaxNumImpl(DL, VT, LHS, RHS, True, False, CC, TLI, DAG); + + // If we can't directly match this, try to see if we can pull an fneg out of + // the select. + if (True.getOpcode() != ISD::FNEG) + return SDValue(); + + ConstantFPSDNode *CRHS = dyn_cast(RHS); + ConstantFPSDNode *CFalse = dyn_cast(False); + SDValue NegTrue = True.getOperand(0); + + // Try to unfold an fneg from the select if we are comparing the negated + // constant. + // + // select (setcc x, K) (fneg x), -K -> fneg(minnum(x, K)) + // + // TODO: Handle fabs + if (LHS == NegTrue && CFalse && CRHS) { + APFloat NegRHS = neg(CRHS->getValueAPF()); + if (NegRHS == CFalse->getValueAPF()) { + SDValue Combined = combineMinNumMaxNumImpl(DL, VT, LHS, RHS, NegTrue, + False, CC, TLI, DAG); + if (Combined) + return DAG.getNode(ISD::FNEG, DL, VT, Combined); + return SDValue(); + } + } + + return SDValue(); +} + /// If a (v)select has a condition value that is a sign-bit test, try to smear /// the condition operand sign-bit across the value width and use it as a mask. static SDValue foldSelectOfConstantsUsingSra(SDNode *N, SelectionDAG &DAG) { Index: llvm/test/CodeGen/ARM/unsafe-fneg-select-minnum-maxnum-combine.ll =================================================================== --- llvm/test/CodeGen/ARM/unsafe-fneg-select-minnum-maxnum-combine.ll +++ llvm/test/CodeGen/ARM/unsafe-fneg-select-minnum-maxnum-combine.ll @@ -6,12 +6,9 @@ ; CHECK: @ %bb.0: ; CHECK-NEXT: vmov.f32 s0, #-8.000000e+00 ; CHECK-NEXT: vmov s2, r0 -; CHECK-NEXT: vmov.f32 s4, #8.000000e+00 -; CHECK-NEXT: vneg.f32 s6, s2 -; CHECK-NEXT: vcmp.f32 s0, s2 -; CHECK-NEXT: vmrs APSR_nzcv, fpscr -; CHECK-NEXT: vselgt.f32 s0, s6, s4 +; CHECK-NEXT: vminnm.f32 s0, s2, s0 ; CHECK-NEXT: vmov r0, s0 +; CHECK-NEXT: eor r0, r0, #-2147483648 ; CHECK-NEXT: mov pc, lr %fneg.a = fneg nnan nsz float %a %cmp.a = fcmp nnan nsz olt float %a, -8.0 @@ -22,13 +19,10 @@ define half @select_fneg_a_or_8_cmp_olt_a_neg8_f16(half %a, half %b) #0 { ; CHECK-LABEL: select_fneg_a_or_8_cmp_olt_a_neg8_f16: ; CHECK: @ %bb.0: -; CHECK-NEXT: vmov.f16 s4, r0 ; CHECK-NEXT: vmov.f16 s0, #-8.000000e+00 -; CHECK-NEXT: vcmp.f16 s0, s4 -; CHECK-NEXT: vmov.f16 s2, #8.000000e+00 -; CHECK-NEXT: vmrs APSR_nzcv, fpscr -; CHECK-NEXT: vneg.f16 s6, s4 -; CHECK-NEXT: vselgt.f16 s0, s6, s2 +; CHECK-NEXT: vmov.f16 s2, r0 +; CHECK-NEXT: vminnm.f16 s0, s2, s0 +; CHECK-NEXT: vneg.f16 s0, s0 ; CHECK-NEXT: vmov r0, s0 ; CHECK-NEXT: mov pc, lr %fneg.a = fneg nnan nsz half %a @@ -42,12 +36,9 @@ ; CHECK: @ %bb.0: ; CHECK-NEXT: vmov.f32 s0, #-8.000000e+00 ; CHECK-NEXT: vmov s2, r0 -; CHECK-NEXT: vmov.f32 s4, #8.000000e+00 -; CHECK-NEXT: vneg.f32 s6, s2 -; CHECK-NEXT: vcmp.f32 s2, s0 -; CHECK-NEXT: vmrs APSR_nzcv, fpscr -; CHECK-NEXT: vselgt.f32 s0, s6, s4 +; CHECK-NEXT: vmaxnm.f32 s0, s2, s0 ; CHECK-NEXT: vmov r0, s0 +; CHECK-NEXT: eor r0, r0, #-2147483648 ; CHECK-NEXT: mov pc, lr %fneg.a = fneg nnan nsz float %a %cmp.a = fcmp nnan nsz ogt float %a, -8.0 @@ -58,13 +49,10 @@ define half @select_fneg_a_or_8_cmp_ogt_a_neg8_f16(half %a, half %b) #0 { ; CHECK-LABEL: select_fneg_a_or_8_cmp_ogt_a_neg8_f16: ; CHECK: @ %bb.0: -; CHECK-NEXT: vmov.f16 s4, r0 ; CHECK-NEXT: vmov.f16 s0, #-8.000000e+00 -; CHECK-NEXT: vcmp.f16 s4, s0 -; CHECK-NEXT: vmov.f16 s2, #8.000000e+00 -; CHECK-NEXT: vmrs APSR_nzcv, fpscr -; CHECK-NEXT: vneg.f16 s6, s4 -; CHECK-NEXT: vselgt.f16 s0, s6, s2 +; CHECK-NEXT: vmov.f16 s2, r0 +; CHECK-NEXT: vmaxnm.f16 s0, s2, s0 +; CHECK-NEXT: vneg.f16 s0, s0 ; CHECK-NEXT: vmov r0, s0 ; CHECK-NEXT: mov pc, lr %fneg.a = fneg nnan nsz half %a