[llvm] [BDCE] Handle multi-use `and`/`or`/`xor` on demanded bits (PR #79688)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 29 10:03:50 PST 2024


https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/79688

>From 0a15ead01b6be095a87a405e63e9525ed123ac58 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Sat, 27 Jan 2024 19:19:51 +0100
Subject: [PATCH 1/2] [BDCE] Introduce test for PR79688 (NFC)

---
 llvm/test/Transforms/BDCE/binops-multiuse.ll | 282 +++++++++++++++++++
 1 file changed, 282 insertions(+)
 create mode 100644 llvm/test/Transforms/BDCE/binops-multiuse.ll

diff --git a/llvm/test/Transforms/BDCE/binops-multiuse.ll b/llvm/test/Transforms/BDCE/binops-multiuse.ll
new file mode 100644
index 000000000000000..bf1993bce2de74c
--- /dev/null
+++ b/llvm/test/Transforms/BDCE/binops-multiuse.ll
@@ -0,0 +1,282 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -S -passes=bdce < %s | FileCheck %s
+
+define void @or(i64 %a) {
+; CHECK-LABEL: define void @or(
+; CHECK-SAME: i64 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or i64 [[A]], 3
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[OR]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[OR]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %or = or i64 %a, 3                              ; Mask:          0000 0011
+  %ret1 = and i64 %or, 8                          ; Demanded bits: 0000 1000
+  %ret2 = and i64 %or, 16                         ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @xor(i64 %a) {
+; CHECK-LABEL: define void @xor(
+; CHECK-SAME: i64 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[XOR:%.*]] = xor i64 [[A]], 3
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[XOR]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[XOR]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %xor = xor i64 %a, 3                            ; Mask:          0000 0011
+  %ret1 = and i64 %xor, 8                         ; Demanded bits: 0000 1000
+  %ret2 = and i64 %xor, 16                        ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @and(i64 %a) {
+; CHECK-LABEL: define void @and(
+; CHECK-SAME: i64 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND:%.*]] = and i64 [[A]], 24
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[AND]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[AND]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and = and i64 %a, 24                           ; Mask:          0001 1000
+  %ret1 = and i64 %and, 8                         ; Demanded bits: 0000 1000
+  %ret2 = and i64 %and, 16                        ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @or_of_and(i64 %a, i64 %b) {
+; CHECK-LABEL: define void @or_of_and(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 24
+; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
+; CHECK-NEXT:    [[OR:%.*]] = or i64 [[AND1]], [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[OR]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[OR]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and i64 %a, 24                          ; Mask:          0001 1000
+  %and2 = and i64 %b, 25                          ; Mask:          0001 1001
+  %or = or i64 %and1, %and2
+  %ret1 = and i64 %or, 8                          ; Demanded bits: 0000 1000
+  %ret2 = and i64 %or, 16                         ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @or_disjoint_of_and(i64 %a, i64 %b) {
+; CHECK-LABEL: define void @or_disjoint_of_and(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 56
+; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i64 [[AND1]], [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[OR]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[OR]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and i64 %a, 56                          ; Mask:          0011 1000
+  %and2 = and i64 %b, 25                          ; Mask:          0001 1001
+  %or = or disjoint i64 %and1, %and2
+  %ret1 = and i64 %or, 8                          ; Demanded bits: 0000 1000
+  %ret2 = and i64 %or, 16                         ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @select_of_and(i1 %c, i64 %a, i64 %b) {
+; CHECK-LABEL: define void @select_of_and(
+; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 24
+; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and i64 %a, 24                          ; Mask:          0001 1000
+  %and2 = and i64 %b, 25                          ; Mask:          0001 1001
+  %s = select i1 %c, i64 %and1, i64 %and2
+  %ret1 = and i64 %s, 8                           ; Demanded bits: 0000 1000
+  %ret2 = and i64 %s, 16                          ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @select_of_and_2(i1 %c, i64 %a, i64 %b) {
+; CHECK-LABEL: define void @select_of_and_2(
+; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 25
+; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 23
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and i64 %a, 25                          ; Mask:          0001 1001
+  %and2 = and i64 %b, 23                          ; Mask:          0001 0111
+  %s = select i1 %c, i64 %and1, i64 %and2
+  %ret1 = and i64 %s, 8                           ; Demanded bits: 0000 1000
+  %ret2 = and i64 %s, 16                          ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @select_of_and_multiuse(i1 %c, i64 %a, i64 %b) {
+; CHECK-LABEL: define void @select_of_and_multiuse(
+; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 24
+; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use2(i64 [[RET2]], i64 [[AND2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and i64 %a, 24                          ; Mask:          0001 1000
+  %and2 = and i64 %b, 25                          ; Mask:          0001 1001
+  %s = select i1 %c, i64 %and1, i64 %and2
+  %ret1 = and i64 %s, 8                           ; Demanded bits: 0000 1000
+  %ret2 = and i64 %s, 16                          ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use2(i64 %ret2, i64 %and2)
+  ret void
+}
+
+define void @select_of_and_different_demanded(i1 %c, i64 %a, i64 %b) {
+; CHECK-LABEL: define void @select_of_and_different_demanded(
+; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and i64 0, 24
+; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 3
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 7
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and i64 %a, 24                          ; Mask:          0001 1000
+  %and2 = and i64 %b, 25                          ; Mask:          0001 1001
+  %s = select i1 %c, i64 %and1, i64 %and2
+  %ret1 = and i64 %s, 3                           ; Demanded bits: 0000 0011
+  %ret2 = and i64 %s, 7                           ; Demanded bits: 0000 0111
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @select_of_or(i1 %c, i64 %a, i64 %b) {
+; CHECK-LABEL: define void @select_of_or(
+; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR1:%.*]] = or i64 [[A]], 3
+; CHECK-NEXT:    [[OR2:%.*]] = or i64 [[B]], 192
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[OR1]], i64 [[OR2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %or1 = or i64 %a, 3                             ; Mask:          0000 0011
+  %or2 = or i64 %b, 192                           ; Mask:          1100 0000
+  %s = select i1 %c, i64 %or1, i64 %or2
+  %ret1 = and i64 %s, 8                           ; Demanded bits: 0000 1000
+  %ret2 = and i64 %s, 16                          ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @select_of_xor(i1 %c, i64 %a, i64 %b) {
+; CHECK-LABEL: define void @select_of_xor(
+; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[XOR1:%.*]] = xor i64 [[A]], 128
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i64 [[B]], 36
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[XOR1]], i64 [[XOR2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
+; CHECK-NEXT:    call void @use(i64 [[RET1]])
+; CHECK-NEXT:    call void @use(i64 [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %xor1 = xor i64 %a, 128                         ; Mask:          1000 0000
+  %xor2 = xor i64 %b, 36                          ; Mask:          0010 0100
+  %s = select i1 %c, i64 %xor1, i64 %xor2
+  %ret1 = and i64 %s, 8                           ; Demanded bits: 0000 1000
+  %ret2 = and i64 %s, 16                          ; Demanded bits: 0001 0000
+  call void @use(i64 %ret1)
+  call void @use(i64 %ret2)
+  ret void
+}
+
+define void @select_vectorized(i1 %c, <2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: define void @select_vectorized(
+; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i8> [[A]], <i8 28, i8 28>
+; CHECK-NEXT:    [[AND2:%.*]] = and <2 x i8> [[B]], <i8 29, i8 29>
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], <2 x i8> [[AND1]], <2 x i8> [[AND2]]
+; CHECK-NEXT:    [[RET1:%.*]] = and <2 x i8> [[S]], <i8 4, i8 4>
+; CHECK-NEXT:    [[RET2:%.*]] = and <2 x i8> [[S]], <i8 12, i8 12>
+; CHECK-NEXT:    call void @use3(<2 x i8> [[RET1]])
+; CHECK-NEXT:    call void @use3(<2 x i8> [[RET2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %and1 = and <2 x i8> %a, <i8 28, i8 28>
+  %and2 = and <2 x i8> %b, <i8 29, i8 29>
+  %s = select i1 %c, <2 x i8> %and1, <2 x i8> %and2
+  %ret1 = and <2 x i8> %s, <i8 4, i8 4>
+  %ret2 = and <2 x i8> %s, <i8 12, i8 12>
+  call void @use3(<2 x i8> %ret1)
+  call void @use3(<2 x i8> %ret2)
+  ret void
+}
+
+declare void @use(i64)
+declare void @use2(i64, i64)
+declare void @use3(<2 x i8>)

>From 20737825c9122b6e0a8912731cfa7e0558fe025d Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Sat, 27 Jan 2024 19:24:55 +0100
Subject: [PATCH 2/2] [BDCE] Handle multi-use binary ops upon demanded bits

Simplify multi-use `and`/`or`/`xor` when these last
do not affect the demanded bits being considered.

Fixes: https://github.com/llvm/llvm-project/issues/78596.

Proofs: https://alive2.llvm.org/ce/z/EjuWHa.
---
 llvm/lib/Transforms/Scalar/BDCE.cpp          | 35 +++++++++++++++
 llvm/test/Transforms/BDCE/binops-multiuse.ll | 45 ++++++--------------
 llvm/test/Transforms/BDCE/dead-uses.ll       |  8 ++--
 3 files changed, 53 insertions(+), 35 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/BDCE.cpp b/llvm/lib/Transforms/Scalar/BDCE.cpp
index 1fa2c75b0f42ac1..e99210ce2f2285a 100644
--- a/llvm/lib/Transforms/Scalar/BDCE.cpp
+++ b/llvm/lib/Transforms/Scalar/BDCE.cpp
@@ -23,10 +23,13 @@
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/Utils/Local.h"
+
 using namespace llvm;
+using namespace PatternMatch;
 
 #define DEBUG_TYPE "bdce"
 
@@ -125,6 +128,38 @@ static bool bitTrackingDCE(Function &F, DemandedBits &DB) {
       }
     }
 
+    // Simplify and, or, xor when their mask does not affect the demanded bits.
+    if (auto *BO = dyn_cast<BinaryOperator>(&I)) {
+      APInt Demanded = DB.getDemandedBits(BO);
+      if (!Demanded.isAllOnes()) {
+        const APInt *Mask;
+        if (match(BO->getOperand(1), m_APInt(Mask))) {
+          bool CanBeSimplified = false;
+          switch (BO->getOpcode()) {
+          case Instruction::Or:
+          case Instruction::Xor:
+            CanBeSimplified = !Demanded.intersects(*Mask);
+            break;
+          case Instruction::And:
+            CanBeSimplified = Demanded.isSubsetOf(*Mask);
+            break;
+          default:
+            // TODO: Handle more cases here.
+            break;
+          }
+
+          if (CanBeSimplified) {
+            clearAssumptionsOfUsers(BO, DB);
+            BO->replaceAllUsesWith(BO->getOperand(0));
+            Worklist.push_back(BO);
+            ++NumSimplified;
+            Changed = true;
+            continue;
+          }
+        }
+      }
+    }
+
     for (Use &U : I.operands()) {
       // DemandedBits only detects dead integer uses.
       if (!U->getType()->isIntOrIntVectorTy())
diff --git a/llvm/test/Transforms/BDCE/binops-multiuse.ll b/llvm/test/Transforms/BDCE/binops-multiuse.ll
index bf1993bce2de74c..0c03ca4d6fc57e4 100644
--- a/llvm/test/Transforms/BDCE/binops-multiuse.ll
+++ b/llvm/test/Transforms/BDCE/binops-multiuse.ll
@@ -5,9 +5,8 @@ define void @or(i64 %a) {
 ; CHECK-LABEL: define void @or(
 ; CHECK-SAME: i64 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR:%.*]] = or i64 [[A]], 3
-; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[OR]], 8
-; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[OR]], 16
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[A]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[A]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
 ; CHECK-NEXT:    call void @use(i64 [[RET2]])
 ; CHECK-NEXT:    ret void
@@ -25,9 +24,8 @@ define void @xor(i64 %a) {
 ; CHECK-LABEL: define void @xor(
 ; CHECK-SAME: i64 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[XOR:%.*]] = xor i64 [[A]], 3
-; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[XOR]], 8
-; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[XOR]], 16
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[A]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[A]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
 ; CHECK-NEXT:    call void @use(i64 [[RET2]])
 ; CHECK-NEXT:    ret void
@@ -45,9 +43,8 @@ define void @and(i64 %a) {
 ; CHECK-LABEL: define void @and(
 ; CHECK-SAME: i64 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND:%.*]] = and i64 [[A]], 24
-; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[AND]], 8
-; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[AND]], 16
+; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[A]], 8
+; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[A]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
 ; CHECK-NEXT:    call void @use(i64 [[RET2]])
 ; CHECK-NEXT:    ret void
@@ -65,9 +62,7 @@ define void @or_of_and(i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @or_of_and(
 ; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 24
-; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
-; CHECK-NEXT:    [[OR:%.*]] = or i64 [[AND1]], [[AND2]]
+; CHECK-NEXT:    [[OR:%.*]] = or i64 [[A]], [[B]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[OR]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[OR]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -89,9 +84,7 @@ define void @or_disjoint_of_and(i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @or_disjoint_of_and(
 ; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 56
-; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i64 [[AND1]], [[AND2]]
+; CHECK-NEXT:    [[OR:%.*]] = or i64 [[A]], [[B]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[OR]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[OR]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -113,9 +106,7 @@ define void @select_of_and(i1 %c, i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @select_of_and(
 ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 24
-; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[B]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -137,9 +128,8 @@ define void @select_of_and_2(i1 %c, i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @select_of_and_2(
 ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 25
 ; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 23
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[AND2]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -161,9 +151,8 @@ define void @select_of_and_multiuse(i1 %c, i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @select_of_and_multiuse(
 ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and i64 [[A]], 24
 ; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[B]], 25
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[AND1]], i64 [[AND2]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[AND2]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -209,9 +198,7 @@ define void @select_of_or(i1 %c, i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @select_of_or(
 ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR1:%.*]] = or i64 [[A]], 3
-; CHECK-NEXT:    [[OR2:%.*]] = or i64 [[B]], 192
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[OR1]], i64 [[OR2]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[B]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -233,9 +220,7 @@ define void @select_of_xor(i1 %c, i64 %a, i64 %b) {
 ; CHECK-LABEL: define void @select_of_xor(
 ; CHECK-SAME: i1 [[C:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[XOR1:%.*]] = xor i64 [[A]], 128
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i64 [[B]], 36
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[XOR1]], i64 [[XOR2]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], i64 [[A]], i64 [[B]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and i64 [[S]], 8
 ; CHECK-NEXT:    [[RET2:%.*]] = and i64 [[S]], 16
 ; CHECK-NEXT:    call void @use(i64 [[RET1]])
@@ -257,9 +242,7 @@ define void @select_vectorized(i1 %c, <2 x i8> %a, <2 x i8> %b) {
 ; CHECK-LABEL: define void @select_vectorized(
 ; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND1:%.*]] = and <2 x i8> [[A]], <i8 28, i8 28>
-; CHECK-NEXT:    [[AND2:%.*]] = and <2 x i8> [[B]], <i8 29, i8 29>
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], <2 x i8> [[AND1]], <2 x i8> [[AND2]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], <2 x i8> [[A]], <2 x i8> [[B]]
 ; CHECK-NEXT:    [[RET1:%.*]] = and <2 x i8> [[S]], <i8 4, i8 4>
 ; CHECK-NEXT:    [[RET2:%.*]] = and <2 x i8> [[S]], <i8 12, i8 12>
 ; CHECK-NEXT:    call void @use3(<2 x i8> [[RET1]])
diff --git a/llvm/test/Transforms/BDCE/dead-uses.ll b/llvm/test/Transforms/BDCE/dead-uses.ll
index 1a19ff6fb11d5e6..85ee0dd8f2b9048 100644
--- a/llvm/test/Transforms/BDCE/dead-uses.ll
+++ b/llvm/test/Transforms/BDCE/dead-uses.ll
@@ -9,14 +9,14 @@ declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>)
 ; First fshr operand is dead.
 define i32 @pr39771_fshr_multi_use_instr(i32 %a) {
 ; CHECK-LABEL: @pr39771_fshr_multi_use_instr(
-; CHECK-NEXT:    [[X:%.*]] = or i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[X:%.*]] = or i32 [[A:%.*]], 2
 ; CHECK-NEXT:    [[B:%.*]] = tail call i32 @llvm.fshr.i32(i32 0, i32 [[X]], i32 1)
 ; CHECK-NEXT:    [[C:%.*]] = lshr i32 [[B]], 23
 ; CHECK-NEXT:    [[D:%.*]] = xor i32 [[C]], [[B]]
 ; CHECK-NEXT:    [[E:%.*]] = and i32 [[D]], 31
 ; CHECK-NEXT:    ret i32 [[E]]
 ;
-  %x = or i32 %a, 0
+  %x = or i32 %a, 2
   %b = tail call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 1)
   %c = lshr i32 %b, 23
   %d = xor i32 %c, %b
@@ -27,14 +27,14 @@ define i32 @pr39771_fshr_multi_use_instr(i32 %a) {
 ; First fshr operand is dead (vector variant).
 define <2 x i32> @pr39771_fshr_multi_use_instr_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @pr39771_fshr_multi_use_instr_vec(
-; CHECK-NEXT:    [[X:%.*]] = or <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[X:%.*]] = or <2 x i32> [[A:%.*]], <i32 2, i32 2>
 ; CHECK-NEXT:    [[B:%.*]] = tail call <2 x i32> @llvm.fshr.v2i32(<2 x i32> zeroinitializer, <2 x i32> [[X]], <2 x i32> <i32 1, i32 1>)
 ; CHECK-NEXT:    [[C:%.*]] = lshr <2 x i32> [[B]], <i32 23, i32 23>
 ; CHECK-NEXT:    [[D:%.*]] = xor <2 x i32> [[C]], [[B]]
 ; CHECK-NEXT:    [[E:%.*]] = and <2 x i32> [[D]], <i32 31, i32 31>
 ; CHECK-NEXT:    ret <2 x i32> [[E]]
 ;
-  %x = or <2 x i32> %a, zeroinitializer
+  %x = or <2 x i32> %a, <i32 2, i32 2>
   %b = tail call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %x, <2 x i32> <i32 1, i32 1>)
   %c = lshr <2 x i32> %b, <i32 23, i32 23>
   %d = xor <2 x i32> %c, %b



More information about the llvm-commits mailing list