-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] simplify icmp pred x, ~x
#73990
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 all commits
ea9f69f
0d681e7
e9aba12
11efb03
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 | ||
---|---|---|---|---|
|
@@ -5,6 +5,349 @@ declare void @llvm.assume(i1) | |||
declare void @barrier() | ||||
declare void @use.i8(i8) | ||||
|
||||
; Test case of X comp X^Neg_C, which have Transform to SLT. | ||||
; X s< X^Neg_C --> X s< 0 | ||||
define i1 @src_slt(i8 %x) { | ||||
; CHECK-LABEL: @src_slt( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp slt i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_slt_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_slt_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp slt <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X s<= X^Neg_C --> X s< 0 | ||||
define i1 @src_sle(i8 %x) { | ||||
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. Please take a look at this: https://llvm.godbolt.org/z/zvMcnvsE4 Currently, the src_sle and src_sle_comm (and other comm pairs) actually all test the case where the not is on the left hand side. To test the case where the not is on the right hand side, you need to introduce an additional, higher-complexity operation, like a mul in this example. The other thing I noticed is that predicates already get canonicalized to from non-strict to strict, apparently thanks to this transform:
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. @nikic I could not even imagine that!! thank you for let me know! I don't sure that I exact understood what you say. should I change the code shown in the link next time? 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. @nikic maybe this problem solved after implemented code moved to 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 comment comment is not done. The tests still don't properly check the commuted case -- and it looks like the implementation doesn't handle the commuted case either. It would be probably be better to move the code inside foldICmpXorXX(), because that already has handling for the commutation. 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. After #91185 you shouldn't need to change the tests anymore -- just make sure that the commuted ones actually do get folded. |
||||
; CHECK-LABEL: @src_sle( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp sle i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_sle_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_sle_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp sle <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X u> X^Neg_C --> X s< 0 | ||||
define i1 @src_ugt(i8 %x) { | ||||
; CHECK-LABEL: @src_ugt( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp ugt i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_ugt_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_ugt_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp ugt <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X u>= X^Neg_C --> X s< 0 | ||||
define i1 @src_uge(i8 %x) { | ||||
; CHECK-LABEL: @src_uge( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp uge i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_uge_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_uge_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp uge <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_uge_vec_min(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_uge_vec_min( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -128, i8 -128> | ||||
%cmp = icmp uge <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_uge_vec_128(<2 x i128> %x) { | ||||
; CHECK-LABEL: @src_uge_vec_128( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i128> [[X:%.*]], zeroinitializer | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728> | ||||
%cmp = icmp uge <2 x i128> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; Test case of X comp X^Neg_C, which have Transform to SGT. | ||||
; X s> X^Neg_C --> X s> -1 | ||||
define i1 @src_sgt(i8 %x) { | ||||
; CHECK-LABEL: @src_sgt( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp sgt i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_sgt_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_sgt_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1> | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp sgt <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X s>= X^Neg_C --> X s> -1 | ||||
define i1 @src_sge(i8 %x) { | ||||
; CHECK-LABEL: @src_sge( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp sge i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_sge_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_sge_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1> | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp sge <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X u< X^Neg_C --> X s> -1 | ||||
define i1 @src_ult(i8 %x) { | ||||
; CHECK-LABEL: @src_ult( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp ult i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_ult_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_ult_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1> | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp ult <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X u<= X^Neg_C --> X s> -1 | ||||
define i1 @src_ule(i8 %x) { | ||||
; CHECK-LABEL: @src_ule( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1 | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%not = xor i8 %x, -1 | ||||
%cmp = icmp ule i8 %x, %not | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_ule_vec(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_ule_vec( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1> | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -1, i8 -1> | ||||
%cmp = icmp ule <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_ule_vec_min(<2 x i8> %x) { | ||||
; CHECK-LABEL: @src_ule_vec_min( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1> | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i8> %x, <i8 -128, i8 -128> | ||||
%cmp = icmp ule <2 x i8> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
define <2 x i1> @src_ule_vec_128(<2 x i128> %x) { | ||||
; CHECK-LABEL: @src_ule_vec_128( | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i128> [[X:%.*]], <i128 -1, i128 -1> | ||||
; CHECK-NEXT: ret <2 x i1> [[CMP]] | ||||
; | ||||
%not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728> | ||||
%cmp = icmp ule <2 x i128> %x, %not | ||||
ret <2 x i1> %cmp | ||||
} | ||||
|
||||
; X comp X^Neg_C tests. negative | ||||
; X comp Y | ||||
define i1 @src_sle_xny(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_sle_xny( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp sle i8 %x, %y.not | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_sle_nyx(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_sle_nyx( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp sle i8 %y.not, %x | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_sge_xny(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_sge_xny( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp sge i8 %x, %y.not | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_sge_nyx(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_sge_nyx( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp sge i8 %y.not, %x | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_ule_xny(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_ule_xny( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp ule i8 %x, %y.not | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_ule_nyx(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_ule_nyx( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp ule i8 %y.not, %x | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_uge_xny(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_uge_xny( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp uge i8 %x, %y.not | ||||
ret i1 %cmp | ||||
} | ||||
define i1 @src_uge_nyx(i8 %x, i8 %y) { | ||||
; CHECK-LABEL: @src_uge_nyx( | ||||
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1 | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X:%.*]], [[Y_NOT]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%y.not = xor i8 %y, -1 | ||||
%cmp = icmp uge i8 %y.not, %x | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
; X comp X^Neg_C tests. negative | ||||
; (X+1) comp X^Neg_C | ||||
define i1 @src_sle_incx_nx(i8 %x) { | ||||
; CHECK-LABEL: @src_sle_incx_nx( | ||||
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 -2, [[X:%.*]] | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[TMP1]], [[X]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%nx = xor i8 %x, -1 | ||||
%inc.x = add i8 %x, 1 | ||||
%cmp = icmp sle i8 %inc.x, %nx | ||||
ret i1 %cmp | ||||
} | ||||
; (X-1) comp X^Neg_C | ||||
define i1 @src_sle_decx_nx(i8 %x) { | ||||
; CHECK-LABEL: @src_sle_decx_nx( | ||||
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[X:%.*]] | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[TMP1]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%nx = xor i8 %x, -1 | ||||
%dec.x = add i8 %x, -1 | ||||
%cmp = icmp sle i8 %dec.x, %nx | ||||
ret i1 %cmp | ||||
} | ||||
; X comp (X+1)^Neg_C | ||||
define i1 @src_sle_x_nincx(i8 %x) { | ||||
; CHECK-LABEL: @src_sle_x_nincx( | ||||
; CHECK-NEXT: [[NOT_INC_X:%.*]] = sub i8 -2, [[X:%.*]] | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[NOT_INC_X]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%inc.x = add i8 %x, 1 | ||||
%not.inc.x = xor i8 %inc.x, -1 | ||||
%cmp = icmp sle i8 %x, %not.inc.x | ||||
ret i1 %cmp | ||||
} | ||||
; X comp (X-1)^Neg_C | ||||
define i1 @src_sle_x_ndecx(i8 %x) { | ||||
; CHECK-LABEL: @src_sle_x_ndecx( | ||||
; CHECK-NEXT: [[NOT_DEC_X:%.*]] = sub i8 0, [[X:%.*]] | ||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[NOT_DEC_X]] | ||||
; CHECK-NEXT: ret i1 [[CMP]] | ||||
; | ||||
%dec.x = add i8 %x, -1 | ||||
%not.dec.x = xor i8 %dec.x, -1 | ||||
%cmp = icmp sle i8 %x, %not.dec.x | ||||
ret i1 %cmp | ||||
} | ||||
|
||||
; test for (~x ^ y) < ~z | ||||
define i1 @test_xor1(i8 %x, i8 %y, i8 %z) { | ||||
; CHECK-LABEL: @test_xor1( | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like there are bit too many tests here for such a simple transform :) See https://llvm.org/docs/InstCombineContributorGuide.html#general-testing-considerations:
It's not necessary to have a variant of every test with -1 and -128. It's okay to have most tests with -1 and just one with -128.
Similarly, we don't need to have an i128 variant of every tests. It's again something where it's fine to test it just once.