[llvm] [ValueTracking] Improve `isImpliedCondCommonOperandWithConstants` to handle truncated LHS (PR #69829)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 22 01:01:08 PDT 2023
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/69829
>From e175724e001bc068ee4aec1e47e9b8c996b58ea6 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 21 Oct 2023 17:31:48 +0800
Subject: [PATCH 1/3] [ValueTracking] Add pre-commit tests from PR68514. NFC.
---
llvm/test/Analysis/ValueTracking/pr68514.ll | 79 +++++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 llvm/test/Analysis/ValueTracking/pr68514.ll
diff --git a/llvm/test/Analysis/ValueTracking/pr68514.ll b/llvm/test/Analysis/ValueTracking/pr68514.ll
new file mode 100644
index 000000000000000..53c251ed2e88264
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/pr68514.ll
@@ -0,0 +1,79 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Tests from PR68514
+define i1 @f(i32 %a) {
+; CHECK-LABEL: define i1 @f(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
+; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i16 [[B]], 2
+; CHECK-NEXT: [[AND9:%.*]] = and i1 [[CMP]], [[CMP2]]
+; CHECK-NEXT: ret i1 [[AND9]]
+;
+entry:
+ %cmp = icmp eq i32 %a, 0
+ %b = trunc i32 %a to i16
+ %cmp2 = icmp sgt i16 %b, 2
+ %and9 = and i1 %cmp, %cmp2
+ ret i1 %and9
+}
+
+define i1 @g(i32 %a) {
+; CHECK-LABEL: define i1 @g(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 3
+; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i16 [[B]], 2
+; CHECK-NEXT: [[OR9:%.*]] = or i1 [[CMP]], [[CMP2]]
+; CHECK-NEXT: ret i1 [[OR9]]
+;
+entry:
+ %cmp = icmp eq i32 %a, 3
+ %b = trunc i32 %a to i16
+ %cmp2 = icmp sgt i16 %b, 2
+ %or9 = or i1 %cmp, %cmp2
+ ret i1 %or9
+}
+
+; b = trunc(a)
+
+define i1 @fold_trunc(i32 %a) {
+; CHECK-LABEL: define i1 @fold_trunc(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A]], 2
+; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i16 [[B]], 2
+; CHECK-NEXT: [[AND9:%.*]] = or i1 [[CMP]], [[CMP2]]
+; CHECK-NEXT: ret i1 [[AND9]]
+;
+entry:
+ %cmp = icmp ugt i32 %a, 2
+ %b = trunc i32 %a to i16
+ %cmp2 = icmp ugt i16 %b, 2
+ %and9 = or i1 %cmp, %cmp2
+ ret i1 %and9
+}
+
+; Negative tests
+
+define i1 @nofold_trunc(i32 %a) {
+; CHECK-LABEL: define i1 @nofold_trunc(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A]], 3
+; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i16 [[B]], 2
+; CHECK-NEXT: [[AND9:%.*]] = or i1 [[CMP]], [[CMP2]]
+; CHECK-NEXT: ret i1 [[AND9]]
+;
+entry:
+ %cmp = icmp ugt i32 %a, 3
+ %b = trunc i32 %a to i16
+ %cmp2 = icmp ugt i16 %b, 2
+ %and9 = or i1 %cmp, %cmp2
+ ret i1 %and9
+}
>From 33ee6056faf7e28408bff531ca87b03539353d4f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 21 Oct 2023 17:32:46 +0800
Subject: [PATCH 2/3] [ValueTracking] Improve
`isImpliedCondCommonOperandWithConstants` to handle truncated LHS
---
llvm/lib/Analysis/ValueTracking.cpp | 41 +++++++++++++++++----
llvm/test/Analysis/ValueTracking/pr68514.ll | 15 ++------
2 files changed, 37 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8824a05e3aa6ccd..188faf00329ece2 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8231,14 +8231,30 @@ isImpliedCondMatchingOperands(CmpInst::Predicate LPred,
return std::nullopt;
}
-/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
-/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
-/// Otherwise, return std::nullopt if we can't infer anything.
+/// Return true if "icmp LPred X, LC" implies "icmp RPred cast(X), RC" is true.
+/// Return false if "icmp LPred X, LC" implies "icmp RPred cast(X), RC" is
+/// false. Otherwise, return std::nullopt if we can't infer anything.
static std::optional<bool> isImpliedCondCommonOperandWithConstants(
- CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
- const APInt &RC) {
+ const Value *L0, CmpInst::Predicate LPred, const APInt &LC, const Value *R0,
+ CmpInst::Predicate RPred, const APInt &RC) {
ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
+
+ if (L0 == R0)
+ ; // noop
+ // Example: icmp eq X, 3 --> icmp sgt trunc(X), 2
+ else if (match(R0, m_Trunc(m_Specific(L0))))
+ DomCR = DomCR.truncate(RC.getBitWidth());
+ // Example: icmp slt trunc(X), 3 --> icmp ne X, 3
+ else if (match(L0, m_Trunc(m_Specific(R0)))) {
+ // Try to prove by negation
+ DomCR = DomCR.inverse();
+ CR = CR.inverse();
+ std::swap(DomCR, CR);
+ DomCR = DomCR.truncate(LC.getBitWidth());
+ } else
+ return std::nullopt;
+
ConstantRange Intersection = DomCR.intersectWith(CR);
ConstantRange Difference = DomCR.difference(CR);
if (Intersection.isEmptySet())
@@ -8272,8 +8288,19 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
// Can we infer anything when the 0-operands match and the 1-operands are
// constants (not necessarily matching)?
const APInt *LC, *RC;
- if (L0 == R0 && match(L1, m_APInt(LC)) && match(R1, m_APInt(RC)))
- return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC);
+ if (match(L1, m_APInt(LC)) && match(R1, m_APInt(RC))) {
+ if (auto Res = isImpliedCondCommonOperandWithConstants(L0, LPred, *LC, R0,
+ RPred, *RC))
+ return Res;
+
+ if (match(L0, m_Trunc(m_Specific(R0)))) {
+ // When L0 == trunc(R0), we use the law of excluded middle to cover some
+ // missing cases.
+ if (auto Res = isImpliedCondCommonOperandWithConstants(
+ L0, LPred, *LC, R0, ICmpInst::getInversePredicate(RPred), *RC))
+ return !*Res;
+ }
+ }
// L0 = R0 = L1 + R1, L0 >=u L1 implies R0 >=u R1, L0 <u L1 implies R0 <u R1
if (ICmpInst::isUnsigned(LPred) && ICmpInst::isUnsigned(RPred)) {
diff --git a/llvm/test/Analysis/ValueTracking/pr68514.ll b/llvm/test/Analysis/ValueTracking/pr68514.ll
index 53c251ed2e88264..482cad942624aaa 100644
--- a/llvm/test/Analysis/ValueTracking/pr68514.ll
+++ b/llvm/test/Analysis/ValueTracking/pr68514.ll
@@ -6,11 +6,7 @@ define i1 @f(i32 %a) {
; CHECK-LABEL: define i1 @f(
; CHECK-SAME: i32 [[A:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
-; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i16 [[B]], 2
-; CHECK-NEXT: [[AND9:%.*]] = and i1 [[CMP]], [[CMP2]]
-; CHECK-NEXT: ret i1 [[AND9]]
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp eq i32 %a, 0
@@ -24,11 +20,9 @@ define i1 @g(i32 %a) {
; CHECK-LABEL: define i1 @g(
; CHECK-SAME: i32 [[A:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 3
; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i16 [[B]], 2
-; CHECK-NEXT: [[OR9:%.*]] = or i1 [[CMP]], [[CMP2]]
-; CHECK-NEXT: ret i1 [[OR9]]
+; CHECK-NEXT: ret i1 [[CMP2]]
;
entry:
%cmp = icmp eq i32 %a, 3
@@ -45,10 +39,7 @@ define i1 @fold_trunc(i32 %a) {
; CHECK-SAME: i32 [[A:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A]], 2
-; CHECK-NEXT: [[B:%.*]] = trunc i32 [[A]] to i16
-; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i16 [[B]], 2
-; CHECK-NEXT: [[AND9:%.*]] = or i1 [[CMP]], [[CMP2]]
-; CHECK-NEXT: ret i1 [[AND9]]
+; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%cmp = icmp ugt i32 %a, 2
>From a860c657b765e4ad1983b86e1ba07a6817424868 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 22 Oct 2023 15:54:20 +0800
Subject: [PATCH 3/3] fixup! [ValueTracking] Improve
`isImpliedCondCommonOperandWithConstants` to handle truncated LHS
Fix AMDGPU tests. NFC.
---
.../CodeGen/AMDGPU/combine-reg-or-const.ll | 23 ++++++++-----------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/combine-reg-or-const.ll b/llvm/test/CodeGen/AMDGPU/combine-reg-or-const.ll
index 3a7100c5903ebb9..19f1ea06eba618f 100644
--- a/llvm/test/CodeGen/AMDGPU/combine-reg-or-const.ll
+++ b/llvm/test/CodeGen/AMDGPU/combine-reg-or-const.ll
@@ -11,23 +11,18 @@ define protected amdgpu_kernel void @_Z11test_kernelPii(ptr addrspace(1) nocaptu
; CHECK-NEXT: s_cbranch_scc1 .LBB0_2
; CHECK-NEXT: ; %bb.1: ; %if.then
; CHECK-NEXT: s_load_dwordx2 s[2:3], s[4:5], 0x0
-; CHECK-NEXT: s_and_b32 s4, s0, 0xffff
+; CHECK-NEXT: s_and_b32 s6, s0, 0xffff
; CHECK-NEXT: s_mov_b32 s1, 0
-; CHECK-NEXT: s_mul_i32 s6, s4, 0xaaab
; CHECK-NEXT: s_lshl_b64 s[4:5], s[0:1], 2
-; CHECK-NEXT: s_lshr_b32 s1, s6, 19
-; CHECK-NEXT: s_mul_i32 s1, s1, 12
-; CHECK-NEXT: s_sub_i32 s6, s0, s1
-; CHECK-NEXT: s_and_b32 s7, s6, 0xffff
; CHECK-NEXT: s_waitcnt lgkmcnt(0)
-; CHECK-NEXT: s_add_u32 s0, s2, s4
-; CHECK-NEXT: s_addc_u32 s1, s3, s5
-; CHECK-NEXT: s_bfe_u32 s2, s6, 0xd0003
-; CHECK-NEXT: s_add_i32 s2, s2, s7
-; CHECK-NEXT: s_or_b32 s2, s2, 0xc0
-; CHECK-NEXT: v_mov_b32_e32 v0, s0
-; CHECK-NEXT: v_mov_b32_e32 v1, s1
-; CHECK-NEXT: v_mov_b32_e32 v2, s2
+; CHECK-NEXT: s_add_u32 s2, s2, s4
+; CHECK-NEXT: s_addc_u32 s3, s3, s5
+; CHECK-NEXT: s_bfe_u32 s0, s0, 0xd0003
+; CHECK-NEXT: s_or_b32 s1, s6, 0xc0
+; CHECK-NEXT: s_add_i32 s0, s1, s0
+; CHECK-NEXT: v_mov_b32_e32 v0, s2
+; CHECK-NEXT: v_mov_b32_e32 v1, s3
+; CHECK-NEXT: v_mov_b32_e32 v2, s0
; CHECK-NEXT: flat_store_dword v[0:1], v2
; CHECK-NEXT: .LBB0_2: ; %if.end
; CHECK-NEXT: s_endpgm
More information about the llvm-commits
mailing list