[llvm] [InstCombine] Fold `select Cond, not X, X` into `Cond ^ X` (PR #90089)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri May 17 06:09:45 PDT 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/90089

>From 6dffd8b83a7dec8bc40c425b5bb6e4a51e9ffc46 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 26 Apr 2024 01:04:57 +0800
Subject: [PATCH 1/4] [InstCombine] Add pre-commit tests. NFC.

---
 .../test/Transforms/InstCombine/select-cmp.ll | 78 +++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/select-cmp.ll b/llvm/test/Transforms/InstCombine/select-cmp.ll
index 711fac542179f..1188ded2f807e 100644
--- a/llvm/test/Transforms/InstCombine/select-cmp.ll
+++ b/llvm/test/Transforms/InstCombine/select-cmp.ll
@@ -345,4 +345,82 @@ define i1 @icmp_no_common(i1 %c, i8 %x, i8 %y, i8 %z) {
   ret i1 %r
 }
 
+define i1 @test_select_inverse1(i64 %x, i1 %y) {
+; CHECK-LABEL: @test_select_inverse1(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i64 [[X:%.*]], 0
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i64 [[X]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[SEL]]
+;
+  %cmp1 = icmp ne i64 %x, 0
+  %cmp2 = icmp eq i64 %x, 0
+  %sel = select i1 %y, i1 %cmp1, i1 %cmp2
+  ret i1 %sel
+}
+
+define i1 @test_select_inverse2(i64 %x, i1 %y) {
+; CHECK-LABEL: @test_select_inverse2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i64 [[X:%.*]], -1
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[X]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[SEL]]
+;
+  %cmp1 = icmp sgt i64 %x, -1
+  %cmp2 = icmp slt i64 %x, 0
+  %sel = select i1 %y, i1 %cmp1, i1 %cmp2
+  ret i1 %sel
+}
+
+define i1 @test_select_inverse3(ptr %x, i1 %y) {
+; CHECK-LABEL: @test_select_inverse3(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq ptr [[X:%.*]], null
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne ptr [[X]], null
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[SEL]]
+;
+  %cmp1 = icmp eq ptr %x, null
+  %cmp2 = icmp ne ptr %x, null
+  %sel = select i1 %y, i1 %cmp1, i1 %cmp2
+  ret i1 %sel
+}
+
+define i1 @test_select_inverse_fail(i64 %x, i1 %y) {
+; CHECK-LABEL: @test_select_inverse_fail(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i64 [[X:%.*]], 0
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[X]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[SEL]]
+;
+  %cmp1 = icmp sgt i64 %x, 0
+  %cmp2 = icmp slt i64 %x, 0
+  %sel = select i1 %y, i1 %cmp1, i1 %cmp2
+  ret i1 %sel
+}
+
+define <2 x i1> @test_select_inverse_vec(<2 x i64> %x, <2 x i1> %y) {
+; CHECK-LABEL: @test_select_inverse_vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i64> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq <2 x i64> [[X]], zeroinitializer
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[Y:%.*]], <2 x i1> [[CMP1]], <2 x i1> [[CMP2]]
+; CHECK-NEXT:    ret <2 x i1> [[SEL]]
+;
+  %cmp1 = icmp ne <2 x i64> %x, zeroinitializer
+  %cmp2 = icmp eq <2 x i64> %x, zeroinitializer
+  %sel = select <2 x i1> %y, <2 x i1> %cmp1, <2 x i1> %cmp2
+  ret <2 x i1> %sel
+}
+
+define <2 x i1> @test_select_inverse_vec_fail(<2 x i64> %x, i1 %y) {
+; CHECK-LABEL: @test_select_inverse_vec_fail(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i64> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq <2 x i64> [[X]], zeroinitializer
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], <2 x i1> [[CMP1]], <2 x i1> [[CMP2]]
+; CHECK-NEXT:    ret <2 x i1> [[SEL]]
+;
+  %cmp1 = icmp ne <2 x i64> %x, zeroinitializer
+  %cmp2 = icmp eq <2 x i64> %x, zeroinitializer
+  %sel = select i1 %y, <2 x i1> %cmp1, <2 x i1> %cmp2
+  ret <2 x i1> %sel
+}
+
 declare void @use(i1)

>From ac7ded456af70c1c10f64dac4b7093b41aa9eccd Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 26 Apr 2024 01:06:51 +0800
Subject: [PATCH 2/4] [InstCombine] Fold `select Cond, not X, X` into `Cond ^
 X`

---
 .../InstCombine/InstCombineSelect.cpp         |  5 +++++
 .../test/Transforms/InstCombine/select-cmp.ll | 20 ++++++++-----------
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 117eb7a1dcc93..69341c8d3f41c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3985,5 +3985,10 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
     }
   }
 
