Skip to content

Commit a7f962c

Browse files
authored
[InstCombine] Canonicalize and(zext(A), B) into select A, B & 1, 0 (#66740)
This patch canonicalizes the pattern `and(zext(A), B)` into `select A, B & 1, 0`. Thus, we can reuse transforms `select B == even, B & 1, 0 -> 0` and `select B == odd, B & 1, 0 -> zext(B == odd)` in `InstCombine`. It is an alternative to #66676. Alive2: https://alive2.llvm.org/ce/z/598phE Fixes #66733. Fixes #66606. Fixes #28612.
1 parent 3231a36 commit a7f962c

File tree

6 files changed

+44
-51
lines changed

6 files changed

+44
-51
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,6 +2650,12 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
26502650
A->getType()->isIntOrIntVectorTy(1))
26512651
return SelectInst::Create(A, Constant::getNullValue(Ty), B);
26522652

2653+
// and(zext(A), B) -> A ? (B & 1) : 0
2654+
if (match(&I, m_c_And(m_OneUse(m_ZExt(m_Value(A))), m_Value(B))) &&
2655+
A->getType()->isIntOrIntVectorTy(1))
2656+
return SelectInst::Create(A, Builder.CreateAnd(B, ConstantInt::get(Ty, 1)),
2657+
Constant::getNullValue(Ty));
2658+
26532659
// (-1 + A) & B --> A ? 0 : B where A is 0/1.
26542660
if (match(&I, m_c_And(m_OneUse(m_Add(m_ZExtOrSelf(m_Value(A)), m_AllOnes())),
26552661
m_Value(B)))) {

llvm/test/Transforms/InstCombine/and-or-icmps.ll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2769,9 +2769,9 @@ define i64 @icmp_slt_0_and_icmp_sgt_neg1_i64(i64 %x) {
27692769
define i64 @icmp_slt_0_and_icmp_sge_neg1_i64_fail(i64 %x) {
27702770
; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg1_i64_fail(
27712771
; CHECK-NEXT: [[A:%.*]] = icmp sgt i64 [[X:%.*]], -2
2772-
; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i64
27732772
; CHECK-NEXT: [[C:%.*]] = lshr i64 [[X]], 62
2774-
; CHECK-NEXT: [[D:%.*]] = and i64 [[C]], [[B]]
2773+
; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[C]], 1
2774+
; CHECK-NEXT: [[D:%.*]] = select i1 [[A]], i64 [[TMP1]], i64 0
27752775
; CHECK-NEXT: ret i64 [[D]]
27762776
;
27772777
%A = icmp sge i64 %x, -1
@@ -2871,9 +2871,8 @@ define i32 @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse1(i32 %x) {
28712871
define i32 @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse2(i32 %x) {
28722872
; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse2(
28732873
; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -3
2874-
; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32
28752874
; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31
2876-
; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]]
2875+
; CHECK-NEXT: [[D:%.*]] = select i1 [[A]], i32 [[C]], i32 0
28772876
; CHECK-NEXT: call void @use32(i32 [[C]])
28782877
; CHECK-NEXT: ret i32 [[D]]
28792878
;
@@ -2923,10 +2922,9 @@ define i32 @icmp_slt_0_or_icmp_eq_100_i32_multiuse_fail1(i32 %x) {
29232922

29242923
define i32 @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_multiuse_fail2(i32 %x, i32 %y) {
29252924
; CHECK-LABEL: @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_multiuse_fail2(
2926-
; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], -2
2927-
; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32
2925+
; CHECK-NEXT: [[A_NOT:%.*]] = icmp eq i32 [[X:%.*]], -2
29282926
; CHECK-NEXT: [[C:%.*]] = lshr i32 [[Y:%.*]], 31
2929-
; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]]
2927+
; CHECK-NEXT: [[D:%.*]] = select i1 [[A_NOT]], i32 0, i32 [[C]]
29302928
; CHECK-NEXT: call void @use32(i32 [[C]])
29312929
; CHECK-NEXT: ret i32 [[D]]
29322930
;

llvm/test/Transforms/InstCombine/and.ll

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,8 +2443,8 @@ define i64 @test_and_or_constexpr_infloop() {
24432443

24442444
define i32 @and_zext(i32 %a, i1 %b) {
24452445
; CHECK-LABEL: @and_zext(
2446-
; CHECK-NEXT: [[MASK:%.*]] = zext i1 [[B:%.*]] to i32
2447-
; CHECK-NEXT: [[R:%.*]] = and i32 [[MASK]], [[A:%.*]]
2446+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 1
2447+
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 0
24482448
; CHECK-NEXT: ret i32 [[R]]
24492449
;
24502450
%mask = zext i1 %b to i32
@@ -2454,8 +2454,8 @@ define i32 @and_zext(i32 %a, i1 %b) {
24542454

24552455
define i32 @and_zext_commuted(i32 %a, i1 %b) {
24562456
; CHECK-LABEL: @and_zext_commuted(
2457-
; CHECK-NEXT: [[MASK:%.*]] = zext i1 [[B:%.*]] to i32
2458-
; CHECK-NEXT: [[R:%.*]] = and i32 [[MASK]], [[A:%.*]]
2457+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 1
2458+
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 0
24592459
; CHECK-NEXT: ret i32 [[R]]
24602460
;
24612461
%mask = zext i1 %b to i32
@@ -2478,8 +2478,8 @@ define i32 @and_zext_multiuse(i32 %a, i1 %b) {
24782478

24792479
define <2 x i32> @and_zext_vec(<2 x i32> %a, <2 x i1> %b) {
24802480
; CHECK-LABEL: @and_zext_vec(
2481-
; CHECK-NEXT: [[MASK:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i32>
2482-
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[MASK]], [[A:%.*]]
2481+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1, i32 1>
2482+
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i32> [[TMP1]], <2 x i32> zeroinitializer
24832483
; CHECK-NEXT: ret <2 x i32> [[R]]
24842484
;
24852485
%mask = zext <2 x i1> %b to <2 x i32>
@@ -2490,10 +2490,7 @@ define <2 x i32> @and_zext_vec(<2 x i32> %a, <2 x i1> %b) {
24902490
; tests from PR66606
24912491
define i32 @and_zext_eq_even(i32 %a) {
24922492
; CHECK-LABEL: @and_zext_eq_even(
2493-
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 2
2494-
; CHECK-NEXT: [[NOT:%.*]] = zext i1 [[COND]] to i32
2495-
; CHECK-NEXT: [[R:%.*]] = and i32 [[NOT]], [[A]]
2496-
; CHECK-NEXT: ret i32 [[R]]
2493+
; CHECK-NEXT: ret i32 0
24972494
;
24982495
%cond = icmp eq i32 %a, 2
24992496
%not = zext i1 %cond to i32
@@ -2503,10 +2500,7 @@ define i32 @and_zext_eq_even(i32 %a) {
25032500

25042501
define i32 @and_zext_eq_even_commuted(i32 %a) {
25052502
; CHECK-LABEL: @and_zext_eq_even_commuted(
2506-
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 2
2507-
; CHECK-NEXT: [[NOT:%.*]] = zext i1 [[COND]] to i32
2508-
; CHECK-NEXT: [[R:%.*]] = and i32 [[NOT]], [[A]]
2509-
; CHECK-NEXT: ret i32 [[R]]
2503+
; CHECK-NEXT: ret i32 0
25102504
;
25112505
%cond = icmp eq i32 %a, 2
25122506
%not = zext i1 %cond to i32
@@ -2517,8 +2511,7 @@ define i32 @and_zext_eq_even_commuted(i32 %a) {
25172511
define i32 @and_zext_eq_odd(i32 %a) {
25182512
; CHECK-LABEL: @and_zext_eq_odd(
25192513
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 3
2520-
; CHECK-NEXT: [[NOT:%.*]] = zext i1 [[COND]] to i32
2521-
; CHECK-NEXT: [[R:%.*]] = and i32 [[NOT]], [[A]]
2514+
; CHECK-NEXT: [[R:%.*]] = zext i1 [[COND]] to i32
25222515
; CHECK-NEXT: ret i32 [[R]]
25232516
;
25242517
%cond = icmp eq i32 %a, 3
@@ -2530,8 +2523,7 @@ define i32 @and_zext_eq_odd(i32 %a) {
25302523
define i32 @and_zext_eq_odd_commuted(i32 %a) {
25312524
; CHECK-LABEL: @and_zext_eq_odd_commuted(
25322525
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 3
2533-
; CHECK-NEXT: [[NOT:%.*]] = zext i1 [[COND]] to i32
2534-
; CHECK-NEXT: [[R:%.*]] = and i32 [[NOT]], [[A]]
2526+
; CHECK-NEXT: [[R:%.*]] = zext i1 [[COND]] to i32
25352527
; CHECK-NEXT: ret i32 [[R]]
25362528
;
25372529
%cond = icmp eq i32 %a, 3
@@ -2545,10 +2537,7 @@ define i32 @and_zext_eq_zero(i32 %A, i32 %C) {
25452537
; CHECK-LABEL: @and_zext_eq_zero(
25462538
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], 0
25472539
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP1]] to i32
2548-
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[A]], [[C:%.*]]
2549-
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1
2550-
; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP2]], [[TMP4]]
2551-
; CHECK-NEXT: ret i32 [[TMP5]]
2540+
; CHECK-NEXT: ret i32 [[TMP2]]
25522541
;
25532542
%1 = icmp eq i32 %A, 0
25542543
%2 = zext i1 %1 to i32

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4441,9 +4441,9 @@ define i1 @redundant_sign_bit_count_ugt_31_30(i32 %x) {
44414441
define i1 @zext_bool_and_eq0(i1 %x, i8 %y) {
44424442
; CHECK-LABEL: @zext_bool_and_eq0(
44434443
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
4444-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
4445-
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[X:%.*]]
4446-
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP3]], true
4444+
; CHECK-NEXT: [[R1:%.*]] = icmp eq i8 [[TMP1]], 0
4445+
; CHECK-NEXT: [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
4446+
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[R1]]
44474447
; CHECK-NEXT: ret i1 [[R]]
44484448
;
44494449
%zx = zext i1 %x to i8
@@ -4454,9 +4454,10 @@ define i1 @zext_bool_and_eq0(i1 %x, i8 %y) {
44544454

44554455
define <2 x i1> @zext_bool_and_eq0_commute(<2 x i1> %x, <2 x i8> %p) {
44564456
; CHECK-LABEL: @zext_bool_and_eq0_commute(
4457-
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i8> [[P:%.*]] to <2 x i1>
4458-
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i1> [[TMP1]], [[X:%.*]]
4459-
; CHECK-NEXT: [[R:%.*]] = xor <2 x i1> [[TMP2]], <i1 true, i1 true>
4457+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[P:%.*]], <i8 1, i8 1>
4458+
; CHECK-NEXT: [[R1:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer
4459+
; CHECK-NEXT: [[NOT_X:%.*]] = xor <2 x i1> [[X:%.*]], <i1 true, i1 true>
4460+
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[NOT_X]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[R1]]
44604461
; CHECK-NEXT: ret <2 x i1> [[R]]
44614462
;
44624463
%y = mul <2 x i8> %p, %p ; thwart complexity-based canonicalization
@@ -4469,8 +4470,8 @@ define <2 x i1> @zext_bool_and_eq0_commute(<2 x i1> %x, <2 x i8> %p) {
44694470
define i1 @zext_bool_and_ne0(i1 %x, i8 %y) {
44704471
; CHECK-LABEL: @zext_bool_and_ne0(
44714472
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
4472-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
4473-
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[X:%.*]]
4473+
; CHECK-NEXT: [[R1:%.*]] = icmp ne i8 [[TMP1]], 0
4474+
; CHECK-NEXT: [[R:%.*]] = select i1 [[X:%.*]], i1 [[R1]], i1 false
44744475
; CHECK-NEXT: ret i1 [[R]]
44754476
;
44764477
%zx = zext i1 %x to i8
@@ -4482,9 +4483,9 @@ define i1 @zext_bool_and_ne0(i1 %x, i8 %y) {
44824483
define i1 @zext_bool_and_ne1(i1 %x, i8 %y) {
44834484
; CHECK-LABEL: @zext_bool_and_ne1(
44844485
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
4485-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
4486-
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[X:%.*]]
4487-
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP3]], true
4486+
; CHECK-NEXT: [[R1:%.*]] = icmp eq i8 [[TMP1]], 0
4487+
; CHECK-NEXT: [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
4488+
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[R1]]
44884489
; CHECK-NEXT: ret i1 [[R]]
44894490
;
44904491
%zx = zext i1 %x to i8
@@ -4495,8 +4496,8 @@ define i1 @zext_bool_and_ne1(i1 %x, i8 %y) {
44954496

44964497
define <2 x i1> @zext_bool_and_eq1(<2 x i1> %x, <2 x i8> %y) {
44974498
; CHECK-LABEL: @zext_bool_and_eq1(
4498-
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i8> [[Y:%.*]] to <2 x i1>
4499-
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP1]], [[X:%.*]]
4499+
; CHECK-NEXT: [[R1:%.*]] = trunc <2 x i8> [[Y:%.*]] to <2 x i1>
4500+
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[X:%.*]], <2 x i1> [[R1]], <2 x i1> zeroinitializer
45004501
; CHECK-NEXT: ret <2 x i1> [[R]]
45014502
;
45024503
%zx = zext <2 x i1> %x to <2 x i8>
@@ -4541,8 +4542,8 @@ define i1 @zext_bool_and_eq0_use(i1 %x, i64 %y) {
45414542

45424543
define i1 @zext_bool_and_ne0_use(i1 %x, i64 %y) {
45434544
; CHECK-LABEL: @zext_bool_and_ne0_use(
4544-
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i64
4545-
; CHECK-NEXT: [[A:%.*]] = and i64 [[ZX]], [[Y:%.*]]
4545+
; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[Y:%.*]], 1
4546+
; CHECK-NEXT: [[A:%.*]] = select i1 [[X:%.*]], i64 [[TMP1]], i64 0
45464547
; CHECK-NEXT: call void @use_i64(i64 [[A]])
45474548
; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[A]], 0
45484549
; CHECK-NEXT: ret i1 [[R]]

llvm/test/Transforms/InstCombine/narrow.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ define i1 @searchArray2(i32 %hay, ptr %haystack) {
155155
; CHECK-NEXT: [[IDX:%.*]] = getelementptr i32, ptr [[HAYSTACK:%.*]], i64 [[INDVAR]]
156156
; CHECK-NEXT: [[LD:%.*]] = load i32, ptr [[IDX]], align 4
157157
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[LD]], [[HAY:%.*]]
158-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[CMP1]] to i8
159-
; CHECK-NEXT: [[AND]] = and i8 [[FOUND]], [[ZEXT]]
158+
; CHECK-NEXT: [[AND]] = select i1 [[CMP1]], i8 [[FOUND]], i8 0
160159
; CHECK-NEXT: [[INDVAR_NEXT]] = add i64 [[INDVAR]], 1
161160
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVAR_NEXT]], 1000
162161
; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]]

llvm/test/Transforms/InstCombine/zext-or-icmp.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,15 @@ define i8 @PR49475_infloop(i32 %t0, i16 %insert, i64 %e, i8 %i162) {
173173
; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[T0:%.*]], 0
174174
; CHECK-NEXT: [[B2:%.*]] = icmp eq i16 [[INSERT:%.*]], 0
175175
; CHECK-NEXT: [[T1:%.*]] = or i1 [[B]], [[B2]]
176-
; CHECK-NEXT: [[EXT:%.*]] = zext i1 [[T1]] to i32
177-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[EXT]], [[T0]]
178-
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[AND]], 140
179-
; CHECK-NEXT: [[XOR1:%.*]] = zext i32 [[TMP1]] to i64
176+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[T0]], 1
177+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], 140
178+
; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
179+
; CHECK-NEXT: [[XOR1:%.*]] = select i1 [[T1]], i64 [[TMP3]], i64 140
180180
; CHECK-NEXT: [[CONV16:%.*]] = sext i8 [[I162:%.*]] to i64
181181
; CHECK-NEXT: [[SUB17:%.*]] = sub i64 [[CONV16]], [[E:%.*]]
182182
; CHECK-NEXT: [[SEXT:%.*]] = shl i64 [[SUB17]], 32
183183
; CHECK-NEXT: [[CONV18:%.*]] = ashr exact i64 [[SEXT]], 32
184-
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[CONV18]], [[XOR1]]
184+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i64 [[XOR1]], [[CONV18]]
185185
; CHECK-NEXT: [[CONV19:%.*]] = zext i1 [[CMP]] to i16
186186
; CHECK-NEXT: [[OR21:%.*]] = or i16 [[CONV19]], [[INSERT]]
187187
; CHECK-NEXT: [[TOBOOL23_NOT:%.*]] = icmp eq i16 [[OR21]], 0

0 commit comments

Comments
 (0)