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,53 @@ "for some float libcalls"), cl::location(LimitFloatPrecision), cl::init(0)); + +static bool isVectorReductionOp(const User *I); + +/// 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.setNoInfs(Instr->hasNoInfs()); + Flags.setUnsafeAlgebra(Instr->hasUnsafeAlgebra()); + Flags.setNoSignedZeros(Instr->hasNoSignedZeros()); + Flags.setAllowContract(Instr->hasAllowContract()); + Flags.setAllowReciprocal(Instr->hasAllowReciprocal()); + } + + if (const OverflowingBinaryOperator *OFBinOp = + dyn_cast(Instr)) { + Flags.setNoSignedWrap(OFBinOp->hasNoSignedWrap()); + Flags.setNoUnsignedWrap(OFBinOp->hasNoUnsignedWrap()); + } + + if (const PossiblyExactOperator *ExactOp = + dyn_cast(Instr)) + Flags.setExact(ExactOp->isExact()); + + if (isVectorReductionOp(Instr)) + Flags.setVectorReduction(true); + + 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 @@ -977,6 +1024,8 @@ } void SelectionDAGBuilder::visit(const Instruction &I) { + SDNodeFlagsAcquirer Flags(&I,this); + // Set up outgoing PHI node register values before emitting the terminator. if (isa(&I)) { HandlePHINodesInSuccessorBlocks(I.getParent()); @@ -1058,6 +1107,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 @@ -2637,42 +2692,11 @@ SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); - bool nuw = false; - bool nsw = false; - bool exact = false; - bool vec_redux = false; - FastMathFlags FMF; - - if (const OverflowingBinaryOperator *OFBinOp = - dyn_cast(&I)) { - nuw = OFBinOp->hasNoUnsignedWrap(); - nsw = OFBinOp->hasNoSignedWrap(); - } - if (const PossiblyExactOperator *ExactOp = - dyn_cast(&I)) - exact = ExactOp->isExact(); - if (const FPMathOperator *FPOp = dyn_cast(&I)) - FMF = FPOp->getFastMathFlags(); - - if (isVectorReductionOp(&I)) { - vec_redux = true; + if (isVectorReductionOp(&I)) DEBUG(dbgs() << "Detected a reduction operation:" << I << "\n"); - } - - SDNodeFlags Flags; - Flags.setExact(exact); - Flags.setNoSignedWrap(nsw); - Flags.setNoUnsignedWrap(nuw); - Flags.setVectorReduction(vec_redux); - Flags.setAllowReciprocal(FMF.allowReciprocal()); - Flags.setAllowContract(FMF.allowContract()); - Flags.setNoInfs(FMF.noInfs()); - Flags.setNoNaNs(FMF.noNaNs()); - Flags.setNoSignedZeros(FMF.noSignedZeros()); - Flags.setUnsafeAlgebra(FMF.unsafeAlgebra()); SDValue BinNodeValue = DAG.getNode(OpCode, getCurSDLoc(), Op1.getValueType(), - Op1, Op2, Flags); + Op1, Op2); setValue(&I, BinNodeValue); } @@ -6573,6 +6597,7 @@ } void SelectionDAGBuilder::visitCall(const CallInst &I) { + // 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