Skip to content

[InstCombine] Canonicalize and(zext(A), B) into select A, B & 1, 0 #66740

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

Merged
merged 6 commits into from
Sep 28, 2023

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Sep 19, 2023

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.

@llvmbot
Copy link
Member

llvmbot commented Sep 19, 2023

@llvm/pr-subscribers-llvm-transforms

Changes

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 #66606.


Full diff: https://github.com/llvm/llvm-project/pull/66740.diff

6 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+6)
  • (modified) llvm/test/Transforms/InstCombine/and-or-icmps.ll (+5-7)
  • (modified) llvm/test/Transforms/InstCombine/and.ll (+10-18)
  • (modified) llvm/test/Transforms/InstCombine/icmp.ll (+16-15)
  • (modified) llvm/test/Transforms/InstCombine/narrow.ll (+1-2)
  • (modified) llvm/test/Transforms/InstCombine/zext-or-icmp.ll (+5-5)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index ca7dfa82ab5a5d7..7fa432e1fdc1790 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2654,6 +2654,12 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
       A->getType()->isIntOrIntVectorTy(1))
     return SelectInst::Create(A, Constant::getNullValue(Ty), B);
 
+  // and(zext(A), B) -> A ? (B & 1) : 0
+  if (match(&I, m_c_And(m_OneUse(m_ZExt(m_Value(A))), m_Value(B))) &&
+      A->getType()->isIntOrIntVectorTy(1))
+    return SelectInst::Create(A, Builder.CreateAnd(B, ConstantInt::get(Ty, 1)),
+                              Constant::getNullValue(Ty));
+
   // (iN X s>> (N-1)) & Y --> (X s< 0) ? Y : 0 -- with optional sext
   if (match(&I, m_c_And(m_OneUse(m_SExtOrSelf(
                             m_AShr(m_Value(X), m_APIntAllowUndef(C)))),
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 065dbf261e131bf..881a9b7ff129dbb 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -2769,9 +2769,9 @@ define i64 @icmp_slt_0_and_icmp_sgt_neg1_i64(i64 %x) {
 define i64 @icmp_slt_0_and_icmp_sge_neg1_i64_fail(i64 %x) {
 ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg1_i64_fail(
 ; CHECK-NEXT:    [[A:%.*]] = icmp sgt i64 [[X:%.*]], -2
-; CHECK-NEXT:    [[B:%.*]] = zext i1 [[A]] to i64
 ; CHECK-NEXT:    [[C:%.*]] = lshr i64 [[X]], 62
-; CHECK-NEXT:    [[D:%.*]] = and i64 [[C]], [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[C]], 1
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[A]], i64 [[TMP1]], i64 0
 ; CHECK-NEXT:    ret i64 [[D]]
 ;
   %A = icmp sge i64 %x, -1
@@ -2871,9 +2871,8 @@ define i32 @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse1(i32 %x) {
 define i32 @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse2(i32 %x) {
 ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse2(
 ; CHECK-NEXT:    [[A:%.*]] = icmp sgt i32 [[X:%.*]], -3
-; CHECK-NEXT:    [[B:%.*]] = zext i1 [[A]] to i32
 ; CHECK-NEXT:    [[C:%.*]] = lshr i32 [[X]], 31
-; CHECK-NEXT:    [[D:%.*]] = and i32 [[C]], [[B]]
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[A]], i32 [[C]], i32 0
 ; CHECK-NEXT:    call void @use32(i32 [[C]])
 ; CHECK-NEXT:    ret i32 [[D]]
 ;
@@ -2923,10 +2922,9 @@ define i32 @icmp_slt_0_or_icmp_eq_100_i32_multiuse_fail1(i32 %x) {
 
 define i32 @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_multiuse_fail2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_multiuse_fail2(
-; CHECK-NEXT:    [[A:%.*]] = icmp ne i32 [[X:%.*]], -2
-; CHECK-NEXT:    [[B:%.*]] = zext i1 [[A]] to i32
+; CHECK-NEXT:    [[A_NOT:%.*]] = icmp eq i32 [[X:%.*]], -2
 ; CHECK-NEXT:    [[C:%.*]] = lshr i32 [[Y:%.*]], 31
-; CHECK-NEXT:    [[D:%.*]] = and i32 [[C]], [[B]]
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[A_NOT]], i32 0, i32 [[C]]
 ; CHECK-NEXT:    call void @use32(i32 [[C]])
 ; CHECK-NEXT:    ret i32 [[D]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll
index 7ec4b0dbb0a12f0..9aa0df3062263cc 100644
--- a/llvm/test/Transforms/InstCombine/and.ll
+++ b/llvm/test/Transforms/InstCombine/and.ll
@@ -2443,8 +2443,8 @@ define i64 @test_and_or_constexpr_infloop() {
 
 define i32 @and_zext(i32 %a, i1 %b) {
 ; CHECK-LABEL: @and_zext(
-; CHECK-NEXT:    [[MASK:%.*]] = zext i1 [[B:%.*]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[MASK]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %mask = zext i1 %b to i32
@@ -2454,8 +2454,8 @@ define i32 @and_zext(i32 %a, i1 %b) {
 
 define i32 @and_zext_commuted(i32 %a, i1 %b) {
 ; CHECK-LABEL: @and_zext_commuted(
-; CHECK-NEXT:    [[MASK:%.*]] = zext i1 [[B:%.*]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[MASK]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %mask = zext i1 %b to i32
@@ -2478,8 +2478,8 @@ define i32 @and_zext_multiuse(i32 %a, i1 %b) {
 
 define <2 x i32> @and_zext_vec(<2 x i32> %a, <2 x i1> %b) {
 ; CHECK-LABEL: @and_zext_vec(
-; CHECK-NEXT:    [[MASK:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[MASK]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i32> [[TMP1]], <2 x i32> zeroinitializer
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %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) {
 ; tests from PR66606
 define i32 @and_zext_eq_even(i32 %a) {
 ; CHECK-LABEL: @and_zext_eq_even(
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT:    [[NOT:%.*]] = zext i1 [[COND]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[NOT]], [[A]]
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-NEXT:    ret i32 0
 ;
   %cond = icmp eq i32 %a, 2
   %not = zext i1 %cond to i32
@@ -2503,10 +2500,7 @@ define i32 @and_zext_eq_even(i32 %a) {
 
 define i32 @and_zext_eq_even_commuted(i32 %a) {
 ; CHECK-LABEL: @and_zext_eq_even_commuted(
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT:    [[NOT:%.*]] = zext i1 [[COND]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[NOT]], [[A]]
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-NEXT:    ret i32 0
 ;
   %cond = icmp eq i32 %a, 2
   %not = zext i1 %cond to i32
@@ -2517,8 +2511,7 @@ define i32 @and_zext_eq_even_commuted(i32 %a) {
 define i32 @and_zext_eq_odd(i32 %a) {
 ; CHECK-LABEL: @and_zext_eq_odd(
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[A:%.*]], 3
-; CHECK-NEXT:    [[NOT:%.*]] = zext i1 [[COND]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[NOT]], [[A]]
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[COND]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %cond = icmp eq i32 %a, 3
@@ -2530,8 +2523,7 @@ define i32 @and_zext_eq_odd(i32 %a) {
 define i32 @and_zext_eq_odd_commuted(i32 %a) {
 ; CHECK-LABEL: @and_zext_eq_odd_commuted(
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[A:%.*]], 3
-; CHECK-NEXT:    [[NOT:%.*]] = zext i1 [[COND]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[NOT]], [[A]]
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[COND]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %cond = icmp eq i32 %a, 3
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 666d85d6cc32103..a5c05278f4232e8 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -4441,9 +4441,9 @@ define i1 @redundant_sign_bit_count_ugt_31_30(i32 %x) {
 define i1 @zext_bool_and_eq0(i1 %x, i8 %y) {
 ; CHECK-LABEL: @zext_bool_and_eq0(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
-; CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[TMP2]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP3]], true
+; CHECK-NEXT:    [[R1:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[R1]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %zx = zext i1 %x to i8
@@ -4454,9 +4454,10 @@ define i1 @zext_bool_and_eq0(i1 %x, i8 %y) {
 
 define <2 x i1> @zext_bool_and_eq0_commute(<2 x i1> %x, <2 x i8> %p) {
 ; CHECK-LABEL: @zext_bool_and_eq0_commute(
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i8> [[P:%.*]] to <2 x i1>
-; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i1> [[TMP1]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor <2 x i1> [[TMP2]], <i1 true, i1 true>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[P:%.*]], <i8 1, i8 1>
+; CHECK-NEXT:    [[R1:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT:    [[NOT_X:%.*]] = xor <2 x i1> [[X:%.*]], <i1 true, i1 true>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[NOT_X]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[R1]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %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) {
 define i1 @zext_bool_and_ne0(i1 %x, i8 %y) {
 ; CHECK-LABEL: @zext_bool_and_ne0(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP2]], [[X:%.*]]
+; CHECK-NEXT:    [[R1:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 [[R1]], i1 false
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %zx = zext i1 %x to i8
@@ -4482,9 +4483,9 @@ define i1 @zext_bool_and_ne0(i1 %x, i8 %y) {
 define i1 @zext_bool_and_ne1(i1 %x, i8 %y) {
 ; CHECK-LABEL: @zext_bool_and_ne1(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
-; CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[TMP2]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP3]], true
+; CHECK-NEXT:    [[R1:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[R1]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %zx = zext i1 %x to i8
@@ -4495,8 +4496,8 @@ define i1 @zext_bool_and_ne1(i1 %x, i8 %y) {
 
 define <2 x i1> @zext_bool_and_eq1(<2 x i1> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @zext_bool_and_eq1(
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i8> [[Y:%.*]] to <2 x i1>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i1> [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[R1:%.*]] = trunc <2 x i8> [[Y:%.*]] to <2 x i1>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[X:%.*]], <2 x i1> [[R1]], <2 x i1> zeroinitializer
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %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) {
 
 define i1 @zext_bool_and_ne0_use(i1 %x, i64 %y) {
 ; CHECK-LABEL: @zext_bool_and_ne0_use(
-; CHECK-NEXT:    [[ZX:%.*]] = zext i1 [[X:%.*]] to i64
-; CHECK-NEXT:    [[A:%.*]] = and i64 [[ZX]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[Y:%.*]], 1
+; CHECK-NEXT:    [[A:%.*]] = select i1 [[X:%.*]], i64 [[TMP1]], i64 0
 ; CHECK-NEXT:    call void @use_i64(i64 [[A]])
 ; CHECK-NEXT:    [[R:%.*]] = icmp ne i64 [[A]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
diff --git a/llvm/test/Transforms/InstCombine/narrow.ll b/llvm/test/Transforms/InstCombine/narrow.ll
index 9e4670b51ad139a..781974d33bf1157 100644
--- a/llvm/test/Transforms/InstCombine/narrow.ll
+++ b/llvm/test/Transforms/InstCombine/narrow.ll
@@ -155,8 +155,7 @@ define i1 @searchArray2(i32 %hay, ptr %haystack) {
 ; CHECK-NEXT:    [[IDX:%.*]] = getelementptr i32, ptr [[HAYSTACK:%.*]], i64 [[INDVAR]]
 ; CHECK-NEXT:    [[LD:%.*]] = load i32, ptr [[IDX]], align 4
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[LD]], [[HAY:%.*]]
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP1]] to i8
-; CHECK-NEXT:    [[AND]] = and i8 [[FOUND]], [[ZEXT]]
+; CHECK-NEXT:    [[AND]] = select i1 [[CMP1]], i8 [[FOUND]], i8 0
 ; CHECK-NEXT:    [[INDVAR_NEXT]] = add i64 [[INDVAR]], 1
 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVAR_NEXT]], 1000
 ; CHECK-NEXT:    br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]]
diff --git a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
index 74d0f2f21aec8e0..dcb8c081f154aa0 100644
--- a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
@@ -173,15 +173,15 @@ define i8 @PR49475_infloop(i32 %t0, i16 %insert, i64 %e, i8 %i162) {
 ; CHECK-NEXT:    [[B:%.*]] = icmp eq i32 [[T0:%.*]], 0
 ; CHECK-NEXT:    [[B2:%.*]] = icmp eq i16 [[INSERT:%.*]], 0
 ; CHECK-NEXT:    [[T1:%.*]] = or i1 [[B]], [[B2]]
-; CHECK-NEXT:    [[EXT:%.*]] = zext i1 [[T1]] to i32
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[EXT]], [[T0]]
-; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[AND]], 140
-; CHECK-NEXT:    [[XOR1:%.*]] = zext i32 [[TMP1]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[T0]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], 140
+; CHECK-NEXT:    [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
+; CHECK-NEXT:    [[XOR1:%.*]] = select i1 [[T1]], i64 [[TMP3]], i64 140
 ; CHECK-NEXT:    [[CONV16:%.*]] = sext i8 [[I162:%.*]] to i64
 ; CHECK-NEXT:    [[SUB17:%.*]] = sub i64 [[CONV16]], [[E:%.*]]
 ; CHECK-NEXT:    [[SEXT:%.*]] = shl i64 [[SUB17]], 32
 ; CHECK-NEXT:    [[CONV18:%.*]] = ashr exact i64 [[SEXT]], 32
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i64 [[CONV18]], [[XOR1]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i64 [[XOR1]], [[CONV18]]
 ; CHECK-NEXT:    [[CONV19:%.*]] = zext i1 [[CMP]] to i16
 ; CHECK-NEXT:    [[OR21:%.*]] = or i16 [[CONV19]], [[INSERT]]
 ; CHECK-NEXT:    [[TOBOOL23_NOT:%.*]] = icmp eq i16 [[OR21]], 0

@dianqk
Copy link
Member

dianqk commented Sep 19, 2023

We should use rebase instead of merge.
And I recommend force push to change the code before the review starts.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 19, 2023

We should use rebase instead of merge. And I recommend force push to change the code before the review starts.

I am confused with the LLVM GitHub user guide. I witnessed someone mess up by doing rebase + force push.
Examples: #65853 #65543 #65535

@nikic
Copy link
Contributor

nikic commented Sep 19, 2023

I think this is the right canonicalization at the IR level, as select allows better analysis than zext(icmp). However, this seems to be universally worse for the backend: https://llvm.godbolt.org/z/Yh7brfc8b So I think we would need an SDAG undo transform. Interestingly, this already happens for riscv64, so maybe the undo transform already exists but is not enabled for all target.

@goldsteinn What do you think?

@sftlbcn
Copy link

sftlbcn commented Sep 19, 2023

this also fixes #28612

@goldsteinn
Copy link
Contributor

goldsteinn commented Sep 19, 2023

I think this is the right canonicalization at the IR level, as select allows better analysis than zext(icmp). However, this seems to be universally worse for the backend: https://llvm.godbolt.org/z/Yh7brfc8b So I think we would need an SDAG undo transform. Interestingly, this already happens for riscv64, so maybe the undo transform already exists but is not enabled for all target.

@goldsteinn What do you think?

Yeah, I think I agree, I looked a bit around DAGCombiner and can't find where risv does this but pretty sure its in the RISCV target codes as commenting out the entirety of visitSelect, visitSelect_CC, and visitAndLike doesn't change the riscv codegen.

I'd say since we also do:

  %zx = sext i1 %x to i32
  %r = and i32 %zx, %y

to

  %r = select i1 %x, i32 %masked, i32 0

This makes sense in that context.

I'll throw up a patch shortly to cover this case in the backend.

Edit: its a bit more ambiguous if the i1 is coming from setcc: https://llvm.godbolt.org/z/dxEs4KrMs
Edit2: Its also a bit more challenging to fix this up in the DAGCombiner b.c booleans are not handled the same way across targets.

@goldsteinn
Copy link
Contributor

Created: #66793 which fixes the backend regression this can cause.

@nikic
Copy link
Contributor

nikic commented Sep 20, 2023

You might want to check whether this also fixes #66740 and if so add a test.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 21, 2023

You might want to check whether this also fixes #66740 and if so add a test.

Confirmed. I have added a pre-commit test for #66733 in 1a73a6b.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 21, 2023

To avoid backend regressions, I will merge this PR after #66793.

@dtcxzyw dtcxzyw merged commit a7f962c into llvm:main Sep 28, 2023
@dtcxzyw dtcxzyw deleted the canonicalize-and-zext-bool branch September 28, 2023 18:52
legrosbuffle pushed a commit to legrosbuffle/llvm-project that referenced this pull request Sep 29, 2023
llvm#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 llvm#66676. 
Alive2: https://alive2.llvm.org/ce/z/598phE
Fixes llvm#66733.
Fixes llvm#66606.
Fixes llvm#28612.
cyyself added a commit to cyyself/llvm-project that referenced this pull request Jul 17, 2024
cyyself added a commit to cyyself/llvm-project that referenced this pull request Jul 18, 2024
cyyself added a commit to cyyself/llvm-project that referenced this pull request Jul 18, 2024
cyyself added a commit to cyyself/llvm-project that referenced this pull request Jul 24, 2024
cyyself added a commit to cyyself/llvm-project that referenced this pull request Aug 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(a == 0) & (((short)a) >= 0) is not always optimized to just a == 0 [InstCombine] a & !a is not optimized recognize 'and' of disjoint ranges
6 participants