[llvm] [GlobalISel] Add G_SUB for computeNumSignBits (PR #158384)

Yatao Wang via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 16 11:25:29 PDT 2025


https://github.com/ningxinr updated https://github.com/llvm/llvm-project/pull/158384

>From 21a88d95001c653eebb0e956687953c437935eab Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Fri, 12 Sep 2025 12:05:03 -0700
Subject: [PATCH 1/7] Add tests for ISel and GlobalISel Sub

---
 .../AArch64/GlobalISel/knownbits-sub.mir      | 234 ++++++++++++++++++
 .../AArch64/AArch64SelectionDAGTest.cpp       |  45 ++++
 2 files changed, 279 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
new file mode 100644
index 0000000000000..8051bd2d17812
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
@@ -0,0 +1,234 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple aarch64 -passes="print<gisel-value-tracking>" %s -o - 2>&1 | FileCheck %s
+
+---
+name:            Cst
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Cst
+  ; CHECK-NEXT: %0:_ KnownBits:00000010 SignBits:6
+  ; CHECK-NEXT: %1:_ KnownBits:11100000 SignBits:3
+  ; CHECK-NEXT: %2:_ KnownBits:00100010 SignBits:2
+    %0:_(s8) = G_CONSTANT i8 2
+    %1:_(s8) = G_CONSTANT i8 224
+    %2:_(s8) = G_SUB %0, %1
+...
+---
+name:            CstZero
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @CstZero
+  ; CHECK-NEXT: %0:_ KnownBits:00000000 SignBits:8
+  ; CHECK-NEXT: %1:_ KnownBits:00000000 SignBits:8
+  ; CHECK-NEXT: %2:_ KnownBits:00000000 SignBits:8
+    %0:_(s8) = G_CONSTANT i8 0
+    %1:_(s8) = G_CONSTANT i8 0
+    %2:_(s8) = G_SUB %0, %1
+...
+---
+name:            CstNegOne
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @CstNegOne
+  ; CHECK-NEXT: %0:_ KnownBits:00000000 SignBits:8
+  ; CHECK-NEXT: %1:_ KnownBits:00000001 SignBits:7
+  ; CHECK-NEXT: %2:_ KnownBits:11111111 SignBits:8
+    %0:_(s8) = G_CONSTANT i8 0
+    %1:_(s8) = G_CONSTANT i8 1
+    %2:_(s8) = G_SUB %0, %1
+...
+---
+name:            CstNeg
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @CstNeg
+  ; CHECK-NEXT: %0:_ KnownBits:11100000 SignBits:3
+  ; CHECK-NEXT: %1:_ KnownBits:00000010 SignBits:6
+  ; CHECK-NEXT: %2:_ KnownBits:11011110 SignBits:2
+    %0:_(s8) = G_CONSTANT i8 224
+    %1:_(s8) = G_CONSTANT i8 2
+    %2:_(s8) = G_SUB %0, %1
+...
+---
+name:            ScalarVar
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @ScalarVar
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
+    %0:_(s8) = COPY $b0
+    %1:_(s8) = COPY $b1
+    %2:_(s8) = G_SUB %0, %1
+...
+---
+name:            ScalarRhsEarlyOut
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @ScalarRhsEarlyOut
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:00000011 SignBits:6
+  ; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
+    %0:_(s8) = COPY $b0
+    %1:_(s8) = G_CONSTANT i8 3
+    %2:_(s8) = G_SUB %0, %1
+...
+---
+name:            ScalarNonNegative
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @ScalarNonNegative
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
+  ; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
+  ; CHECK-NEXT: %3:_ KnownBits:00000000 SignBits:8
+  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:1
+    %0:_(s8) = COPY $b0
+    %1:_(s8) = G_CONSTANT i8 15
+    %2:_(s8) = G_AND %0, %1
+    %3:_(s8) = G_CONSTANT i8 0
+    %4:_(s8) = G_SUB %3, %2
+...
+---
+name:            ScalarLhsEarlyOut
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @ScalarLhsEarlyOut
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:00000011 SignBits:6
+  ; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
+    %0:_(s8) = COPY $b0
+    %1:_(s8) = G_CONSTANT i8 3
+    %2:_(s8) = G_SUB %1, %0
+...
+---
+name:            ScalarPartKnown
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @ScalarPartKnown
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
+  ; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
+  ; CHECK-NEXT: %3:_ KnownBits:00000101 SignBits:5
+  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:1
+    %0:_(s8) = COPY $b0
+    %1:_(s8) = G_CONSTANT i8 15
+    %2:_(s8) = G_AND %0, %1
+    %3:_(s8) = G_CONSTANT i8 5
+    %4:_(s8) = G_SUB %2, %3
+...
+---
+name:            VectorVar
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorVar
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:1
+    %0:_(<4 x s16>) = COPY $d0
+    %1:_(<4 x s16>) = COPY $d1
+    %2:_(<4 x s16>) = G_SUB %0, %1
+...
+---
+name:            VectorRhsEarlyOut
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorRhsEarlyOut
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000000011 SignBits:14
+  ; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
+    %0:_(<4 x s16>) = COPY $d0
+    %1:_(s16) = G_CONSTANT i16 3
+    %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
+    %3:_(<4 x s16>) = G_SUB %2, %0
+...
+---
+name:            VectorNonNegative
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorNonNegative
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:0000000011111111 SignBits:8
+  ; CHECK-NEXT: %2:_ KnownBits:0000000011111111 SignBits:8
+  ; CHECK-NEXT: %3:_ KnownBits:00000000???????? SignBits:8
+  ; CHECK-NEXT: %4:_ KnownBits:0000000000000000 SignBits:16
+  ; CHECK-NEXT: %5:_ KnownBits:0000000000000000 SignBits:16
+  ; CHECK-NEXT: %6:_ KnownBits:???????????????? SignBits:1
+    %0:_(<4 x s16>) = COPY $d0
+    %1:_(s16) = G_CONSTANT i16 255
+    %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
+    %3:_(<4 x s16>) = G_AND %0, %2
+    %4:_(s16) = G_CONSTANT i16 0
+    %5:_(<4 x s16>) = G_BUILD_VECTOR %4, %4, %4, %4
+    %6:_(<4 x s16>) = G_SUB %5, %3
+...
+---
+name:            VectorLhsEarlyOut
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorLhsEarlyOut
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000000011 SignBits:14
+  ; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
+    %0:_(<4 x s16>) = COPY $d0
+    %1:_(s16) = G_CONSTANT i16 3
+    %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
+    %3:_(<4 x s16>) = G_SUB %0, %2
+...
+---
+name:            VectorPartKnown
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorPartKnown
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:0000000011111111 SignBits:8
+  ; CHECK-NEXT: %2:_ KnownBits:0000000011111111 SignBits:8
+  ; CHECK-NEXT: %3:_ KnownBits:00000000???????? SignBits:8
+  ; CHECK-NEXT: %4:_ KnownBits:0000000000101010 SignBits:10
+  ; CHECK-NEXT: %5:_ KnownBits:0000000001001010 SignBits:9
+  ; CHECK-NEXT: %6:_ KnownBits:000000000??01010 SignBits:9
+  ; CHECK-NEXT: %7:_ KnownBits:???????????????? SignBits:1
+    %0:_(<4 x s16>) = COPY $d0
+    %1:_(s16) = G_CONSTANT i16 255
+    %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
+    %3:_(<4 x s16>) = G_AND %0, %2
+    %4:_(s16) = G_CONSTANT i16 42
+    %5:_(s16) = G_CONSTANT i16 74
+    %6:_(<4 x s16>) = G_BUILD_VECTOR %4, %5, %5, %4
+    %7:_(<4 x s16>) = G_SUB %6, %3
+...
+---
+name:            VectorCst36
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorCst36
+  ; CHECK-NEXT: %0:_ KnownBits:0000000000000011 SignBits:14
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000000110 SignBits:13
+  ; CHECK-NEXT: %2:_ KnownBits:0000000000000?1? SignBits:13
+  ; CHECK-NEXT: %3:_ KnownBits:0000000000000?1? SignBits:13
+  ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1
+    %0:_(s16) = G_CONSTANT i16 3
+    %1:_(s16) = G_CONSTANT i16 6
+    %2:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0
+    %3:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0
+    %4:_(<4 x s16>) = G_SUB %2, %3
+...
+
+---
+name:            VectorCst3unknown
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @VectorCst3unknown
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14
+  ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1
+    %0:_(<4 x s16>) = COPY $d0
+    %1:_(s16) = COPY $h0
+    %2:_(s16) = G_CONSTANT i16 3
+    %3:_(<4 x s16>) = G_BUILD_VECTOR %1, %2, %2, %1
+    %4:_(<4 x s16>) = G_SUB %0, %3
+...
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index c74d15782398a..b56e3ec53c18c 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -177,6 +177,51 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_VASHR) {
   EXPECT_EQ(DAG->ComputeNumSignBits(Fr2), 5u);
 }
 
+TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SUB) {
+  SDLoc Loc;
+  auto IntVT = EVT::getIntegerVT(Context, 8);
+  auto N0 = DAG->getConstant(0x00, Loc, IntVT);
+  auto N1 = DAG->getConstant(0x01, Loc, IntVT);
+  auto N5 = DAG->getConstant(0x05, Loc, IntVT);
+  auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT);
+  auto UnknownOp = DAG->getRegister(0, IntVT);
+  auto Mask = DAG->getConstant(0x1e, Loc, IntVT);
+  auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
+  // RHS early out
+  // Nsign1 = 01010101
+  // Nsign3 = 000????0
+  auto OpRhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, Nsign1);
+  EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u);
+
+  // Neg 0
+  // N0 = 00000000
+  auto OpNegZero = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N0);
+  EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u);
+
+  // Neg 1
+  // N0 = 00000000
+  // N1 = 00000001
+  auto OpNegOne = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1);
+  EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u);
+
+  // Non negative
+  // N0     = 00000000
+  // Nsign3 = 000????0
+  auto OpNonNeg = DAG->getNode(ISD::SUB, Loc, IntVT, N0, Nsign3);
+  EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u);
+
+  // LHS early out
+  // Nsign1 = 01010101
+  // Nsign3 = 000????0
+  auto OpLhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign1, Nsign3);
+  EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u);
+
+  // Nsign3 = 000????0
+  // N5     = 00000101
+  auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, N5);
+  EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u);
+}
+
 TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) {
   TargetLowering TL(*TM);
 

>From 877acf41c0e0d985db65ec2b93fe6549d09fd219 Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Fri, 12 Sep 2025 13:42:57 -0700
Subject: [PATCH 2/7] Fix typo

---
 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ashr.mir | 4 ++--
 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-shl.mir  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ashr.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ashr.mir
index 8552931c1f4c0..ee354479d603c 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ashr.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ashr.mir
@@ -102,8 +102,8 @@ body:             |
   ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
   ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1
     %0:_(<4 x s16>) = COPY $d0
-    %2:_(s16) = COPY $h0
-    %1:_(s16) = G_CONSTANT i16 3
+    %1:_(s16) = COPY $h0
+    %2:_(s16) = G_CONSTANT i16 3
     %3:_(<4 x s16>) = G_BUILD_VECTOR %1, %2, %2, %1
     %4:_(<4 x s16>) = G_ASHR %0, %3
 ...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-shl.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-shl.mir
index 61d1c4375bd6e..97bcb80503d8d 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-shl.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-shl.mir
@@ -135,8 +135,8 @@ body:             |
   ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
   ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1
     %0:_(<4 x s16>) = COPY $d0
-    %2:_(s16) = COPY $h0
-    %1:_(s16) = G_CONSTANT i16 3
+    %1:_(s16) = COPY $h0
+    %2:_(s16) = G_CONSTANT i16 3
     %3:_(<4 x s16>) = G_BUILD_VECTOR %1, %2, %2, %1
     %4:_(<4 x s16>) = G_SHL %0, %3
 ...

>From 83df265c3023045de074b3f9b616f7d25d191495 Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Fri, 12 Sep 2025 16:19:38 -0700
Subject: [PATCH 3/7] Initial attemp for sub

---
 llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 14 ++++++++++++++
 .../CodeGen/AArch64/GlobalISel/knownbits-sub.mir   | 10 +++++-----
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 0cf44e02254de..294a76b885f06 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1976,6 +1976,20 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
 
     break;
   }
