[llvm] [InstCombine] Add support for cast instructions in `getFreelyInvertedImpl` (PR #82451)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 22 07:41:08 PST 2024


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

>From 130148121d77a5d50080b3f4819308d77a5b0a62 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 22 Feb 2024 23:36:04 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.

---
 llvm/test/Transforms/InstCombine/not.ll | 98 +++++++++++++++++++++++++
 1 file changed, 98 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll
index 3b0e5b4412fbec..cde1a6f551ec71 100644
--- a/llvm/test/Transforms/InstCombine/not.ll
+++ b/llvm/test/Transforms/InstCombine/not.ll
@@ -769,3 +769,101 @@ entry:
   %cmp = icmp sle i32 %select, %not.c
   ret i1 %cmp
 }
+
+define i32 @test_sext(i32 %a, i32 %b){
+; CHECK-LABEL: @test_sext(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[SEXT:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEXT]], [[B:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[ADD]], -1
+; CHECK-NEXT:    ret i32 [[NOT]]
+;
+  %cmp = icmp eq i32 %a, 0
+  %sext = sext i1 %cmp to i32
+  %add = add i32 %b, %sext
+  %not = xor i32 %add, -1
+  ret i32 %not
+}
+
+define <2 x i32> @test_sext_vec(<2 x i32> %a, <2 x i32> %b){
+; CHECK-LABEL: @test_sext_vec(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[SEXT]], [[B:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i32> [[ADD]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[NOT]]
+;
+  %cmp = icmp eq <2 x i32> %a, zeroinitializer
+  %sext = sext <2 x i1> %cmp to <2 x i32>
+  %add = add <2 x i32> %b, %sext
+  %not = xor <2 x i32> %add, <i32 -1, i32 -1>
+  ret <2 x i32> %not
+}
+
+define i64 @test_zext_nneg(i32 %c1, i64 %c2, i64 %c3){
+; CHECK-LABEL: @test_zext_nneg(
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[C1:%.*]], -1
+; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i32 [[NOT]] to i64
+; CHECK-NEXT:    [[ADD1:%.*]] = add i64 [[C2:%.*]], -5
+; CHECK-NEXT:    [[ADD2:%.*]] = add i64 [[CONV]], [[C3:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[ADD1]], [[ADD2]]
+; CHECK-NEXT:    ret i64 [[SUB]]
+;
+  %not = xor i32 %c1, -1
+  %conv = zext nneg i32 %not to i64
+  %add1 = add i64 %c2, -5
+  %add2 = add i64 %conv, %c3
+  %sub = sub i64 %add1, %add2
+  ret i64 %sub
+}
+
+define i8 @test_trunc(i8 %a){
+; CHECK-LABEL: @test_trunc(
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[SHR:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[SHR]] to i8
+; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[CONV]], -1
+; CHECK-NEXT:    ret i8 [[NOT]]
+;
+  %zext = zext i8 %a to i32
+  %sub = add nsw i32 %zext, -1
+  %shr = ashr i32 %sub, 31
+  %conv = trunc i32 %shr to i8
+  %not = xor i8 %conv, -1
+  ret i8 %not
+}
+
+define <2 x i8> @test_trunc_vec(<2 x i8> %a){
+; CHECK-LABEL: @test_trunc_vec(
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i32> [[ZEXT]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[SHR:%.*]] = ashr <2 x i32> [[SUB]], <i32 31, i32 31>
+; CHECK-NEXT:    [[CONV:%.*]] = trunc <2 x i32> [[SHR]] to <2 x i8>
+; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i8> [[CONV]], <i8 -1, i8 -1>
+; CHECK-NEXT:    ret <2 x i8> [[NOT]]
+;
+  %zext = zext <2 x i8> %a to <2 x i32>
+  %sub = add nsw <2 x i32> %zext, <i32 -1, i32 -1>
+  %shr = ashr <2 x i32> %sub, <i32 31, i32 31>
+  %conv = trunc <2 x i32> %shr to <2 x i8>
+  %not = xor <2 x i8> %conv, <i8 -1, i8 -1>
+  ret <2 x i8> %not
+}
+
+; Negative tests
+
+define i32 @test_zext(i32 %a, i32 %b){
+; CHECK-LABEL: @test_zext(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[SEXT:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEXT]], [[B:%.*]]
+; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[ADD]], -1
+; CHECK-NEXT:    ret i32 [[NOT]]
+;
+  %cmp = icmp eq i32 %a, 0
+  %sext = zext i1 %cmp to i32
+  %add = add i32 %b, %sext
+  %not = xor i32 %add, -1
+  ret i32 %not
+}

>From 746360830ce948f5f2434abe046ff4f95731f5a7 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 22 Feb 2024 23:37:14 +0800
Subject: [PATCH 2/2] [InstCombine] Add support for cast instructions in
 `getFreelyInvertedImpl`

---
 .../InstCombine/InstructionCombining.cpp      | 14 +++++++
 llvm/test/Transforms/InstCombine/not.ll       | 37 +++++++------------
 2 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 4af455c37c788c..87c8dca7efed89 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2387,6 +2387,20 @@ Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
     return NonNull;
   }
 
+  if (match(V, m_SExtLike(m_Value(A)))) {
+    if (auto *AV = getFreelyInvertedImpl(A, A->hasOneUse(), Builder,
+                                         DoesConsume, Depth))
+      return Builder ? Builder->CreateSExt(AV, V->getType()) : NonNull;
+    return nullptr;
+  }
+
+  if (match(V, m_Trunc(m_Value(A)))) {
+    if (auto *AV = getFreelyInvertedImpl(A, A->hasOneUse(), Builder,
+                                         DoesConsume, Depth))
+      return Builder ? Builder->CreateTrunc(AV, V->getType()) : NonNull;
+    return nullptr;
+  }
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll
index cde1a6f551ec71..f277d13eee930c 100644
--- a/llvm/test/Transforms/InstCombine/not.ll
+++ b/llvm/test/Transforms/InstCombine/not.ll
@@ -772,10 +772,9 @@ entry:
 
 define i32 @test_sext(i32 %a, i32 %b){
 ; CHECK-LABEL: @test_sext(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[SEXT:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEXT]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[ADD]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i1 [[TMP1]] to i32
+; CHECK-NEXT:    [[NOT:%.*]] = sub i32 [[TMP2]], [[B:%.*]]
 ; CHECK-NEXT:    ret i32 [[NOT]]
 ;
   %cmp = icmp eq i32 %a, 0
@@ -787,10 +786,9 @@ define i32 @test_sext(i32 %a, i32 %b){
 
 define <2 x i32> @test_sext_vec(<2 x i32> %a, <2 x i32> %b){
 ; CHECK-LABEL: @test_sext_vec(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT:    [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[SEXT]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i32> [[ADD]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    [[NOT:%.*]] = sub <2 x i32> [[TMP2]], [[B:%.*]]
 ; CHECK-NEXT:    ret <2 x i32> [[NOT]]
 ;
   %cmp = icmp eq <2 x i32> %a, zeroinitializer
@@ -802,11 +800,10 @@ define <2 x i32> @test_sext_vec(<2 x i32> %a, <2 x i32> %b){
 
 define i64 @test_zext_nneg(i32 %c1, i64 %c2, i64 %c3){
 ; CHECK-LABEL: @test_zext_nneg(
-; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[C1:%.*]], -1
-; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i32 [[NOT]] to i64
-; CHECK-NEXT:    [[ADD1:%.*]] = add i64 [[C2:%.*]], -5
-; CHECK-NEXT:    [[ADD2:%.*]] = add i64 [[CONV]], [[C3:%.*]]
-; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[ADD1]], [[ADD2]]
+; CHECK-NEXT:    [[DOTNEG:%.*]] = add i64 [[C2:%.*]], -4
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[C1:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 [[TMP1]], [[C3:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = add i64 [[DOTNEG]], [[TMP2]]
 ; CHECK-NEXT:    ret i64 [[SUB]]
 ;
   %not = xor i32 %c1, -1
@@ -819,11 +816,8 @@ define i64 @test_zext_nneg(i32 %c1, i64 %c2, i64 %c3){
 
 define i8 @test_trunc(i8 %a){
 ; CHECK-LABEL: @test_trunc(
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[A:%.*]] to i32
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[SHR:%.*]] = ashr i32 [[SUB]], 31
-; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[SHR]] to i8
-; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[CONV]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], 0
+; CHECK-NEXT:    [[NOT:%.*]] = sext i1 [[TMP1]] to i8
 ; CHECK-NEXT:    ret i8 [[NOT]]
 ;
   %zext = zext i8 %a to i32
@@ -836,11 +830,8 @@ define i8 @test_trunc(i8 %a){
 
 define <2 x i8> @test_trunc_vec(<2 x i8> %a){
 ; CHECK-LABEL: @test_trunc_vec(
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i32> [[ZEXT]], <i32 -1, i32 -1>
-; CHECK-NEXT:    [[SHR:%.*]] = ashr <2 x i32> [[SUB]], <i32 31, i32 31>
-; CHECK-NEXT:    [[CONV:%.*]] = trunc <2 x i32> [[SHR]] to <2 x i8>
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i8> [[CONV]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <2 x i8> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[NOT:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
 ; CHECK-NEXT:    ret <2 x i8> [[NOT]]
 ;
   %zext = zext <2 x i8> %a to <2 x i32>



More information about the llvm-commits mailing list