Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -661,6 +661,10 @@ SDValue getValue(const Value *V); bool findValue(const Value *V) const; + // returns DAG node of SDValue present in NodeMap for + // a given Value. + SDNode * getDAGNode(const Value *); + SDValue getNonRegisterValue(const Value *V); SDValue getValueImpl(const Value *V); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -84,6 +84,35 @@ "for some float libcalls"), cl::location(LimitFloatPrecision), cl::init(0)); + +/// This class is used for propagating Flags from Instruction to SDNode. +/// These flags are later used by accessing SDNode during different +/// DAG phases. +class SDNodeFlagsAcquirer { +public: + SDNodeFlagsAcquirer(const Instruction * I, SelectionDAGBuilder *SDB): + Instr(I), SelDB(SDB) {} + + ~SDNodeFlagsAcquirer() { + SDNode * Node = SelDB->getDAGNode(Instr); + if (Node) { + SDNodeFlags Flags = Node->getFlags(); + if (isa(*Instr)) { + Flags.setNoNaNs(Instr->hasNoNaNs()); + Flags.setUnsafeAlgebra(Instr->hasUnsafeAlgebra()); + Flags.setNoSignedZeros(Instr->hasNoSignedZeros()); + Flags.setAllowContract(Instr->hasAllowContract()); + Flags.setAllowReciprocal(Instr->hasAllowReciprocal()); + } + Node->setFlags(Flags); + } + } + +private: + const Instruction * Instr; + SelectionDAGBuilder *SelDB; +}; + // Limit the width of DAG chains. This is important in general to prevent // DAG-based analysis from blowing up. For example, alias analysis and // load clustering may not complete in reasonable time. It is difficult to @@ -1058,6 +1087,12 @@ return Result; } +SDNode * SelectionDAGBuilder::getDAGNode(const Value *V) { + if (NodeMap.find(V) == NodeMap.end()) + return nullptr; + return NodeMap[V].getNode(); +} + /// getValue - Return an SDValue for the given Value. SDValue SelectionDAGBuilder::getValue(const Value *V) { // If we already have an SDValue for this value, use it. It's important @@ -6573,6 +6608,8 @@ } void SelectionDAGBuilder::visitCall(const CallInst &I) { + SDNodeFlagsAcquirer Flags(&I,this); + // Handle inline assembly differently. if (isa(I.getCalledValue())) { visitInlineAsm(&I); Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -34328,14 +34328,25 @@ // So they always return Op0 if either input is a NaN. However, we can still // use those instructions for fmaxnum by selecting away a NaN input. - // If either operand is NaN, the 2nd source operand (Op0) is passed through. - auto MinMaxOp = N->getOpcode() == ISD::FMAXNUM ? X86ISD::FMAX : X86ISD::FMIN; - SDValue MinOrMax = DAG.getNode(MinMaxOp, DL, VT, Op1, Op0); - SDValue IsOp0Nan = DAG.getSetCC(DL, SetCCType , Op0, Op0, ISD::SETUO); + SDNodeFlags Flags = N->getFlags(); + bool FastMathFlag = Flags.hasUnsafeAlgebra() || Flags.hasNoNaNs(); - // If Op0 is a NaN, select Op1. Otherwise, select the max. If both operands - // are NaN, the NaN value of Op1 is the result. - return DAG.getSelect(DL, VT, IsOp0Nan, Op1, MinOrMax); + if (!FastMathFlag) { + // If either operand is NaN, the 2nd source operand (Op0) is passed through. + auto MinMaxOp = N->getOpcode() == ISD::FMAXNUM ? X86ISD::FMAX : X86ISD::FMIN; + SDValue MinOrMax = DAG.getNode(MinMaxOp, DL, VT, Op1, Op0); + SDValue IsOp0Nan = DAG.getSetCC(DL, SetCCType , Op0, Op0, ISD::SETUO); + + // If Op0 is a NaN, select Op1. Otherwise, select the max. If both operands + // are NaN, the NaN value of Op1 is the result. + return DAG.getSelect(DL, VT, IsOp0Nan, Op1, MinOrMax); + } else { + // FastMath assume operands and result are not a NaN. + auto MinMaxOp = N->getOpcode() == ISD::FMAXNUM ? ISD::SETUGE : ISD::SETULE; + SDValue CCRes = DAG.getSetCC(DL, SetCCType , Op0, Op1, MinMaxOp); + + return DAG.getSelect(DL, VT, CCRes, Op0, Op1); + } } /// Do target-specific dag combines on X86ISD::ANDNP nodes. Index: test/CodeGen/X86/pr34149.ll =================================================================== --- test/CodeGen/X86/pr34149.ll +++ test/CodeGen/X86/pr34149.ll @@ -8,9 +8,7 @@ define <4 x double> @via_minnum(<4 x double> %x, <4 x double> %y) { ; CHECK-LABEL: via_minnum: ; CHECK: # BB#0: -; CHECK-NEXT: vminpd %ymm0, %ymm1, %ymm2 -; CHECK-NEXT: vcmpunordpd %ymm0, %ymm0, %ymm0 -; CHECK-NEXT: vblendvpd %ymm0, %ymm1, %ymm2, %ymm0 +; CHECK-NEXT: vminpd %ymm0, %ymm1, %ymm0 ; CHECK-NEXT: retq %z = call fast <4 x double> @llvm.minnum.v4f64(<4 x double> %x, <4 x double> %y) readnone ret <4 x double> %z @@ -19,9 +17,7 @@ define <4 x double> @via_maxnum(<4 x double> %x, <4 x double> %y) { ; CHECK-LABEL: via_maxnum: ; CHECK: # BB#0: -; CHECK-NEXT: vmaxpd %ymm0, %ymm1, %ymm2 -; CHECK-NEXT: vcmpunordpd %ymm0, %ymm0, %ymm0 -; CHECK-NEXT: vblendvpd %ymm0, %ymm1, %ymm2, %ymm0 +; CHECK-NEXT: vmaxpd %ymm0, %ymm1, %ymm0 ; CHECK-NEXT: retq %z = call fast <4 x double> @llvm.maxnum.v4f64(<4 x double> %x, <4 x double> %y) readnone ret <4 x double> %z