+  case TargetOpcode::G_SUB: {
+    Register Src1 = MI.getOperand(1).getReg();
+    unsigned Src1NumSignBits =
+        computeNumSignBits(Src1, DemandedElts, Depth + 1);
+    if (Src1NumSignBits != 1) {
+      Register Src2 = MI.getOperand(2).getReg();
+      unsigned Src2NumSignBits =
+          computeNumSignBits(Src2, DemandedElts, Depth + 1);
+      if (Src2NumSignBits == 1)
+        return 1; // Early out.
+      FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
+    }
+    break;
+  }
   case TargetOpcode::G_FCMP:
   case TargetOpcode::G_ICMP: {
     bool IsFP = Opcode == TargetOpcode::G_FCMP;
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
index 8051bd2d17812..d91c39508d5de 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
@@ -82,7 +82,7 @@ body:             |
   ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
   ; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
   ; CHECK-NEXT: %3:_ KnownBits:00000000 SignBits:8
-  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:3
     %0:_(s8) = COPY $b0
     %1:_(s8) = G_CONSTANT i8 15
     %2:_(s8) = G_AND %0, %1
@@ -110,7 +110,7 @@ body:             |
   ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
   ; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
   ; CHECK-NEXT: %3:_ KnownBits:00000101 SignBits:5
-  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:3
     %0:_(s8) = COPY $b0
     %1:_(s8) = G_CONSTANT i8 15
     %2:_(s8) = G_AND %0, %1
@@ -154,7 +154,7 @@ body:             |
   ; CHECK-NEXT: %3:_ KnownBits:00000000???????? SignBits:8
   ; CHECK-NEXT: %4:_ KnownBits:0000000000000000 SignBits:16
   ; CHECK-NEXT: %5:_ KnownBits:0000000000000000 SignBits:16
-  ; CHECK-NEXT: %6:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %6:_ KnownBits:???????????????? SignBits:7
     %0:_(<4 x s16>) = COPY $d0
     %1:_(s16) = G_CONSTANT i16 255
     %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
@@ -189,7 +189,7 @@ body:             |
   ; CHECK-NEXT: %4:_ KnownBits:0000000000101010 SignBits:10
   ; CHECK-NEXT: %5:_ KnownBits:0000000001001010 SignBits:9
   ; CHECK-NEXT: %6:_ KnownBits:000000000??01010 SignBits:9
-  ; CHECK-NEXT: %7:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %7:_ KnownBits:???????????????? SignBits:7
     %0:_(<4 x s16>) = COPY $d0
     %1:_(s16) = G_CONSTANT i16 255
     %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
@@ -208,7 +208,7 @@ body:             |
   ; CHECK-NEXT: %1:_ KnownBits:0000000000000110 SignBits:13
   ; CHECK-NEXT: %2:_ KnownBits:0000000000000?1? SignBits:13
   ; CHECK-NEXT: %3:_ KnownBits:0000000000000?1? SignBits:13
-  ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:12
     %0:_(s16) = G_CONSTANT i16 3
     %1:_(s16) = G_CONSTANT i16 6
     %2:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0

>From bebcbc09f43008bee0793c7e9bf6d82b2b9ad908 Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Mon, 15 Sep 2025 11:07:33 -0700
Subject: [PATCH 4/7] Fix lit test
 CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir

---
 .../test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir
index c8fee5d334429..7cbe5de22debc 100644
--- a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir
+++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-bitcounts.mir
@@ -119,9 +119,10 @@ body:             |
     ; CHECK: [[R32:%[0-9]+]]:_(s32) = G_SUB [[COUNT]], [[BITDIFF]]
     %2(s16) = G_CTLZ %1
 
-    ; CHECK: [[SHIFTEDR:%[0-9]+]]:_(s32) = G_SHL [[R32]], [[BITDIFF]]
-    ; CHECK: [[R:%[0-9]+]]:_(s32) = G_ASHR [[SHIFTEDR]], [[BITDIFF]]
-    ; CHECK: $r0 = COPY [[R]]
+    ; LIBCALLS: [[SHIFTEDR:%[0-9]+]]:_(s32) = G_SHL [[R32]], [[BITDIFF]]
+    ; LIBCALLS: [[R:%[0-9]+]]:_(s32) = G_ASHR [[SHIFTEDR]], [[BITDIFF]]
+    ; LIBCALLS: $r0 = COPY [[R]]
+    ; CLZ: $r0 = COPY [[R32]]
     %3(s32) = G_SEXT %2(s16)
     $r0 = COPY %3(s32)
     BX_RET 14, $noreg, implicit $r0

>From 59ddc872d8dc22fc44a942fb8bac40552339d36c Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Mon, 15 Sep 2025 11:10:05 -0700
Subject: [PATCH 5/7] Handle non neg case

---
 .../CodeGen/GlobalISel/GISelValueTracking.cpp   | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 294a76b885f06..f09b4e30e1ee6 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1980,14 +1980,15 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     Register Src1 = MI.getOperand(1).getReg();
     unsigned Src1NumSignBits =
         computeNumSignBits(Src1, DemandedElts, Depth + 1);
-    if (Src1NumSignBits != 1) {
-      Register Src2 = MI.getOperand(2).getReg();
-      unsigned Src2NumSignBits =
-          computeNumSignBits(Src2, DemandedElts, Depth + 1);
-      if (Src2NumSignBits == 1)
-        return 1; // Early out.
-      FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
-    }
+    if (Src1NumSignBits == 1)
+      return 1; // Early Out.
+    Register Src2 = MI.getOperand(2).getReg();
+    unsigned Src2NumSignBits =
+        computeNumSignBits(Src2, DemandedElts, Depth + 1);
+    if (Src2NumSignBits == 1)
+      return 1; // Early out.
+    FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
+
     break;
   }
   case TargetOpcode::G_FCMP:

