diff options
Diffstat (limited to 'llvm/lib/CodeGen')
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 308 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 240 | 
2 files changed, 272 insertions, 276 deletions
| diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 2b47407393d..9b678b22b46 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -785,252 +785,6 @@ void DAGCombiner::deleteAndRecombine(SDNode *N) {    DAG.DeleteNode(N);  } -/// Return 1 if we can compute the negated form of the specified expression for -/// the same cost as the expression itself, or 2 if we can compute the negated -/// form more cheaply than the expression itself. -static char isNegatibleForFree(SDValue Op, bool LegalOperations, -                               const TargetLowering &TLI, -                               const TargetOptions *Options, -                               bool ForCodeSize, -                               unsigned Depth = 0) { -  // fneg is removable even if it has multiple uses. -  if (Op.getOpcode() == ISD::FNEG) -    return 2; - -  // Don't allow anything with multiple uses unless we know it is free. -  EVT VT = Op.getValueType(); -  const SDNodeFlags Flags = Op->getFlags(); -  if (!Op.hasOneUse() && -      !(Op.getOpcode() == ISD::FP_EXTEND && -        TLI.isFPExtFree(VT, Op.getOperand(0).getValueType()))) -    return 0; - -  // Don't recurse exponentially. -  if (Depth > SelectionDAG::MaxRecursionDepth) -    return 0; - -  switch (Op.getOpcode()) { -  default: return false; -  case ISD::ConstantFP: { -    if (!LegalOperations) -      return 1; - -    // Don't invert constant FP values after legalization unless the target says -    // the negated constant is legal. -    return TLI.isOperationLegal(ISD::ConstantFP, VT) || -           TLI.isFPImmLegal(neg(cast<ConstantFPSDNode>(Op)->getValueAPF()), VT, -                            ForCodeSize); -  } -  case ISD::BUILD_VECTOR: { -    // Only permit BUILD_VECTOR of constants. -    if (llvm::any_of(Op->op_values(), [&](SDValue N) { -          return !N.isUndef() && !isa<ConstantFPSDNode>(N); -        })) -      return 0; -    if (!LegalOperations) -      return 1; -    if (TLI.isOperationLegal(ISD::ConstantFP, VT) && -        TLI.isOperationLegal(ISD::BUILD_VECTOR, VT)) -      return 1; -    return llvm::all_of(Op->op_values(), [&](SDValue N) { -      return N.isUndef() || -             TLI.isFPImmLegal(neg(cast<ConstantFPSDNode>(N)->getValueAPF()), VT, -                              ForCodeSize); -    }); -  } -  case ISD::FADD: -    if (!Options->NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) -      return 0; - -    // After operation legalization, it might not be legal to create new FSUBs. -    if (LegalOperations && !TLI.isOperationLegalOrCustom(ISD::FSUB, VT)) -      return 0; - -    // fold (fneg (fadd A, B)) -> (fsub (fneg A), B) -    if (char V = isNegatibleForFree(Op.getOperand(0), LegalOperations, TLI, -                                    Options, ForCodeSize, Depth + 1)) -      return V; -    // fold (fneg (fadd A, B)) -> (fsub (fneg B), A) -    return isNegatibleForFree(Op.getOperand(1), LegalOperations, TLI, Options, -                              ForCodeSize, Depth + 1); -  case ISD::FSUB: -    // We can't turn -(A-B) into B-A when we honor signed zeros. -    if (!Options->NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) -      return 0; - -    // fold (fneg (fsub A, B)) -> (fsub B, A) -    return 1; - -  case ISD::FMUL: -  case ISD::FDIV: -    // fold (fneg (fmul X, Y)) -> (fmul (fneg X), Y) or (fmul X, (fneg Y)) -    if (char V = isNegatibleForFree(Op.getOperand(0), LegalOperations, TLI, -                                    Options, ForCodeSize, Depth + 1)) -      return V; - -    // Ignore X * 2.0 because that is expected to be canonicalized to X + X. -    if (auto *C = isConstOrConstSplatFP(Op.getOperand(1))) -      if (C->isExactlyValue(2.0) && Op.getOpcode() == ISD::FMUL) -        return 0; - -    return isNegatibleForFree(Op.getOperand(1), LegalOperations, TLI, Options, -                              ForCodeSize, Depth + 1); - -  case ISD::FMA: -  case ISD::FMAD: { -    if (!Options->NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) -      return 0; - -    // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) -    // fold (fneg (fma X, Y, Z)) -> (fma X, (fneg Y), (fneg Z)) -    char V2 = isNegatibleForFree(Op.getOperand(2), LegalOperations, TLI, -                                 Options, ForCodeSize, Depth + 1); -    if (!V2) -      return 0; - -    // One of Op0/Op1 must be cheaply negatible, then select the cheapest. -    char V0 = isNegatibleForFree(Op.getOperand(0), LegalOperations, TLI, -                                 Options, ForCodeSize, Depth + 1); -    char V1 = isNegatibleForFree(Op.getOperand(1), LegalOperations, TLI, -                                 Options, ForCodeSize, Depth + 1); -    char V01 = std::max(V0, V1); -    return V01 ? std::max(V01, V2) : 0; -  } - -  case ISD::FP_EXTEND: -  case ISD::FP_ROUND: -  case ISD::FSIN: -    return isNegatibleForFree(Op.getOperand(0), LegalOperations, TLI, Options, -                              ForCodeSize, Depth + 1); -  } -} - -/// If isNegatibleForFree returns true, return the newly negated expression. -static SDValue GetNegatedExpression(SDValue Op, SelectionDAG &DAG, -                                    bool LegalOperations, bool ForCodeSize, -                                    unsigned Depth = 0) { -  // fneg is removable even if it has multiple uses. -  if (Op.getOpcode() == ISD::FNEG) -    return Op.getOperand(0); - -  assert(Depth <= SelectionDAG::MaxRecursionDepth && -         "GetNegatedExpression doesn't match isNegatibleForFree"); -  const TargetOptions &Options = DAG.getTarget().Options; -  const SDNodeFlags Flags = Op->getFlags(); - -  switch (Op.getOpcode()) { -  default: llvm_unreachable("Unknown code"); -  case ISD::ConstantFP: { -    APFloat V = cast<ConstantFPSDNode>(Op)->getValueAPF(); -    V.changeSign(); -    return DAG.getConstantFP(V, SDLoc(Op), Op.getValueType()); -  } -  case ISD::BUILD_VECTOR: { -    SmallVector<SDValue, 4> Ops; -    for (SDValue C : Op->op_values()) { -      if (C.isUndef()) { -        Ops.push_back(C); -        continue; -      } -      APFloat V = cast<ConstantFPSDNode>(C)->getValueAPF(); -      V.changeSign(); -      Ops.push_back(DAG.getConstantFP(V, SDLoc(Op), C.getValueType())); -    } -    return DAG.getBuildVector(Op.getValueType(), SDLoc(Op), Ops); -  } -  case ISD::FADD: -    assert((Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros()) && -           "Expected NSZ fp-flag"); - -    // fold (fneg (fadd A, B)) -> (fsub (fneg A), B) -    if (isNegatibleForFree(Op.getOperand(0), LegalOperations, -                           DAG.getTargetLoweringInfo(), &Options, ForCodeSize, -                           Depth + 1)) -      return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), -                         GetNegatedExpression(Op.getOperand(0), DAG, -                                              LegalOperations, ForCodeSize, -                                              Depth + 1), -                         Op.getOperand(1), Flags); -    // fold (fneg (fadd A, B)) -> (fsub (fneg B), A) -    return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), -                       GetNegatedExpression(Op.getOperand(1), DAG, -                                            LegalOperations, ForCodeSize, -                                            Depth + 1), -                       Op.getOperand(0), Flags); -  case ISD::FSUB: -    // fold (fneg (fsub 0, B)) -> B -    if (ConstantFPSDNode *N0CFP = -            isConstOrConstSplatFP(Op.getOperand(0), /*AllowUndefs*/ true)) -      if (N0CFP->isZero()) -        return Op.getOperand(1); - -    // fold (fneg (fsub A, B)) -> (fsub B, A) -    return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), -                       Op.getOperand(1), Op.getOperand(0), Flags); - -  case ISD::FMUL: -  case ISD::FDIV: -    // fold (fneg (fmul X, Y)) -> (fmul (fneg X), Y) -    if (isNegatibleForFree(Op.getOperand(0), LegalOperations, -                           DAG.getTargetLoweringInfo(), &Options, ForCodeSize, -                           Depth + 1)) -      return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), -                         GetNegatedExpression(Op.getOperand(0), DAG, -                                              LegalOperations, ForCodeSize, -                                              Depth + 1), -                         Op.getOperand(1), Flags); - -    // fold (fneg (fmul X, Y)) -> (fmul X, (fneg Y)) -    return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), -                       Op.getOperand(0), -                       GetNegatedExpression(Op.getOperand(1), DAG, -                                            LegalOperations, ForCodeSize, -                                            Depth + 1), Flags); - -  case ISD::FMA: -  case ISD::FMAD: { -    assert((Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros()) && -           "Expected NSZ fp-flag"); - -    SDValue Neg2 = GetNegatedExpression(Op.getOperand(2), DAG, LegalOperations, -                                        ForCodeSize, Depth + 1); - -    char V0 = isNegatibleForFree(Op.getOperand(0), LegalOperations, -                                 DAG.getTargetLoweringInfo(), &Options, -                                 ForCodeSize, Depth + 1); -    char V1 = isNegatibleForFree(Op.getOperand(1), LegalOperations, -                                 DAG.getTargetLoweringInfo(), &Options, -                                 ForCodeSize, Depth + 1); -    if (V0 >= V1) { -      // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) -      SDValue Neg0 = GetNegatedExpression( -          Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); -      return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Neg0, -                         Op.getOperand(1), Neg2, Flags); -    } - -    // fold (fneg (fma X, Y, Z)) -> (fma X, (fneg Y), (fneg Z)) -    SDValue Neg1 = GetNegatedExpression(Op.getOperand(1), DAG, LegalOperations, -                                        ForCodeSize, Depth + 1); -    return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), -                       Op.getOperand(0), Neg1, Neg2, Flags); -  } - -  case ISD::FP_EXTEND: -  case ISD::FSIN: -    return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), -                       GetNegatedExpression(Op.getOperand(0), DAG, -                                            LegalOperations, ForCodeSize, -                                            Depth + 1)); -  case ISD::FP_ROUND: -    return DAG.getNode(ISD::FP_ROUND, SDLoc(Op), Op.getValueType(), -                       GetNegatedExpression(Op.getOperand(0), DAG, -                                            LegalOperations, ForCodeSize, -                                            Depth + 1), -                       Op.getOperand(1)); -  } -} -  // APInts must be the same size for most operations, this helper  // function zero extends the shorter of the pair so that they match.  // We provide an Offset so that we can create bitwidths that won't overflow. @@ -12052,17 +11806,17 @@ SDValue DAGCombiner::visitFADD(SDNode *N) {    // fold (fadd A, (fneg B)) -> (fsub A, B)    if ((!LegalOperations || TLI.isOperationLegalOrCustom(ISD::FSUB, VT)) && -      isNegatibleForFree(N1, LegalOperations, TLI, &Options, ForCodeSize) == 2) -    return DAG.getNode(ISD::FSUB, DL, VT, N0, -                       GetNegatedExpression(N1, DAG, LegalOperations, -                                            ForCodeSize), Flags); +      TLI.isNegatibleForFree(N1, DAG, LegalOperations, ForCodeSize) == 2) +    return DAG.getNode( +        ISD::FSUB, DL, VT, N0, +        TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize), Flags);    // fold (fadd (fneg A), B) -> (fsub B, A)    if ((!LegalOperations || TLI.isOperationLegalOrCustom(ISD::FSUB, VT)) && -      isNegatibleForFree(N0, LegalOperations, TLI, &Options, ForCodeSize) == 2) -    return DAG.getNode(ISD::FSUB, DL, VT, N1, -                       GetNegatedExpression(N0, DAG, LegalOperations, -                                            ForCodeSize), Flags); +      TLI.isNegatibleForFree(N0, DAG, LegalOperations, ForCodeSize) == 2) +    return DAG.getNode( +        ISD::FSUB, DL, VT, N1, +        TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize), Flags);    auto isFMulNegTwo = [](SDValue FMul) {      if (!FMul.hasOneUse() || FMul.getOpcode() != ISD::FMUL) @@ -12241,16 +11995,16 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) {    if (N0CFP && N0CFP->isZero()) {      if (N0CFP->isNegative() ||          (Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros())) { -      if (isNegatibleForFree(N1, LegalOperations, TLI, &Options, ForCodeSize)) -        return GetNegatedExpression(N1, DAG, LegalOperations, ForCodeSize); +      if (TLI.isNegatibleForFree(N1, DAG, LegalOperations, ForCodeSize)) +        return TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize);        if (!LegalOperations || TLI.isOperationLegal(ISD::FNEG, VT))          return DAG.getNode(ISD::FNEG, DL, VT, N1, Flags);      }    }    if (((Options.UnsafeFPMath && Options.NoSignedZerosFPMath) || -      (Flags.hasAllowReassociation() && Flags.hasNoSignedZeros())) -      && N1.getOpcode() == ISD::FADD) { +       (Flags.hasAllowReassociation() && Flags.hasNoSignedZeros())) && +      N1.getOpcode() == ISD::FADD) {      // X - (X + Y) -> -Y      if (N0 == N1->getOperand(0))        return DAG.getNode(ISD::FNEG, DL, VT, N1->getOperand(1), Flags); @@ -12260,10 +12014,10 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) {    }    // fold (fsub A, (fneg B)) -> (fadd A, B) -  if (isNegatibleForFree(N1, LegalOperations, TLI, &Options, ForCodeSize)) -    return DAG.getNode(ISD::FADD, DL, VT, N0, -                       GetNegatedExpression(N1, DAG, LegalOperations, -                                            ForCodeSize), Flags); +  if (TLI.isNegatibleForFree(N1, DAG, LegalOperations, ForCodeSize)) +    return DAG.getNode( +        ISD::FADD, DL, VT, N0, +        TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize), Flags);    // FSUB -> FMA combines:    if (SDValue Fused = visitFSUBForFMACombine(N)) { @@ -12277,11 +12031,10 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) {  /// Return true if both inputs are at least as cheap in negated form and at  /// least one input is strictly cheaper in negated form.  bool DAGCombiner::isCheaperToUseNegatedFPOps(SDValue X, SDValue Y) { -  const TargetOptions &Options = DAG.getTarget().Options; -  if (char LHSNeg = isNegatibleForFree(X, LegalOperations, TLI, &Options, -                                   ForCodeSize)) -    if (char RHSNeg = isNegatibleForFree(Y, LegalOperations, TLI, &Options, -                                         ForCodeSize)) +  if (char LHSNeg = +          TLI.isNegatibleForFree(X, DAG, LegalOperations, ForCodeSize)) +    if (char RHSNeg = +            TLI.isNegatibleForFree(Y, DAG, LegalOperations, ForCodeSize))        // Both negated operands are at least as cheap as their counterparts.        // Check to see if at least one is cheaper negated.        if (LHSNeg == 2 || RHSNeg == 2) @@ -12362,8 +12115,10 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) {    // -N0 * -N1 --> N0 * N1    if (isCheaperToUseNegatedFPOps(N0, N1)) { -    SDValue NegN0 = GetNegatedExpression(N0, DAG, LegalOperations, ForCodeSize); -    SDValue NegN1 = GetNegatedExpression(N1, DAG, LegalOperations, ForCodeSize); +    SDValue NegN0 = +        TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize); +    SDValue NegN1 = +        TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize);      return DAG.getNode(ISD::FMUL, DL, VT, NegN0, NegN1, Flags);    } @@ -12445,8 +12200,10 @@ SDValue DAGCombiner::visitFMA(SDNode *N) {    // (-N0 * -N1) + N2 --> (N0 * N1) + N2    if (isCheaperToUseNegatedFPOps(N0, N1)) { -    SDValue NegN0 = GetNegatedExpression(N0, DAG, LegalOperations, ForCodeSize); -    SDValue NegN1 = GetNegatedExpression(N1, DAG, LegalOperations, ForCodeSize); +    SDValue NegN0 = +        TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize); +    SDValue NegN1 = +        TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize);      return DAG.getNode(ISD::FMA, DL, VT, NegN0, NegN1, N2, Flags);    } @@ -12707,8 +12464,8 @@ SDValue DAGCombiner::visitFDIV(SDNode *N) {    if (isCheaperToUseNegatedFPOps(N0, N1))      return DAG.getNode(          ISD::FDIV, SDLoc(N), VT, -        GetNegatedExpression(N0, DAG, LegalOperations, ForCodeSize), -        GetNegatedExpression(N1, DAG, LegalOperations, ForCodeSize), Flags); +        TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize), +        TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize), Flags);    return SDValue();  } @@ -13262,9 +13019,8 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) {    if (isConstantFPBuildVectorOrConstantFP(N0))      return DAG.getNode(ISD::FNEG, SDLoc(N), VT, N0); -  if (isNegatibleForFree(N0, LegalOperations, DAG.getTargetLoweringInfo(), -                         &DAG.getTarget().Options, ForCodeSize)) -    return GetNegatedExpression(N0, DAG, LegalOperations, ForCodeSize); +  if (TLI.isNegatibleForFree(N0, DAG, LegalOperations, ForCodeSize)) +    return TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize);    // Transform fneg(bitconvert(x)) -> bitconvert(x ^ sign) to avoid loading    // constant pool values. diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index fbe4e8cca8e..0b6f8ba4257 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5331,6 +5331,246 @@ verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const {    return false;  } +char TargetLowering::isNegatibleForFree(SDValue Op, SelectionDAG &DAG, +                                        bool LegalOperations, bool ForCodeSize, +                                        unsigned Depth) const { +  // fneg is removable even if it has multiple uses. +  if (Op.getOpcode() == ISD::FNEG) +    return 2; + +  // Don't allow anything with multiple uses unless we know it is free. +  EVT VT = Op.getValueType(); +  const SDNodeFlags Flags = Op->getFlags(); +  const TargetOptions &Options = DAG.getTarget().Options; +  if (!Op.hasOneUse() && !(Op.getOpcode() == ISD::FP_EXTEND && +                           isFPExtFree(VT, Op.getOperand(0).getValueType()))) +    return 0; + +  // Don't recurse exponentially. +  if (Depth > SelectionDAG::MaxRecursionDepth) +    return 0; + +  switch (Op.getOpcode()) { +  case ISD::ConstantFP: { +    if (!LegalOperations) +      return 1; + +    // Don't invert constant FP values after legalization unless the target says +    // the negated constant is legal. +    return isOperationLegal(ISD::ConstantFP, VT) || +           isFPImmLegal(neg(cast<ConstantFPSDNode>(Op)->getValueAPF()), VT, +                        ForCodeSize); +  } +  case ISD::BUILD_VECTOR: { +    // Only permit BUILD_VECTOR of constants. +    if (llvm::any_of(Op->op_values(), [&](SDValue N) { +          return !N.isUndef() && !isa<ConstantFPSDNode>(N); +        })) +      return 0; +    if (!LegalOperations) +      return 1; +    if (isOperationLegal(ISD::ConstantFP, VT) && +        isOperationLegal(ISD::BUILD_VECTOR, VT)) +      return 1; +    return llvm::all_of(Op->op_values(), [&](SDValue N) { +      return N.isUndef() || +             isFPImmLegal(neg(cast<ConstantFPSDNode>(N)->getValueAPF()), VT, +                          ForCodeSize); +    }); +  } +  case ISD::FADD: +    if (!Options.NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) +      return 0; + +    // After operation legalization, it might not be legal to create new FSUBs. +    if (LegalOperations && !isOperationLegalOrCustom(ISD::FSUB, VT)) +      return 0; + +    // fold (fneg (fadd A, B)) -> (fsub (fneg A), B) +    if (char V = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, +                                    ForCodeSize, Depth + 1)) +      return V; +    // fold (fneg (fadd A, B)) -> (fsub (fneg B), A) +    return isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, +                              ForCodeSize, Depth + 1); +  case ISD::FSUB: +    // We can't turn -(A-B) into B-A when we honor signed zeros. +    if (!Options.NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) +      return 0; + +    // fold (fneg (fsub A, B)) -> (fsub B, A) +    return 1; + +  case ISD::FMUL: +  case ISD::FDIV: +    // fold (fneg (fmul X, Y)) -> (fmul (fneg X), Y) or (fmul X, (fneg Y)) +    if (char V = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, +                                    ForCodeSize, Depth + 1)) +      return V; + +    // Ignore X * 2.0 because that is expected to be canonicalized to X + X. +    if (auto *C = isConstOrConstSplatFP(Op.getOperand(1))) +      if (C->isExactlyValue(2.0) && Op.getOpcode() == ISD::FMUL) +        return 0; + +    return isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, +                              ForCodeSize, Depth + 1); + +  case ISD::FMA: +  case ISD::FMAD: { +    if (!Options.NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) +      return 0; + +    // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) +    // fold (fneg (fma X, Y, Z)) -> (fma X, (fneg Y), (fneg Z)) +    char V2 = isNegatibleForFree(Op.getOperand(2), DAG, LegalOperations, +                                 ForCodeSize, Depth + 1); +    if (!V2) +      return 0; + +    // One of Op0/Op1 must be cheaply negatible, then select the cheapest. +    char V0 = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, +                                 ForCodeSize, Depth + 1); +    char V1 = isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, +                                 ForCodeSize, Depth + 1); +    char V01 = std::max(V0, V1); +    return V01 ? std::max(V01, V2) : 0; +  } + +  case ISD::FP_EXTEND: +  case ISD::FP_ROUND: +  case ISD::FSIN: +    return isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, +                              ForCodeSize, Depth + 1); +  } + +  return 0; +} + +SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG, +                                             bool LegalOperations, +                                             bool ForCodeSize, +                                             unsigned Depth) const { +  // fneg is removable even if it has multiple uses. +  if (Op.getOpcode() == ISD::FNEG) +    return Op.getOperand(0); + +  assert(Depth <= SelectionDAG::MaxRecursionDepth && +         "getNegatedExpression doesn't match isNegatibleForFree"); +  const SDNodeFlags Flags = Op->getFlags(); + +  switch (Op.getOpcode()) { +  case ISD::ConstantFP: { +    APFloat V = cast<ConstantFPSDNode>(Op)->getValueAPF(); +    V.changeSign(); +    return DAG.getConstantFP(V, SDLoc(Op), Op.getValueType()); +  } +  case ISD::BUILD_VECTOR: { +    SmallVector<SDValue, 4> Ops; +    for (SDValue C : Op->op_values()) { +      if (C.isUndef()) { +        Ops.push_back(C); +        continue; +      } +      APFloat V = cast<ConstantFPSDNode>(C)->getValueAPF(); +      V.changeSign(); +      Ops.push_back(DAG.getConstantFP(V, SDLoc(Op), C.getValueType())); +    } +    return DAG.getBuildVector(Op.getValueType(), SDLoc(Op), Ops); +  } +  case ISD::FADD: +    assert((DAG.getTarget().Options.NoSignedZerosFPMath || +            Flags.hasNoSignedZeros()) && +           "Expected NSZ fp-flag"); + +    // fold (fneg (fadd A, B)) -> (fsub (fneg A), B) +    if (isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, +                           Depth + 1)) +      return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), +                         getNegatedExpression(Op.getOperand(0), DAG, +                                              LegalOperations, ForCodeSize, +                                              Depth + 1), +                         Op.getOperand(1), Flags); +    // fold (fneg (fadd A, B)) -> (fsub (fneg B), A) +    return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), +                       getNegatedExpression(Op.getOperand(1), DAG, +                                            LegalOperations, ForCodeSize, +                                            Depth + 1), +                       Op.getOperand(0), Flags); +  case ISD::FSUB: +    // fold (fneg (fsub 0, B)) -> B +    if (ConstantFPSDNode *N0CFP = +            isConstOrConstSplatFP(Op.getOperand(0), /*AllowUndefs*/ true)) +      if (N0CFP->isZero()) +        return Op.getOperand(1); + +    // fold (fneg (fsub A, B)) -> (fsub B, A) +    return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), +                       Op.getOperand(1), Op.getOperand(0), Flags); + +  case ISD::FMUL: +  case ISD::FDIV: +    // fold (fneg (fmul X, Y)) -> (fmul (fneg X), Y) +    if (isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, +                           Depth + 1)) +      return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), +                         getNegatedExpression(Op.getOperand(0), DAG, +                                              LegalOperations, ForCodeSize, +                                              Depth + 1), +                         Op.getOperand(1), Flags); + +    // fold (fneg (fmul X, Y)) -> (fmul X, (fneg Y)) +    return DAG.getNode( +        Op.getOpcode(), SDLoc(Op), Op.getValueType(), Op.getOperand(0), +        getNegatedExpression(Op.getOperand(1), DAG, LegalOperations, +                             ForCodeSize, Depth + 1), +        Flags); + +  case ISD::FMA: +  case ISD::FMAD: { +    assert((DAG.getTarget().Options.NoSignedZerosFPMath || +            Flags.hasNoSignedZeros()) && +           "Expected NSZ fp-flag"); + +    SDValue Neg2 = getNegatedExpression(Op.getOperand(2), DAG, LegalOperations, +                                        ForCodeSize, Depth + 1); + +    char V0 = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, +                                 ForCodeSize, Depth + 1); +    char V1 = isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, +                                 ForCodeSize, Depth + 1); +    if (V0 >= V1) { +      // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) +      SDValue Neg0 = getNegatedExpression( +          Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); +      return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Neg0, +                         Op.getOperand(1), Neg2, Flags); +    } + +    // fold (fneg (fma X, Y, Z)) -> (fma X, (fneg Y), (fneg Z)) +    SDValue Neg1 = getNegatedExpression(Op.getOperand(1), DAG, LegalOperations, +                                        ForCodeSize, Depth + 1); +    return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), +                       Op.getOperand(0), Neg1, Neg2, Flags); +  } + +  case ISD::FP_EXTEND: +  case ISD::FSIN: +    return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), +                       getNegatedExpression(Op.getOperand(0), DAG, +                                            LegalOperations, ForCodeSize, +                                            Depth + 1)); +  case ISD::FP_ROUND: +    return DAG.getNode(ISD::FP_ROUND, SDLoc(Op), Op.getValueType(), +                       getNegatedExpression(Op.getOperand(0), DAG, +                                            LegalOperations, ForCodeSize, +                                            Depth + 1), +                       Op.getOperand(1)); +  } + +  llvm_unreachable("Unknown code"); +} +  //===----------------------------------------------------------------------===//  // Legalization Utilities  //===----------------------------------------------------------------------===// | 

