This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Extend sub(sext(add(X, Y)), sext(add(X, Z))) -> sub(Y, Z) fold to adds that mutually wrap
Needs ReviewPublic

Authored by dmgreen on Aug 21 2023, 12:17 AM.

Details

Summary

This combine, added in D157598, folds the sub of two extended adds if the adds are no wrap, as we know the extends are simple. This isn't just valid for no-wrap though - it is also valid if the two adds wrap at the same time. i.e given the following code:

;  %a = srem i32 %X, 3
;  switch i32 %a, label %.loopexit477 [
;    i32 1, label %preheader
;    i32 2, label %.loopexit477.loopexit667
;  ]
;
;preheader:
;  %b = add i32 %X, 1
;  %c = sext i32 %b to i64
;  %d = add i32 %X, 2
;  %e = sext i32 %d to i64
;  %f = sub nsw i64 %e, %c

The sub is provably '1' because due to knowing from the dominating condition that X % 3 == 1, and that for i32 the two adds will either both not wrap (for most values of X), or both wrap if X==2147483647. https://alive2.llvm.org/ce/z/JvnY-o

So this patch adds a isKnownMutuallyWrapping function to detect when two adds will wrap at the same time, and from the mod case detects if the two adds will wrap using (C3 - (Max % C4) + C1) / C4 == (C3 - (Max % C4) + C2) / C4, where C4 is the mod denom and C3 is the remainder.
For Signed: https://alive2.llvm.org/ce/z/N93Njy
And Unsigned: https://alive2.llvm.org/ce/z/A9gzbK (note this is more generally true for the conditions here, but this patch only tries to prove it for the mutually wrapping case).

Diff Detail