Index: lib/Analysis/ScalarEvolution.cpp =================================================================== --- lib/Analysis/ScalarEvolution.cpp +++ lib/Analysis/ScalarEvolution.cpp @@ -1737,6 +1737,38 @@ }; } + +// We're trying to construct a SCEV of type `Type' with `Ops' as operands and +// `OldFlags' as can't-wrap behavior. Infer a more aggressive set of +// can't-overflow flags for the operation if possible. +static SCEV::NoWrapFlags +StrengthenNoWrapFlags(ScalarEvolution &SE, SCEVTypes Type, + const SmallVectorImpl &Ops, + SCEV::NoWrapFlags OldFlags) { + bool CanAnalyze = (Type == scAddExpr) || (Type == scAddRecExpr) || + (Type == scMulExpr); + (void) CanAnalyze; + assert(CanAnalyze && "don't call from other places!"); + + // If FlagNSW is true and all the operands are non-negative, infer FlagNUW. + int SignOrUnsignMask = SCEV::FlagNUW | SCEV::FlagNSW; + SCEV::NoWrapFlags SignOrUnsignWrap = + ScalarEvolution::maskFlags(OldFlags, SignOrUnsignMask); + if ((SignOrUnsignWrap == SCEV::FlagNSW) && + (SignOrUnsignWrap != SignOrUnsignMask)) { + + if (std::all_of(Ops.begin(), Ops.end(), [&SE](const SCEV *S) { + return SE.isKnownNonNegative(S); + })) { + return ScalarEvolution::setFlags( + OldFlags, (SCEV::NoWrapFlags)SignOrUnsignMask); + } + } + + return OldFlags; +} + + /// getAddExpr - Get a canonical add expression, or something simpler if /// possible. const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, @@ -1752,20 +1784,7 @@ "SCEVAddExpr operand types don't match!"); #endif - // If FlagNSW is true and all the operands are non-negative, infer FlagNUW. - // And vice-versa. - int SignOrUnsignMask = SCEV::FlagNUW | SCEV::FlagNSW; - SCEV::NoWrapFlags SignOrUnsignWrap = maskFlags(Flags, SignOrUnsignMask); - if (SignOrUnsignWrap && (SignOrUnsignWrap != SignOrUnsignMask)) { - bool All = true; - for (SmallVectorImpl::const_iterator I = Ops.begin(), - E = Ops.end(); I != E; ++I) - if (!isKnownNonNegative(*I)) { - All = false; - break; - } - if (All) Flags = setFlags(Flags, (SCEV::NoWrapFlags)SignOrUnsignMask); - } + Flags = StrengthenNoWrapFlags(*this, scAddExpr, Ops, Flags); // Sort by complexity, this groups all similar expression types together. GroupByComplexity(Ops, LI); @@ -2174,20 +2193,7 @@ "SCEVMulExpr operand types don't match!"); #endif - // If FlagNSW is true and all the operands are non-negative, infer FlagNUW. - // And vice-versa. - int SignOrUnsignMask = SCEV::FlagNUW | SCEV::FlagNSW; - SCEV::NoWrapFlags SignOrUnsignWrap = maskFlags(Flags, SignOrUnsignMask); - if (SignOrUnsignWrap && (SignOrUnsignWrap != SignOrUnsignMask)) { - bool All = true; - for (SmallVectorImpl::const_iterator I = Ops.begin(), - E = Ops.end(); I != E; ++I) - if (!isKnownNonNegative(*I)) { - All = false; - break; - } - if (All) Flags = setFlags(Flags, (SCEV::NoWrapFlags)SignOrUnsignMask); - } + Flags = StrengthenNoWrapFlags(*this, scMulExpr, Ops, Flags); // Sort by complexity, this groups all similar expression types together. GroupByComplexity(Ops, LI); @@ -2653,20 +2659,7 @@ // meaningful BE count at this point (and if we don't, we'd be stuck // with a SCEVCouldNotCompute as the cached BE count). - // If FlagNSW is true and all the operands are non-negative, infer FlagNUW. - // And vice-versa. - int SignOrUnsignMask = SCEV::FlagNUW | SCEV::FlagNSW; - SCEV::NoWrapFlags SignOrUnsignWrap = maskFlags(Flags, SignOrUnsignMask); - if (SignOrUnsignWrap && (SignOrUnsignWrap != SignOrUnsignMask)) { - bool All = true; - for (SmallVectorImpl::const_iterator I = Operands.begin(), - E = Operands.end(); I != E; ++I) - if (!isKnownNonNegative(*I)) { - All = false; - break; - } - if (All) Flags = setFlags(Flags, (SCEV::NoWrapFlags)SignOrUnsignMask); - } + Flags = StrengthenNoWrapFlags(*this, scAddRecExpr, Operands, Flags); // Canonicalize nested AddRecs in by nesting them in order of loop depth. if (const SCEVAddRecExpr *NestedAR = dyn_cast(Operands[0])) { Index: test/Analysis/ScalarEvolution/pr22179.ll =================================================================== --- /dev/null +++ test/Analysis/ScalarEvolution/pr22179.ll @@ -0,0 +1,28 @@ +; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s + +%struct.anon = type { i8 } +%struct.S = type { i32 } + +@a = common global %struct.anon zeroinitializer, align 1 +@b = common global %struct.S zeroinitializer, align 4 + +; Function Attrs: nounwind ssp uwtable +define i32 @main() { +; CHECK-LABEL: Classifying expressions for: @main + store i8 0, i8* getelementptr inbounds (%struct.anon* @a, i64 0, i32 0), align 1 + br label %loop + +loop: + %storemerge1 = phi i8 [ 0, %0 ], [ %inc, %loop ] + %m = load volatile i32* getelementptr inbounds (%struct.S* @b, i64 0, i32 0), align 4 + %inc = add nuw i8 %storemerge1, 1 +; CHECK: %inc = add nuw i8 %storemerge1, 1 +; CHECK-NEXT: --> {1,+,1}<%loop> +; CHECK-NOT: --> {1,+,1}<%loop> + %exitcond = icmp eq i8 %inc, -128 + br i1 %exitcond, label %exit, label %loop + +exit: + store i8 -128, i8* getelementptr inbounds (%struct.anon* @a, i64 0, i32 0), align 1 + ret i32 0 +} Index: test/CodeGen/X86/avoid_complex_am.ll =================================================================== --- test/CodeGen/X86/avoid_complex_am.ll +++ test/CodeGen/X86/avoid_complex_am.ll @@ -22,7 +22,7 @@ %arrayidx = getelementptr inbounds double* %b, i64 %tmp %tmp1 = load double* %arrayidx, align 8 ; The induction variable should carry the scaling factor: 1. -; CHECK: [[IVNEXT]] = add nuw nsw i64 [[IV]], 1 +; CHECK: [[IVNEXT]] = add nuw i64 [[IV]], 1 %indvars.iv.next = add i64 %indvars.iv, 1 %arrayidx2 = getelementptr inbounds double* %c, i64 %indvars.iv.next %tmp2 = load double* %arrayidx2, align 8