Index: lib/Analysis/ScalarEvolution.cpp =================================================================== --- lib/Analysis/ScalarEvolution.cpp +++ lib/Analysis/ScalarEvolution.cpp @@ -5952,6 +5952,24 @@ return getZeroExtendExpr(getSCEV(U->getOperand(0)), U->getType()); case Instruction::SExt: + if (auto BO = MatchBinaryOp(U->getOperand(0), DT)) { + // The NSW flag of a subtract does not always survive the conversion to + // A + (-1)*B. By pushing sign extension onto its operands we are much + // more likely to preserve NSW and allow later AddRec optimisations. + // + // NOTE: This is effectively duplicating this logic from getSignExtend: + // sext((A + B + ...)) --> (sext(A) + sext(B) + ...) + // but by that point the NSW information has potentially been lost. + if (BO->Opcode == Instruction::Sub && BO->Op) { + SCEV::NoWrapFlags Flags = getNoWrapFlagsFromUB(BO->Op); + if (maskFlags(Flags, SCEV::FlagNSW) == SCEV::FlagNSW) { + Type *Ty = U->getType(); + auto *V1 = getSignExtendExpr(getSCEV(BO->LHS), Ty); + auto *V2 = getSignExtendExpr(getSCEV(BO->RHS), Ty); + return getMinusSCEV(V1, V2, SCEV::FlagNSW); + } + } + } return getSignExtendExpr(getSCEV(U->getOperand(0)), U->getType()); case Instruction::BitCast: Index: test/Analysis/ScalarEvolution/flags-from-poison.ll =================================================================== --- test/Analysis/ScalarEvolution/flags-from-poison.ll +++ test/Analysis/ScalarEvolution/flags-from-poison.ll @@ -609,7 +609,7 @@ %index32 = sub nsw i32 %i, %sub ; CHECK: %index64 = -; CHECK: --> {(sext i32 (-1 * %sub) to i64),+,1} +; CHECK: --> {(-1 * (sext i32 %sub to i64)),+,1}