This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Strip offset when folding and/or of icmps
ClosedPublic

Authored by nikic on Nov 9 2021, 1:13 PM.

Details

Summary

When folding and/or of icmps, look through add of a constant and adjust the icmp range instead. Effectively, this decomposes X + C1 < C2 style range checks back into a normal range. This allows us to fold comparisons involving two range checks or one range check and some other condition. We had a fold for a really specific case of this (or of range check and eq, and only one one side!) while this handles it in fully generality.

Diff Detail

Event Timeline

nikic created this revision.Nov 9 2021, 1:13 PM
nikic requested review of this revision.Nov 9 2021, 1:13 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 9 2021, 1:13 PM
nikic added a comment.Nov 9 2021, 1:30 PM

I expect this will subsume a few more folds strewn about, such as https://github.com/llvm/llvm-project/blob/24e07e1cf58841601287dca3df55078041dde00d/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp#L777-L789. However, this fold needs to be expanded to support splats first (which is trivial, but affects a number of folds under the same branch, so I'll do that separately).

Nice!

I don't see any test diffs with 2 signed preds. Is there any value in adding a test like that to further exercise the range logic?

define i1 @src(i64 %x) {
  %t1 = add i64 %x, 127
  %t2 = icmp slt i64 %t1, 1024
  %t3 = add i64 %x, 128
  %t4 = icmp slt i64 %t3, 256
  %t5 = and i1 %t2, %t4
  ret i1 %t5
}
llvm/test/Transforms/InstCombine/signed-truncation-check.ll
957–958

It's not a single instruction, but don't need this comment now.

nikic updated this revision to Diff 386192.Nov 10 2021, 9:03 AM

Rebase over test with signed preds (https://alive2.llvm.org/ce/z/qv9MZr), drop outdated comment.

I actually thought that we were already canonicalizing signed range checks to unsigned ones, but apparently we aren't.

lebedev.ri added inline comments.Nov 10 2021, 9:12 AM
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
1209–1221

What about the case where both of them are add's,
but we should have matched only one of them,
i.e. y = x + C0; q = ((y + C1) < C2) | (y < C3) ?

2467

Hm, but that new code expects two add's.

nikic added inline comments.Nov 10 2021, 9:20 AM
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
1209–1221

Can this happen though? In canonical IR this will get folded to (x + (C1 + C0) < C2) | (x + C0 < C3), at which point we have the expected pattern. (In non-canonical IR this is not the case, but that shouldn't be a problem as this is not a question of correctness -- the fold will apply only once it has become canonical.)

2467

It doesn't require both comparisons to have an add. We can have an add on neither, both or one of them (this pattern).

This revision is now accepted and ready to land.Nov 10 2021, 9:37 AM
spatel accepted this revision.Nov 10 2021, 9:46 AM

LGTM

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
1209–1210

On first look, I also didn't catch that this block will match either 1 or 2 offsets, so we should make that clear in the code comment.
Something like:

// Look through add of a constant offset on V1, V2, or both operands...
This revision was automatically updated to reflect the committed changes.