-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[NFC][Analysis] Add more SCEV tests for ptr inductions #108210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1595,6 +1595,145 @@ exit: | |
| ret i32 0 | ||
| } | ||
|
|
||
| define i32 @ptr_induction_eq_1(ptr %a, ptr %b) { | ||
| ; CHECK-LABEL: 'ptr_induction_eq_1' | ||
| ; CHECK-NEXT: Classifying expressions for: @ptr_induction_eq_1 | ||
| ; CHECK-NEXT: %ptr.iv = phi ptr [ %ptr.iv.next, %loop ], [ %a, %entry ] | ||
| ; CHECK-NEXT: --> {%a,+,8}<nuw><%loop> U: full-set S: full-set Exits: ((8 * ((-8 + (-1 * (ptrtoint ptr %a to i64)) + (ptrtoint ptr %b to i64)) /u 8))<nuw> + %a) LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| ; CHECK-NEXT: --> {(8 + %a),+,8}<nuw><%loop> U: full-set S: full-set Exits: (8 + (8 * ((-8 + (-1 * (ptrtoint ptr %a to i64)) + (ptrtoint ptr %b to i64)) /u 8))<nuw> + %a) LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: Determining loop execution counts for: @ptr_induction_eq_1 | ||
| ; CHECK-NEXT: Loop %loop: backedge-taken count is ((-8 + (-1 * (ptrtoint ptr %a to i64)) + (ptrtoint ptr %b to i64)) /u 8) | ||
| ; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 2305843009213693951 | ||
| ; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is ((-8 + (-1 * (ptrtoint ptr %a to i64)) + (ptrtoint ptr %b to i64)) /u 8) | ||
| ; CHECK-NEXT: Loop %loop: Trip multiple is 1 | ||
| ; | ||
| entry: | ||
| %cmp = icmp eq ptr %a, %b | ||
| br i1 %cmp, label %exit, label %loop | ||
|
|
||
| loop: | ||
| %ptr.iv = phi ptr [ %ptr.iv.next, %loop ], [ %a, %entry ] | ||
| %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| %exitcond = icmp eq ptr %ptr.iv.next, %b | ||
| br i1 %exitcond, label %exit, label %loop | ||
|
|
||
| exit: | ||
| ret i32 0 | ||
| } | ||
|
|
||
| define i32 @ptr_induction_eq_2(ptr %a, i64 %n) { | ||
| ; CHECK-LABEL: 'ptr_induction_eq_2' | ||
| ; CHECK-NEXT: Classifying expressions for: @ptr_induction_eq_2 | ||
| ; CHECK-NEXT: %b = getelementptr inbounds ptr, ptr %a, i64 %n | ||
| ; CHECK-NEXT: --> ((8 * %n)<nsw> + %a) U: full-set S: full-set | ||
| ; CHECK-NEXT: %ptr.iv = phi ptr [ %ptr.iv.next, %loop ], [ %a, %entry ] | ||
| ; CHECK-NEXT: --> {%a,+,8}<nuw><%loop> U: full-set S: full-set Exits: ((8 * ((-8 + (8 * %n)<nsw>) /u 8))<nuw> + %a) LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| ; CHECK-NEXT: --> {(8 + %a),+,8}<nuw><%loop> U: full-set S: full-set Exits: (8 + (8 * ((-8 + (8 * %n)<nsw>) /u 8))<nuw> + %a) LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: Determining loop execution counts for: @ptr_induction_eq_2 | ||
| ; CHECK-NEXT: Loop %loop: backedge-taken count is ((-8 + (8 * %n)<nsw>) /u 8) | ||
| ; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 2305843009213693951 | ||
| ; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is ((-8 + (8 * %n)<nsw>) /u 8) | ||
| ; CHECK-NEXT: Loop %loop: Trip multiple is 1 | ||
| ; | ||
| entry: | ||
| %b = getelementptr inbounds ptr, ptr %a, i64 %n | ||
| %cmp = icmp eq ptr %a, %b | ||
| br i1 %cmp, label %exit, label %loop | ||
|
|
||
| loop: | ||
| %ptr.iv = phi ptr [ %ptr.iv.next, %loop ], [ %a, %entry ] | ||
| %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| %exitcond = icmp eq ptr %ptr.iv.next, %b | ||
| br i1 %exitcond, label %exit, label %loop | ||
|
|
||
| exit: | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; TODO: It feels like we should be able to calculate the symbolic max | ||
| ; exit count for the loop.inc block here, in the same way as | ||
| ; ptr_induction_eq_1. The problem seems to be in howFarToZero when the | ||
| ; ControlsOnlyExit is set to false. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For ptr_induction_eq_1, we prove that %b-%a is divisible by 8, so the trip count is (b-a)/8. (If difference isn't divisible by 8, we eventually branch on poison.) Here, we can't prove that: as long as there's another exit, the loop can go on indefinitely (at least, until we read past the end of the allocation). So we can't do any useful math. If you tell the compiler the pointers are aligned (for example, using an "align" attribute), we do the computation. Alternatively, we could compute a count assuming the loop exits via a particular branch; see #83052 (review) .
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, this looks to be the same underlying issue as for #101372. Looking into why Clang doesn't generate
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But in that example, unless I'm missing something, the early exit dominates the latch. I don't see how the early exit could make the symbolic max loop trip count greater than the backedge-taken count from the latch? I'm probably not explaining myself that well, but what I mean is surely the early exit can only reduce the trip count, not extend it?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC, consider the something like The early exit then could exit at any later iteration (e.g. when ptr iv is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's fair enough, but then surely the loop in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The early exit in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see. That's the bit I was missing. I think I understand this now. Thanks! So if the IR contained information about alignment that might help?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anyway, the reason I'm asking about this is because I believe this to be a common pattern when you invoke the C++ routine
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This helps us prove the loop is finite, but we can't produce a symbolic bound; at most, we could prove the max iteration count is 2^60 or something like that. Which is marginally helpful. We could also generate a predicated backedge-taken count, which would be useful in contexts like vectorization. Granted, we don't usually vectorize loops with multiple exits anyway, but I guess that's changing a bit.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had a look at adding the predicate and it looks that also helps in some non-multi-exit cases: #108777 #101372 also contains some discussion about encoding alignment assumptions for certain libc++ data types/interfaces, as that would also help in other cases for which versioning is not applicable (e.g. removing bounds checks) |
||
| define i32 @ptr_induction_early_exit_eq_1(ptr %a, ptr %b, ptr %c) { | ||
| ; CHECK-LABEL: 'ptr_induction_early_exit_eq_1' | ||
| ; CHECK-NEXT: Classifying expressions for: @ptr_induction_early_exit_eq_1 | ||
| ; CHECK-NEXT: %ptr.iv = phi ptr [ %ptr.iv.next, %loop.inc ], [ %a, %entry ] | ||
| ; CHECK-NEXT: --> {%a,+,8}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: %ld1 = load ptr, ptr %ptr.iv, align 8 | ||
| ; CHECK-NEXT: --> %ld1 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } | ||
| ; CHECK-NEXT: %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| ; CHECK-NEXT: --> {(8 + %a),+,8}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: Determining loop execution counts for: @ptr_induction_early_exit_eq_1 | ||
| ; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count. | ||
| ; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE*** | ||
| ; CHECK-NEXT: exit count for loop.inc: ***COULDNOTCOMPUTE*** | ||
| ; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count. | ||
| ; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count. | ||
| ; CHECK-NEXT: symbolic max exit count for loop: ***COULDNOTCOMPUTE*** | ||
| ; CHECK-NEXT: symbolic max exit count for loop.inc: ***COULDNOTCOMPUTE*** | ||
| ; | ||
| entry: | ||
| %cmp = icmp eq ptr %a, %b | ||
| br i1 %cmp, label %exit, label %loop | ||
|
|
||
| loop: | ||
| %ptr.iv = phi ptr [ %ptr.iv.next, %loop.inc ], [ %a, %entry ] | ||
| %ld1 = load ptr, ptr %ptr.iv, align 8 | ||
| %earlyexitcond = icmp eq ptr %ld1, %c | ||
| br i1 %earlyexitcond, label %exit, label %loop.inc | ||
|
|
||
| loop.inc: | ||
| %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| %exitcond = icmp eq ptr %ptr.iv.next, %b | ||
| br i1 %exitcond, label %exit, label %loop | ||
|
|
||
| exit: | ||
| ret i32 0 | ||
| } | ||
|
|
||
| define i32 @ptr_induction_early_exit_eq_2(ptr %a, i64 %n, ptr %c) { | ||
| ; CHECK-LABEL: 'ptr_induction_early_exit_eq_2' | ||
| ; CHECK-NEXT: Classifying expressions for: @ptr_induction_early_exit_eq_2 | ||
| ; CHECK-NEXT: %b = getelementptr inbounds ptr, ptr %a, i64 %n | ||
| ; CHECK-NEXT: --> ((8 * %n)<nsw> + %a) U: full-set S: full-set | ||
| ; CHECK-NEXT: %ptr.iv = phi ptr [ %ptr.iv.next, %loop.inc ], [ %a, %entry ] | ||
| ; CHECK-NEXT: --> {%a,+,8}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: %ld1 = load ptr, ptr %ptr.iv, align 8 | ||
| ; CHECK-NEXT: --> %ld1 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } | ||
| ; CHECK-NEXT: %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| ; CHECK-NEXT: --> {(8 + %a),+,8}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | ||
| ; CHECK-NEXT: Determining loop execution counts for: @ptr_induction_early_exit_eq_2 | ||
| ; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count. | ||
| ; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE*** | ||
| ; CHECK-NEXT: exit count for loop.inc: ((-8 + (8 * %n)<nsw>) /u 8) | ||
| ; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 2305843009213693951 | ||
| ; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is ((-8 + (8 * %n)<nsw>) /u 8) | ||
| ; CHECK-NEXT: symbolic max exit count for loop: ***COULDNOTCOMPUTE*** | ||
| ; CHECK-NEXT: symbolic max exit count for loop.inc: ((-8 + (8 * %n)<nsw>) /u 8) | ||
| ; | ||
| entry: | ||
| %b = getelementptr inbounds ptr, ptr %a, i64 %n | ||
| %cmp = icmp eq ptr %a, %b | ||
| br i1 %cmp, label %exit, label %loop | ||
|
|
||
| loop: | ||
| %ptr.iv = phi ptr [ %ptr.iv.next, %loop.inc ], [ %a, %entry ] | ||
| %ld1 = load ptr, ptr %ptr.iv, align 8 | ||
| %earlyexitcond = icmp eq ptr %ld1, %c | ||
| br i1 %earlyexitcond, label %exit, label %loop.inc | ||
|
|
||
| loop.inc: | ||
| %ptr.iv.next = getelementptr inbounds i8, ptr %ptr.iv, i64 8 | ||
| %exitcond = icmp eq ptr %ptr.iv.next, %b | ||
| br i1 %exitcond, label %exit, label %loop | ||
|
|
||
| exit: | ||
| ret i32 0 | ||
| } | ||
|
|
||
|
|
||
| define void @gep_addrec_nw(ptr %a) { | ||
| ; CHECK-LABEL: 'gep_addrec_nw' | ||
| ; CHECK-NEXT: Classifying expressions for: @gep_addrec_nw | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.