Index: llvm/include/llvm/CodeGen/SelectionDAG.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAG.h +++ llvm/include/llvm/CodeGen/SelectionDAG.h @@ -2029,6 +2029,24 @@ OFK_Always, }; + /// Determine if the result of the signed mul of 2 nodes can overflow. + OverflowKind computeOverflowForSignedMul(SDValue N0, SDValue N1) const; + + /// Determine if the result of the unsigned mul of 2 nodes can overflow. + OverflowKind computeOverflowForUnsignedMul(SDValue N0, SDValue N1) const; + + /// Determine if the result of the mul of 2 nodes can overflow. + OverflowKind computeOverflowForMul(bool IsSigned, SDValue N0, + SDValue N1) const { + return IsSigned ? computeOverflowForSignedMul(N0, N1) + : computeOverflowForUnsignedMul(N0, N1); + } + + /// Determine if the result of the mul of 2 nodes can never overflow. + bool willNotOverflowMul(bool IsSigned, SDValue N0, SDValue N1) const { + return computeOverflowForMul(IsSigned, N0, N1) == OFK_Never; + } + /// Determine if the result of the signed addition of 2 nodes can overflow. OverflowKind computeOverflowForSignedAdd(SDValue N0, SDValue N1) const; Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -5441,34 +5441,10 @@ return DAG.getNode(IsSigned ? ISD::SADDO : ISD::UADDO, DL, N->getVTList(), N0, N0); - if (IsSigned) { - // A 1 bit SMULO overflows if both inputs are 1. - if (VT.getScalarSizeInBits() == 1) { - SDValue And = DAG.getNode(ISD::AND, DL, VT, N0, N1); - return CombineTo(N, And, - DAG.getSetCC(DL, CarryVT, And, - DAG.getConstant(0, DL, VT), ISD::SETNE)); - } - - // Multiplying n * m significant bits yields a result of n + m significant - // bits. If the total number of significant bits does not exceed the - // result bit width (minus 1), there is no overflow. - unsigned SignBits = DAG.ComputeNumSignBits(N0); - if (SignBits > 1) - SignBits += DAG.ComputeNumSignBits(N1); - if (SignBits > VT.getScalarSizeInBits() + 1) - return CombineTo(N, DAG.getNode(ISD::MUL, DL, VT, N0, N1), - DAG.getConstant(0, DL, CarryVT)); - } else { - KnownBits N1Known = DAG.computeKnownBits(N1); - KnownBits N0Known = DAG.computeKnownBits(N0); - bool Overflow; - (void)N0Known.getMaxValue().umul_ov(N1Known.getMaxValue(), Overflow); - if (!Overflow) - return CombineTo(N, DAG.getNode(ISD::MUL, DL, VT, N0, N1), - DAG.getConstant(0, DL, CarryVT)); - } - + // If it cannot overflow, transform into a mul. + if (DAG.willNotOverflowMul(IsSigned, N0, N1)) + return CombineTo(N, DAG.getNode(ISD::MUL, DL, VT, N0, N1), + DAG.getConstant(0, DL, CarryVT)); return SDValue(); } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -4036,6 +4036,43 @@ llvm_unreachable("Unknown OverflowResult"); } +SelectionDAG::OverflowKind +SelectionDAG::computeOverflowForUnsignedMul(SDValue N0, SDValue N1) const { + // X * 0 and X * 1 never overflow. + if (isNullConstant(N1) || isOneConstant(N1)) + return OFK_Never; + KnownBits N0Known = computeKnownBits(N0); + KnownBits N1Known = computeKnownBits(N1); + ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); + ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); + return mapOverflowResult(N0Range.unsignedMulMayOverflow(N1Range)); +} + +SelectionDAG::OverflowKind +SelectionDAG::computeOverflowForSignedMul(SDValue N0, SDValue N1) const { + // X * 0 and X * 1 never overflow. + if (isNullConstant(N1) || isOneConstant(N1)) + return OFK_Never; + // Get the size of the result. + unsigned BitWidth = N0.getScalarValueSizeInBits(); + // Sum of the leading zeros. + unsigned SignBits = ComputeNumSignBits(N0) + ComputeNumSignBits(N1); + // If we have enough leading zeros, then there's no overflow. + if (SignBits > BitWidth + 1) + return OFK_Never; + if (SignBits == BitWidth + 1) { + // The overflow occurs when the true multiplication of the + // the operands is the minimum negative number. + KnownBits N0Known = computeKnownBits(N0); + KnownBits N1Known = computeKnownBits(N1); + // If one of the operands is non-negative, then there's no + // overflow. + if (N0Known.isNonNegative() || N1Known.isNonNegative()) + return OFK_Never; + } + return OFK_Sometime; +} + SelectionDAG::OverflowKind SelectionDAG::computeOverflowForSignedAdd(SDValue N0, SDValue N1) const { // X + 0 never overflow @@ -4047,8 +4084,11 @@ if (ComputeNumSignBits(N0) > 1 && ComputeNumSignBits(N1) > 1) return OFK_Never; - // TODO: Add ConstantRange::signedAddMayOverflow handling. - return OFK_Sometime; + KnownBits N0Known = computeKnownBits(N0); + KnownBits N1Known = computeKnownBits(N1); + ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); + ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); + return mapOverflowResult(N0Range.signedAddMayOverflow(N1Range)); } SelectionDAG::OverflowKind @@ -4085,8 +4125,11 @@ if (ComputeNumSignBits(N0) > 1 && ComputeNumSignBits(N1) > 1) return OFK_Never; - // TODO: Add ConstantRange::signedSubMayOverflow handling. - return OFK_Sometime; + KnownBits N0Known = computeKnownBits(N0); + KnownBits N1Known = computeKnownBits(N1); + ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); + ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); + return mapOverflowResult(N0Range.signedSubMayOverflow(N1Range)); } SelectionDAG::OverflowKind @@ -4095,8 +4138,11 @@ if (isNullConstant(N1)) return OFK_Never; - // TODO: Add ConstantRange::unsignedSubMayOverflow handling. - return OFK_Sometime; + KnownBits N0Known = computeKnownBits(N0); + KnownBits N1Known = computeKnownBits(N1); + ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); + ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); + return mapOverflowResult(N0Range.unsignedSubMayOverflow(N1Range)); } bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val, unsigned Depth) const {