[llvm] [ValueTracking] Handle `not` in `isImpliedCondition` (PR #85397)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 15 06:23:42 PDT 2024
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/85397
This patch handles `not` in `isImpliedCondition` to enable more fold in some multi-use cases.
>From ff55eba05dc9e0c19d29dc0b34982e8f866fb664 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 15 Mar 2024 20:59:52 +0800
Subject: [PATCH 1/2] [ValueTracking] Add pre-commit tests. NFC.
---
.../InstCombine/and-or-implied-cond-not.ll | 75 +++++++++++++++++++
1 file changed, 75 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
diff --git a/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll b/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
new file mode 100644
index 00000000000000..e583b072edc5c7
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
@@ -0,0 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @test_imply_not1(i32 %depth) {
+; CHECK-LABEL: define i1 @test_imply_not1(
+; CHECK-SAME: i32 [[DEPTH:%.*]]) {
+; CHECK-NEXT: [[CMP1_NOT1:%.*]] = icmp eq i32 [[DEPTH]], 16
+; CHECK-NEXT: call void @use(i1 [[CMP1_NOT1]])
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[DEPTH]], 8
+; CHECK-NEXT: call void @use(i1 [[CMP2]])
+; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP1_NOT1]], true
+; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[CMP2]], [[CMP_NOT]]
+; CHECK-NEXT: br i1 [[BRMERGE]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: call void @func1()
+; CHECK-NEXT: unreachable
+; CHECK: if.else:
+; CHECK-NEXT: call void @func2()
+; CHECK-NEXT: unreachable
+;
+ %cmp1 = icmp eq i32 %depth, 16
+ call void @use(i1 %cmp1)
+ %cmp2 = icmp slt i32 %depth, 8
+ call void @use(i1 %cmp2)
+ %cmp.not = xor i1 %cmp1, true
+ %brmerge = or i1 %cmp2, %cmp.not
+ br i1 %brmerge, label %if.then, label %if.else
+if.then:
+ call void @func1()
+ unreachable
+
+if.else:
+ call void @func2()
+ unreachable
+}
+
+define i1 @test_imply_not2(i32 %a, i1 %cmp2) {
+; CHECK-LABEL: define i1 @test_imply_not2(
+; CHECK-SAME: i32 [[A:%.*]], i1 [[CMP2:%.*]]) {
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], 0
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
+; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP1]], true
+; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[OR_COND]], [[CMP_NOT]]
+; CHECK-NEXT: ret i1 [[BRMERGE]]
+;
+ %cmp1 = icmp eq i32 %a, 0
+ %or.cond = select i1 %cmp1, i1 %cmp2, i1 false
+ %cmp.not = xor i1 %cmp1, true
+ %brmerge = or i1 %or.cond, %cmp.not
+ ret i1 %brmerge
+}
+
+define i1 @test_imply_not3(i32 %a, i32 %b, i1 %cond) {
+; CHECK-LABEL: define i1 @test_imply_not3(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i1 [[CMP1]])
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP1]], true
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP_NOT]], i1 [[COND]], i1 false
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP2]], [[SEL]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %cmp1 = icmp eq i32 %a, %b
+ call void @use(i1 %cmp1)
+ %cmp2 = icmp slt i32 %a, %b
+ %cmp.not = xor i1 %cmp1, true
+ %sel = select i1 %cmp.not, i1 %cond, i1 false
+ %and = and i1 %cmp2, %sel
+ ret i1 %and
+}
+
+declare void @func1()
+declare void @func2()
+declare void @use(i1)
>From 0cc2a01e3b4730beb1e3fb279a38245e3a8c03fe Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 15 Mar 2024 21:01:00 +0800
Subject: [PATCH 2/2] [ValueTracking] Handle not in `isImpliedCondition`
---
llvm/lib/Analysis/ValueTracking.cpp | 31 ++++++++++++++-----
.../InstCombine/and-or-implied-cond-not.ll | 14 +++------
.../LoopVectorize/reduction-inloop.ll | 3 +-
3 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index edbeede910d7f7..9aa6886ac02b09 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8622,6 +8622,10 @@ llvm::isImpliedCondition(const Value *LHS, CmpInst::Predicate RHSPred,
assert(LHS->getType()->isIntOrIntVectorTy(1) &&
"Expected integer type only!");
+ // Match not
+ if (match(LHS, m_Not(m_Value(LHS))))
+ LHSIsTrue = !LHSIsTrue;
+
// Both LHS and RHS are icmps.
const ICmpInst *LHSCmp = dyn_cast<ICmpInst>(LHS);
if (LHSCmp)
@@ -8648,10 +8652,21 @@ std::optional<bool> llvm::isImpliedCondition(const Value *LHS, const Value *RHS,
if (LHS == RHS)
return LHSIsTrue;
- if (const ICmpInst *RHSCmp = dyn_cast<ICmpInst>(RHS))
- return isImpliedCondition(LHS, RHSCmp->getPredicate(),
- RHSCmp->getOperand(0), RHSCmp->getOperand(1), DL,
- LHSIsTrue, Depth);
+ // Match not
+ bool InvertRHS = false;
+ if (match(RHS, m_Not(m_Value(RHS)))) {
+ if (LHS == RHS)
+ return !LHSIsTrue;
+ InvertRHS = true;
+ }
+
+ if (const ICmpInst *RHSCmp = dyn_cast<ICmpInst>(RHS)) {
+ if (auto Implied = isImpliedCondition(
+ LHS, RHSCmp->getPredicate(), RHSCmp->getOperand(0),
+ RHSCmp->getOperand(1), DL, LHSIsTrue, Depth))
+ return InvertRHS ? !*Implied : *Implied;
+ return std::nullopt;
+ }
if (Depth == MaxAnalysisRecursionDepth)
return std::nullopt;
@@ -8663,21 +8678,21 @@ std::optional<bool> llvm::isImpliedCondition(const Value *LHS, const Value *RHS,
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS1, DL, LHSIsTrue, Depth + 1))
if (*Imp == true)
- return true;
+ return !InvertRHS;
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS2, DL, LHSIsTrue, Depth + 1))
if (*Imp == true)
- return true;
+ return !InvertRHS;
}
if (match(RHS, m_LogicalAnd(m_Value(RHS1), m_Value(RHS2)))) {
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS1, DL, LHSIsTrue, Depth + 1))
if (*Imp == false)
- return false;
+ return InvertRHS;
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS2, DL, LHSIsTrue, Depth + 1))
if (*Imp == false)
- return false;
+ return InvertRHS;
}
return std::nullopt;
diff --git a/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll b/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
index e583b072edc5c7..89b3164018ac9a 100644
--- a/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
@@ -8,9 +8,7 @@ define i1 @test_imply_not1(i32 %depth) {
; CHECK-NEXT: call void @use(i1 [[CMP1_NOT1]])
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[DEPTH]], 8
; CHECK-NEXT: call void @use(i1 [[CMP2]])
-; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP1_NOT1]], true
-; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[CMP2]], [[CMP_NOT]]
-; CHECK-NEXT: br i1 [[BRMERGE]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK-NEXT: br i1 [[CMP1_NOT1]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @func1()
; CHECK-NEXT: unreachable
@@ -37,10 +35,8 @@ if.else:
define i1 @test_imply_not2(i32 %a, i1 %cmp2) {
; CHECK-LABEL: define i1 @test_imply_not2(
; CHECK-SAME: i32 [[A:%.*]], i1 [[CMP2:%.*]]) {
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
-; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP1]], true
-; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[OR_COND]], [[CMP_NOT]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[BRMERGE:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: ret i1 [[BRMERGE]]
;
%cmp1 = icmp eq i32 %a, 0
@@ -56,9 +52,7 @@ define i1 @test_imply_not3(i32 %a, i32 %b, i1 %cond) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[B]]
; CHECK-NEXT: call void @use(i1 [[CMP1]])
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP1]], true
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP_NOT]], i1 [[COND]], i1 false
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP2]], [[SEL]]
+; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP2]], i1 [[COND]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp1 = icmp eq i32 %a, %b
diff --git a/llvm/test/Transforms/LoopVectorize/reduction-inloop.ll b/llvm/test/Transforms/LoopVectorize/reduction-inloop.ll
index d85241167d0cd8..cd2161d279dec1 100644
--- a/llvm/test/Transforms/LoopVectorize/reduction-inloop.ll
+++ b/llvm/test/Transforms/LoopVectorize/reduction-inloop.ll
@@ -1354,9 +1354,8 @@ define i32 @predicated_or_dominates_reduction(ptr %b) {
; CHECK: pred.load.continue6:
; CHECK-NEXT: [[TMP43:%.*]] = phi <4 x i32> [ [[TMP37]], [[PRED_LOAD_CONTINUE4]] ], [ [[TMP42]], [[PRED_LOAD_IF5]] ]
; CHECK-NEXT: [[TMP44:%.*]] = icmp ne <4 x i32> [[TMP43]], zeroinitializer
-; CHECK-NEXT: [[TMP45:%.*]] = select <4 x i1> [[TMP19]], <4 x i1> [[TMP44]], <4 x i1> zeroinitializer
; CHECK-NEXT: [[TMP46:%.*]] = xor <4 x i1> [[TMP19]], <i1 true, i1 true, i1 true, i1 true>
-; CHECK-NEXT: [[TMP47:%.*]] = or <4 x i1> [[TMP45]], [[TMP46]]
+; CHECK-NEXT: [[TMP47:%.*]] = select <4 x i1> [[TMP46]], <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i1> [[TMP44]]
; CHECK-NEXT: [[TMP48:%.*]] = bitcast <4 x i1> [[TMP47]] to i4
; CHECK-NEXT: [[TMP49:%.*]] = call i4 @llvm.ctpop.i4(i4 [[TMP48]]), !range [[RNG42:![0-9]+]]
; CHECK-NEXT: [[TMP50:%.*]] = zext nneg i4 [[TMP49]] to i32
More information about the llvm-commits
mailing list