Index: llvm/trunk/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp @@ -4168,10 +4168,21 @@ } case Intrinsic::ssub_with_overflow: - case Intrinsic::usub_with_overflow: - return BinaryOp(Instruction::Sub, CI->getArgOperand(0), - CI->getArgOperand(1)); + case Intrinsic::usub_with_overflow: { + if (!isOverflowIntrinsicNoWrap(cast(CI), DT)) + return BinaryOp(Instruction::Sub, CI->getArgOperand(0), + CI->getArgOperand(1)); + // The same reasoning as sadd/uadd above. + if (F->getIntrinsicID() == Intrinsic::ssub_with_overflow) + return BinaryOp(Instruction::Sub, CI->getArgOperand(0), + CI->getArgOperand(1), /* IsNSW = */ true, + /* IsNUW = */ false); + else + return BinaryOp(Instruction::Sub, CI->getArgOperand(0), + CI->getArgOperand(1), /* IsNSW = */ false, + /* IsNUW = */ true); + } case Intrinsic::smul_with_overflow: case Intrinsic::umul_with_overflow: return BinaryOp(Instruction::Mul, CI->getArgOperand(0), @@ -5952,6 +5963,21 @@ 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->IsNSW) { + 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: llvm/trunk/test/Analysis/ScalarEvolution/flags-from-poison.ll =================================================================== --- llvm/trunk/test/Analysis/ScalarEvolution/flags-from-poison.ll +++ llvm/trunk/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} {(-1 * %sub),+,1} + %ssub = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %i, i32 %sub) + %val = extractvalue { i32, i1 } %ssub, 0 + %ovfl = extractvalue { i32, i1 } %ssub, 1 + br i1 %ovfl, label %trap, label %cont + +trap: + tail call void @llvm.trap() + unreachable + +cont: +; CHECK: %index64 = +; CHECK: --> {(-1 * (sext i32 %sub to i64)),+,1}