[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