For some cases, InstCombine replaces the sequence of xor/sub instruction followed by cmp instruction into a single cmp instruction. However, this replacement may result suboptimal result especially when the xor/sub has more than one use, as discussed in bug 26465 (https://llvm.org/bugs/show_bug.cgi?id=26465). This patch make the replacement happen only when xor/sub has only one use. Below are test codes for each case that addressed by this patch. For all cases below, instcombine pass does not change the original code at all when the fix is applied.
Case 1: ((xor A, ConstB) == ConstC) -> (A == (ConstB xor ConstC))
- test case
define zeroext i1 @foo(i32 %lhs, i32 %rhs) { %xor = xor i32 %lhs, 5 %cmp1 = icmp eq i32 %xor, 10 %cmp2 = icmp eq i32 %xor, %rhs %sel = or i1 %cmp1, %cmp2 ret i1 %sel }
- Output after instcombine without fix
define zeroext i1 @foo(i32 %lhs, i32 %rhs) { %xor = xor i32 %lhs, 5 %cmp1 = icmp eq i32 %lhs, 15 %cmp2 = icmp eq i32 %xor, %rhs %sel = or i1 %cmp1, %cmp2 ret i1 %sel }
Case 2: ((xor A, B) == 0) with (A == B)
- test case
define zeroext i1 @foo(i32 %lhs, i32 %rhs) { %xor = xor i32 %lhs, %rhs %cmp1 = icmp eq i32 %xor, 0 %cmp2 = icmp eq i32 %xor, 32 %sel = xor i1 %cmp1, %cmp2 ret i1 %sel }
- Output after instcombine without fix
define zeroext i1 @foo(i32 %lhs, i32 %rhs) { %xor = xor i32 %lhs, %rhs %cmp1 = icmp eq i32 %lhs, %rhs %cmp2 = icmp eq i32 %xor, 32 %sel = xor i1 %cmp1, %cmp2 ret i1 %sel }
Case 3: ((sub A, B) == 0) -> (A == B)
- test case
define zeroext i1 @foo(i32 %lhs, i32 %rhs) { %sub = sub nsw i32 %lhs, %rhs %cmp1 = icmp eq i32 %sub, 0 %cmp2 = icmp eq i32 %sub, 31 %sel = or i1 %cmp1, %cmp2 ret i1 %sel }
- Output after instcombine without fix
define zeroext i1 @foo(i32 %lhs, i32 %rhs) { %sub = sub nsw i32 %lhs, %rhs %cmp1 = icmp eq i32 %lhs, %rhs %cmp2 = icmp eq i32 %sub, 31 %sel = or i1 %cmp1, %cmp2 ret i1 %sel }
Sorry - I missed this comment too. Please move it lower to match the format of the other cases.