Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2297,24 +2297,45 @@ // Min/max matching is only viable if all output VTs are the same. if (std::equal(ValueVTs.begin(), ValueVTs.end(), ValueVTs.begin())) { - Value *LHS, *RHS; - SelectPatternFlavor SPF = - matchSelectPattern(const_cast(&I), LHS, RHS).Flavor; - ISD::NodeType Opc = ISD::DELETED_NODE; - switch (SPF) { - case SPF_UMAX: Opc = ISD::UMAX; break; - case SPF_UMIN: Opc = ISD::UMIN; break; - case SPF_SMAX: Opc = ISD::SMAX; break; - case SPF_SMIN: Opc = ISD::SMIN; break; - default: break; - } - EVT VT = ValueVTs[0]; LLVMContext &Ctx = *DAG.getContext(); auto &TLI = DAG.getTargetLoweringInfo(); while (TLI.getTypeAction(Ctx, VT) == TargetLoweringBase::TypeSplitVector) VT = TLI.getTypeToTransformTo(Ctx, VT); + Value *LHS, *RHS; + auto SPR = matchSelectPattern(const_cast(&I), LHS, RHS); + ISD::NodeType Opc = ISD::DELETED_NODE; + switch (SPR.Flavor) { + case SPF_UMAX: Opc = ISD::UMAX; break; + case SPF_UMIN: Opc = ISD::UMIN; break; + case SPF_SMAX: Opc = ISD::SMAX; break; + case SPF_SMIN: Opc = ISD::SMIN; break; + case SPF_FMINNUM: + switch (SPR.NaNBehavior) { + case SPNB_NA: llvm_unreachable("No NaN behavior for FP op?"); + case SPNB_RETURNS_NAN: Opc = ISD::FMINNAN; break; + case SPNB_RETURNS_OTHER: Opc = ISD::FMINNUM; break; + case SPNB_RETURNS_ANY: + Opc = TLI.isOperationLegalOrCustom(ISD::FMINNUM, VT) ? ISD::FMINNUM + : ISD::FMINNAN; + break; + } + break; + case SPF_FMAXNUM: + switch (SPR.NaNBehavior) { + case SPNB_NA: llvm_unreachable("No NaN behavior for FP op?"); + case SPNB_RETURNS_NAN: Opc = ISD::FMAXNAN; break; + case SPNB_RETURNS_OTHER: Opc = ISD::FMAXNUM; break; + case SPNB_RETURNS_ANY: + Opc = TLI.isOperationLegalOrCustom(ISD::FMAXNUM, VT) ? ISD::FMAXNUM + : ISD::FMAXNAN; + break; + } + break; + default: break; + } + if (Opc != ISD::DELETED_NODE && TLI.isOperationLegalOrCustom(Opc, VT) && // If the underlying comparison instruction is used by any other instruction, // the consumed instructions won't be destroyed, so it is not profitable Index: test/CodeGen/AArch64/arm64-fmax-safe.ll =================================================================== --- test/CodeGen/AArch64/arm64-fmax-safe.ll +++ test/CodeGen/AArch64/arm64-fmax-safe.ll @@ -7,7 +7,7 @@ %longer = fpext float %val to double ret double %longer -; CHECK: fmax +; CHECK: fmax s } define double @test_cross(float %in) { @@ -17,11 +17,11 @@ %longer = fpext float %val to double ret double %longer -; CHECK: fmin +; CHECK: fmin s } ; Same as previous, but with ordered comparison; -; can't be converted in safe-math mode. +; must become fminnm, not fmin. define double @test_cross_fail_nan(float %in) { ; CHECK-LABEL: test_cross_fail_nan: %cmp = fcmp olt float %in, 0.000000e+00 @@ -29,7 +29,7 @@ %longer = fpext float %val to double ret double %longer -; CHECK: fcsel s0, s0, s1, mi +; CHECK: fminnm s } ; This isn't a min or a max, but passes the first condition for swapping the Index: test/CodeGen/ARM/vminmaxnm.ll =================================================================== --- test/CodeGen/ARM/vminmaxnm.ll +++ test/CodeGen/ARM/vminmaxnm.ll @@ -343,7 +343,7 @@ ; CHECK: vmaxnm.f32 %cmp1 = fcmp fast olt float %a, -0. %cond1 = select i1 %cmp1, float %a, float -0. - %cmp2 = fcmp fast ogt float %cond1, -0. + %cmp2 = fcmp fast ugt float %cond1, -0. %cond2 = select i1 %cmp2, float %cond1, float -0. ret float %cond2 }