>From f7c2c793d762711f67335765ac1b197a999e44f8 Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Mon, 15 Sep 2025 15:17:26 -0700
Subject: [PATCH 6/7] Handle Non Neg

---
 .../CodeGen/GlobalISel/GISelValueTracking.cpp | 23 ++++++++++++++++++-
 .../AArch64/GlobalISel/knownbits-sub.mir      |  4 ++--
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index f09b4e30e1ee6..0630d643f92a3 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1982,13 +1982,34 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
         computeNumSignBits(Src1, DemandedElts, Depth + 1);
     if (Src1NumSignBits == 1)
       return 1; // Early Out.
+
     Register Src2 = MI.getOperand(2).getReg();
     unsigned Src2NumSignBits =
         computeNumSignBits(Src2, DemandedElts, Depth + 1);
+
+    // Handle NEG.
+    KnownBits Known1 = getKnownBits(Src1, DemandedElts, Depth);
+    if (Known1.Zero.isAllOnes()) {
+      KnownBits Known2 = getKnownBits(Src2, DemandedElts, Depth);
+      // If the input is known to be 0 or 1, the output is 0/-1, which is all
+      // sign bits set.
+      if ((Known2.Zero | 1).isAllOnes())
+        return TyBits;
+
+      // If the input is known to be positive (the sign bit is known clear),
+      // the output of the NEG has the same number of sign bits as the input.
+      if (Known2.isNonNegative())
+        return Src2NumSignBits;
+
+      // Otherwise, we treat this like a SUB.
+    }
+
     if (Src2NumSignBits == 1)
       return 1; // Early out.
