diff options
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 240 | 
1 files changed, 240 insertions, 0 deletions
| 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  //===----------------------------------------------------------------------===// | 

