This handles the case where this combine:
icmp sgt (ashr X, ShAmtC), C --> icmp sgt X, ((C + 1) << ShAmtC) - 1
wasn't performed by instcombine.
This is my first patch to LVI and I'm not really sure this is right.
Proof of the original combine: https://alive2.llvm.org/ce/z/SfpsvX
I think the better way to explain this is icmp slt (ashr X, ShAmtC), C --> icmp slt X, C << ShAmtC (https://alive2.llvm.org/ce/z/ww5u4i). In this case the only precondition is ((C << ShAmtC) >> ShAmtC) == C. Same for sge.
All the +1/-1 get introduced by using sgt/sle because we're effectively trying to reduce them to that base case. This also introduces the extra preconditions to avoid overflow on +/-1.
With this in mind, I think we can introduce an abstraction like this to transparently handle all the signed predicates while only specifying the fold for slt (without knowledge of anything about ashr in particular):
And then do something like this:
Code is untested, but I think the general idea should work.