-    FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
 
+    // Sub can have at most one carry bit.  Thus we know that the output
+    // is, at worst, one more bit than the inputs.
+    FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
     break;
   }
   case TargetOpcode::G_FCMP:
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
index d91c39508d5de..7fdfb18dafeb2 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir
@@ -82,7 +82,7 @@ body:             |
   ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
   ; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
   ; CHECK-NEXT: %3:_ KnownBits:00000000 SignBits:8
-  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:3
+  ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:4
     %0:_(s8) = COPY $b0
     %1:_(s8) = G_CONSTANT i8 15
     %2:_(s8) = G_AND %0, %1
@@ -154,7 +154,7 @@ body:             |
   ; CHECK-NEXT: %3:_ KnownBits:00000000???????? SignBits:8
   ; CHECK-NEXT: %4:_ KnownBits:0000000000000000 SignBits:16
   ; CHECK-NEXT: %5:_ KnownBits:0000000000000000 SignBits:16
-  ; CHECK-NEXT: %6:_ KnownBits:???????????????? SignBits:7
+  ; CHECK-NEXT: %6:_ KnownBits:???????????????? SignBits:8
     %0:_(<4 x s16>) = COPY $d0
     %1:_(s16) = G_CONSTANT i16 255
     %2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1

>From 4c4500de79d197cd1432f5e75e394d68196e90db Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Tue, 16 Sep 2025 10:54:48 -0700
Subject: [PATCH 7/7] Make early out out early

