[SCEV] Why is backedge-taken count <nsw> instead of <nuw>?

Hello,

If I run clang on the following code:

void func(unsigned n) {
for (unsigned long x = 1; x < n; ++x)
dummy(x);
}

I get the following llvm ir:

define void @func(i32 %n) {
entry:
%conv = zext i32 %n to i64
%cmp5 = icmp ugt i32 %n, 1
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret void
for.body: ; preds = %entry, %for.body
%x.06 = phi i64 [ %inc, %for.body ], [ 1, %entry ]
tail call void @dummy(i64 %x.06) #2
%inc = add nuw nsw i64 %x.06, 1
%exitcond = icmp eq i64 %inc, %conv
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}

Over which, SCEV will provide the following analysis:

Printing analysis ‘Scalar Evolution Analysis’ for function ‘func’:
Classifying expressions for: @func
%conv = zext i32 %n to i64
→ (zext i32 %n to i64) U: [0,4294967296) S: [0,4294967296)
%x.06 = phi i64 [ %inc, %for.body ], [ 1, %entry ]
→ {1,+,1}<%for.body> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: (-1 + (zext i32 %n to i64)) LoopDispositions: { %for.body: Computable }
%inc = add nuw nsw i64 %x.06, 1
→ {2,+,1}<%for.body> U: [2,0) S: [2,0) Exits: (zext i32 %n to i64) LoopDispositions: { %for.body: Computable }
Determining loop execution counts for: @func
Loop %for.body: backedge-taken count is (-2 + (zext i32 %n to i64))
Loop %for.body: max backedge-taken count is -2
Loop %for.body: Predicated backedge-taken count is (-2 + (zext i32 %n to i64))
Predicates:
Loop %for.body: Trip multiple is 1

Now, I was surprised by the max backedge-taken count being -2, and I suspect it is due to the backedge-taken count being marked as instead of .

Is that on purpose, is that a bug, or is my analysis incorrect? I am not sure where to fix that issue.

The backedge-taken count isn’t nuw because nsw/nuw markings aren’t flow-sensitive: there isn’t any way to mark the trip count as nuw without marking every computation of (long)n-2 as nuw. There’s some code in ScalarEvolution::howFarToZero to try to refine the max backedge-taken count in some cases, but it isn’t very general. See . -Eli

Is that why we do not deduce + from “add nsw” either?

Is that an intrinsic limitation of creating a context-invariant expressions from a Value* or is that a limitation of our implementation (our unification not considering the nsw flags)?

Essentially, yes. It’s a consequence of unification not considering nsw. (nsw on an instruction is naturally invariant because violating nsw produces poison, not UB.) -Eli

I’m not sure I understand the poison/undef/UB distinctions.

But on this example:

define i32 @func(i1 zeroext %b, i32 %x, i32 %y) {
entry:
%adds = add nsw i32 %x, %y
%addu = add nuw i32 %x, %y
%cond = select i1 %b, i32 %adds, i32 %addu
ret i32 %cond
}

It is important to not propagate the nsw/nuw between the two SCEV expressions (which unification would do today, can I consider that a bug or is it a feature?).
So we work-around it by not informing SCEV of the flags:

Printing analysis ‘Scalar Evolution Analysis’ for function ‘func’:
Classifying expressions for: @func
%adds = add nsw i32 %x, %y
→ (%x + %y) U: full-set S: full-set
%addu = add nuw i32 %x, %y
→ (%x + %y) U: full-set S: full-set
%cond = select i1 %b, i32 %adds, i32 %addu
→ %cond U: full-set S: full-set
Determining loop execution counts for: @func

Would there be problems if we properly considered nuw/nsw flags when unifying SCEVs?

It’s an intentional design choice. There would be other consequences. For example, (%x + %y)<nsw> and (%x + %y)<nuw> wouldn’t compare equal for other simplifications, and all the places that call setNoWrapFlags would have to be rewritten. It’s probably possible to come up with some workable design, but nobody has actually tried it, so it’s not clear how much work it would be to implement, or whether it would improve the generated code overall. -Eli

Ok.

To go back to the original issue, would it be meaningful to add a SCEVUMax(0, BTC) on the final BTC computed by SCEV?

So that it does not use “negative values”?

Hum, actually that gets eliminated to nothing of course. What we need is really the NUW flag…

In general, the backedge-taken count is an unsigned value; it's possible to write a loop with a trip count of 2^64 using a 64-bit induction variable. To prove your loop has a "small" trip count, you have to use either the guard or the nsw/nuw markings on the induction variable.

-Eli

The loop exits iff {2,+,1}<%for.body> == (zext i32 %n to i64)

The nuw marking on the “induction variable” should be sufficient to deduce a max loop trip count of 2^32.
But I do not know how we compute it (we build a database and it is contrived to follow, at least to me).

I saw that we annotate it with (which is correct and can be (and probably has been) deduced from the ranges) and following our discussion, we can’t annotate it with as per limitation of our unification.

So, I am kind of in a bind here…

Is the issue that nothing knows that n isn’t 0? In which case the loop would run close to 2^64-1 iterations. Is the -2 just a failure to print 2^64 - 2 as a positive number?

Well, like I said earlier, it's usually viable to check for a guard, along the lines of https://reviews.llvm.org/D28536 (or maybe implement some context-sensitive range analysis algorithm to use everywhere).

The alternative is to try to do something to preserve the nowrap flags we have on the input to the icmp, in ScalarEvolution::computeExitLimitFromICmp.

-Eli