diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 73 | 
1 files changed, 70 insertions, 3 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 041d7e5b4a4a..ec297579090e 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -2101,10 +2101,80 @@ static bool canFoldInAddressingMode(SDNode *N, SDNode *Use, SelectionDAG &DAG,                                     VT.getTypeForEVT(*DAG.getContext()), AS);  } +/// This inverts a canonicalization in IR that replaces a variable select arm +/// with an identity constant. Codegen improves if we re-use the variable +/// operand rather than load a constant. This can also be converted into a +/// masked vector operation if the target supports it. +static SDValue foldSelectWithIdentityConstant(SDNode *N, SelectionDAG &DAG, +                                              bool ShouldCommuteOperands) { +  // Match a select as operand 1. The identity constant that we are looking for +  // is only valid as operand 1 of a non-commutative binop. +  SDValue N0 = N->getOperand(0); +  SDValue N1 = N->getOperand(1); +  if (ShouldCommuteOperands) +    std::swap(N0, N1); + +  // TODO: Should this apply to scalar select too? +  if (!N1.hasOneUse() || N1.getOpcode() != ISD::VSELECT) +    return SDValue(); + +  unsigned Opcode = N->getOpcode(); +  EVT VT = N->getValueType(0); +  SDValue Cond = N1.getOperand(0); +  SDValue TVal = N1.getOperand(1); +  SDValue FVal = N1.getOperand(2); + +  // TODO: The cases should match with IR's ConstantExpr::getBinOpIdentity(). +  // TODO: Target-specific opcodes could be added. Ex: "isCommutativeBinOp()". +  // TODO: With fast-math (NSZ), allow the opposite-sign form of zero? +  auto isIdentityConstantForOpcode = [](unsigned Opcode, SDValue V) { +    if (ConstantFPSDNode *C = isConstOrConstSplatFP(V)) { +      switch (Opcode) { +      case ISD::FADD: // X + -0.0 --> X +        return C->isZero() && C->isNegative(); +      case ISD::FSUB: // X - 0.0 --> X +        return C->isZero() && !C->isNegative(); +      case ISD::FMUL: // X * 1.0 --> X +      case ISD::FDIV: // X / 1.0 --> X +        return C->isExactlyValue(1.0); +      } +    } +    return false; +  }; + +  // This transform increases uses of N0, so freeze it to be safe. +  // binop N0, (vselect Cond, IDC, FVal) --> vselect Cond, N0, (binop N0, FVal) +  if (isIdentityConstantForOpcode(Opcode, TVal)) { +    SDValue F0 = DAG.getFreeze(N0); +    SDValue NewBO = DAG.getNode(Opcode, SDLoc(N), VT, F0, FVal, N->getFlags()); +    return DAG.getSelect(SDLoc(N), VT, Cond, F0, NewBO); +  } +  // binop N0, (vselect Cond, TVal, IDC) --> vselect Cond, (binop N0, TVal), N0 +  if (isIdentityConstantForOpcode(Opcode, FVal)) { +    SDValue F0 = DAG.getFreeze(N0); +    SDValue NewBO = DAG.getNode(Opcode, SDLoc(N), VT, F0, TVal, N->getFlags()); +    return DAG.getSelect(SDLoc(N), VT, Cond, NewBO, F0); +  } + +  return SDValue(); +} +  SDValue DAGCombiner::foldBinOpIntoSelect(SDNode *BO) {    assert(TLI.isBinOp(BO->getOpcode()) && BO->getNumValues() == 1 &&           "Unexpected binary operator"); +  const TargetLowering &TLI = DAG.getTargetLoweringInfo(); +  auto BinOpcode = BO->getOpcode(); +  EVT VT = BO->getValueType(0); +  if (TLI.shouldFoldSelectWithIdentityConstant(BinOpcode, VT)) { +    if (SDValue Sel = foldSelectWithIdentityConstant(BO, DAG, false)) +      return Sel; + +    if (TLI.isCommutativeBinOp(BO->getOpcode())) +      if (SDValue Sel = foldSelectWithIdentityConstant(BO, DAG, true)) +        return Sel; +  } +    // Don't do this unless the old select is going away. We want to eliminate the    // binary operator, not replace a binop with a select.    // TODO: Handle ISD::SELECT_CC. @@ -2133,7 +2203,6 @@ SDValue DAGCombiner::foldBinOpIntoSelect(SDNode *BO) {    // propagate non constant operands into select. I.e.:    // and (select Cond, 0, -1), X --> select Cond, 0, X    // or X, (select Cond, -1, 0) --> select Cond, -1, X -  auto BinOpcode = BO->getOpcode();    bool CanFoldNonConst =        (BinOpcode == ISD::AND || BinOpcode == ISD::OR) &&        (isNullOrNullSplat(CT) || isAllOnesOrAllOnesSplat(CT)) && @@ -2145,8 +2214,6 @@ SDValue DAGCombiner::foldBinOpIntoSelect(SDNode *BO) {        !DAG.isConstantFPBuildVectorOrConstantFP(CBO))      return SDValue(); -  EVT VT = BO->getValueType(0); -    // We have a select-of-constants followed by a binary operator with a    // constant. Eliminate the binop by pulling the constant math into the select.    // Example: add (select Cond, CT, CF), CBO --> select Cond, CT + CBO, CF + CBO  | 