---
 llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 5 ++---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp     | 9 ++++++---
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 0630d643f92a3..e89c4eed5850b 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1986,6 +1986,8 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     Register Src2 = MI.getOperand(2).getReg();
     unsigned Src2NumSignBits =
         computeNumSignBits(Src2, DemandedElts, Depth + 1);
+    if (Src2NumSignBits == 1)
+      return 1; // Early out.
 
     // Handle NEG.
     KnownBits Known1 = getKnownBits(Src1, DemandedElts, Depth);
@@ -2004,9 +2006,6 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
       // Otherwise, we treat this like a SUB.
     }
 
-    if (Src2NumSignBits == 1)
-      return 1; // Early out.
-
     // Sub can have at most one carry bit.  Thus we know that the output
     // is, at worst, one more bit than the inputs.
     FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index bcf25958d0982..db46294bea0ce 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5066,8 +5066,13 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
     if (Tmp2 == 1) return 1; // Early out.
     return std::min(Tmp, Tmp2) - 1;
   case ISD::SUB:
+    Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1);
+    if (Tmp == 1)
+      return 1; // Early out.
+
     Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1);
-    if (Tmp2 == 1) return 1; // Early out.
+    if (Tmp2 == 1)
+      return 1; // Early out.
 
     // Handle NEG.
     if (ConstantSDNode *CLHS =
@@ -5090,8 +5095,6 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
 
     // Sub can have at most one carry bit.  Thus we know that the output
     // is, at worst, one more bit than the inputs.
-    Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1);
-    if (Tmp == 1) return 1; // Early out.
     return std::min(Tmp, Tmp2) - 1;
   case ISD::MUL: {
     // The output of the Mul can be at most twice the valid bits in the inputs.



More information about the llvm-commits mailing list