+  if (CondVal->getType() == SI.getType() && impliesPoison(FalseVal, TrueVal) &&
+      isImpliedCondition(FalseVal, TrueVal, DL, /*LHSIsTrue=*/true) == false &&
+      isImpliedCondition(FalseVal, TrueVal, DL, /*LHSIsTrue=*/false) == true)
+    return BinaryOperator::CreateXor(CondVal, FalseVal);
+
   return nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/select-cmp.ll b/llvm/test/Transforms/InstCombine/select-cmp.ll
index 1188ded2f807e..3ec89af8d868c 100644
--- a/llvm/test/Transforms/InstCombine/select-cmp.ll
+++ b/llvm/test/Transforms/InstCombine/select-cmp.ll
@@ -347,9 +347,8 @@ define i1 @icmp_no_common(i1 %c, i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_select_inverse1(i64 %x, i1 %y) {
 ; CHECK-LABEL: @test_select_inverse1(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i64 [[X:%.*]], 0
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i64 [[X]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i64 [[X:%.*]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = xor i1 [[CMP2]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[SEL]]
 ;
   %cmp1 = icmp ne i64 %x, 0
@@ -360,9 +359,8 @@ define i1 @test_select_inverse1(i64 %x, i1 %y) {
 
 define i1 @test_select_inverse2(i64 %x, i1 %y) {
 ; CHECK-LABEL: @test_select_inverse2(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i64 [[X:%.*]], -1
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[X]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[X:%.*]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = xor i1 [[CMP2]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[SEL]]
 ;
   %cmp1 = icmp sgt i64 %x, -1
@@ -373,9 +371,8 @@ define i1 @test_select_inverse2(i64 %x, i1 %y) {
 
 define i1 @test_select_inverse3(ptr %x, i1 %y) {
 ; CHECK-LABEL: @test_select_inverse3(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq ptr [[X:%.*]], null
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne ptr [[X]], null
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[Y:%.*]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne ptr [[X:%.*]], null
+; CHECK-NEXT:    [[SEL:%.*]] = xor i1 [[CMP2]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[SEL]]
 ;
   %cmp1 = icmp eq ptr %x, null
@@ -399,9 +396,8 @@ define i1 @test_select_inverse_fail(i64 %x, i1 %y) {
 
 define <2 x i1> @test_select_inverse_vec(<2 x i64> %x, <2 x i1> %y) {
 ; CHECK-LABEL: @test_select_inverse_vec(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i64> [[X:%.*]], zeroinitializer
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq <2 x i64> [[X]], zeroinitializer
-; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[Y:%.*]], <2 x i1> [[CMP1]], <2 x i1> [[CMP2]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq <2 x i64> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[SEL:%.*]] = xor <2 x i1> [[CMP2]], [[Y:%.*]]
 ; CHECK-NEXT:    ret <2 x i1> [[SEL]]
 ;
   %cmp1 = icmp ne <2 x i64> %x, zeroinitializer

>From d1e3e8168edba65885e33c5cb2b1c853a54c7ca4 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 13 May 2024 15:16:26 +0800
Subject: [PATCH 3/4] [InstCombine] Add a header comment for the fold. NFC.

---
 llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 69341c8d3f41c..884aed4f2327e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3985,6 +3985,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
     }
   }
 
+  // select Cond, !X, X -> xor Cond, X
   if (CondVal->getType() == SI.getType() && impliesPoison(FalseVal, TrueVal) &&
       isImpliedCondition(FalseVal, TrueVal, DL, /*LHSIsTrue=*/true) == false &&
       isImpliedCondition(FalseVal, TrueVal, DL, /*LHSIsTrue=*/false) == true)

>From 1731798e2ef457fb5cabd29ae054c700b8b13c14 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 17 May 2024 21:09:03 +0800
Subject: [PATCH 4/4] [InstCombine] Add some comments.

---
 llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 884aed4f2327e..41f9ac4869c75 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3986,6 +3986,8 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   }
 
   // select Cond, !X, X -> xor Cond, X
+  // Note: We don't fold select Cond, Y, X -> X (iff X->Y & !X->!Y) here as
+  // it indicates that these two patterns should be canonicalized.
   if (CondVal->getType() == SI.getType() && impliesPoison(FalseVal, TrueVal) &&
       isImpliedCondition(FalseVal, TrueVal, DL, /*LHSIsTrue=*/true) == false &&
       isImpliedCondition(FalseVal, TrueVal, DL, /*LHSIsTrue=*/false) == true)



More information about the llvm-commits mailing list