[llvm] [DAG] SelectionDAG::isKnownToBeAPowerOfTwo - add ISD::TRUNCATE handling and tests (PR #184365)

Pranshu Goyal via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 5 09:59:31 PST 2026


https://github.com/pranshoe updated https://github.com/llvm/llvm-project/pull/184365

>From 454fd4baac1e9f419f9f66a3c816281614452e9d Mon Sep 17 00:00:00 2001
From: pranshoe <pranshu.goyal71 at gmail.com>
Date: Tue, 3 Mar 2026 15:45:18 +0000
Subject: [PATCH 1/3] [DAG] SelectionDAG::isKnownToBeAPowerOfTwo - add
 ISD::TRUNCATE handling and tests

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  7 ++++
 llvm/test/CodeGen/X86/known-pow2.ll           | 35 +++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 507cd27b7f501..c2920efacb012 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4751,6 +4751,13 @@ bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val,
            isKnownNeverZero(Val, Depth);
   }
 
+  case ISD::TRUNCATE: {
+    if (OrZero)
+      return isKnownToBeAPowerOfTwo(Val.getOperand(0), OrZero, Depth + 1);
+    return isKnownToBeAPowerOfTwo(Val.getOperand(0), OrZero, Depth + 1) &&
+           isKnownNeverZero(Val, Depth);
+  }
+
   case ISD::ROTL:
   case ISD::ROTR:
     return isKnownToBeAPowerOfTwo(Val.getOperand(0), /*OrZero=*/false,
diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll
index 2457f3344592c..847cc2756f548 100644
--- a/llvm/test/CodeGen/X86/known-pow2.ll
+++ b/llvm/test/CodeGen/X86/known-pow2.ll
@@ -1006,3 +1006,38 @@ define i32 @pow2_blsi_sub(i32 %x, i32 %a) {
   %r = and i32 %x_sub_y, %y
   ret i32 %r
 }
+
+define i8 @pow2_trunc_fail(i32 %x, i32 %a){
+; CHECK-LABEL: pow2_trunc_fail:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    subb %sil, %al
+; CHECK-NEXT:    andb %sil, %al
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %y = and i32 %a, 255
+  %x8 = trunc i32 %x to i8
+  %y8 = trunc i32 %y to i8
+  %x_sub_y = sub i8 %x8, %y8
+  %r = and i8 %x_sub_y, %y8
+  ret i8 %r
+}
+
+define i8 @pow2_trunc(i32 %x, i32 %a){
+; CHECK-LABEL: pow2_trunc:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %eax
+; CHECK-NEXT:    negl %eax
+; CHECK-NEXT:    andl %esi, %eax
+; CHECK-NEXT:    notb %dil
+; CHECK-NEXT:    andb %dil, %al
+; CHECK-NEXT:    # kill: def $al killed $al killed $eax
+; CHECK-NEXT:    retq
+  %neg_a = sub i32 0, %a
+  %y = and i32 %a, %neg_a
+  %x8 = trunc i32 %x to i8
+  %y8 = trunc i32 %y to i8
+  %x_sub_y = sub i8 %x8, %y8
+  %r = and i8 %x_sub_y, %y8
+  ret i8 %r
+}

>From 42f4ad6c0fa1f89d2e63b35dd2349e43e2cb167f Mon Sep 17 00:00:00 2001
From: pranshoe <pranshu.goyal71 at gmail.com>
Date: Thu, 5 Mar 2026 17:48:38 +0000
Subject: [PATCH 2/3] [DAG] SelectionDAG::isKnownToBeAPowerOfTwo - Vector
 Coverage tests for ISD::TRUNCATE

---
 llvm/test/CodeGen/X86/known-pow2.ll | 54 ++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll
index 847cc2756f548..d2eba2cdca76c 100644
--- a/llvm/test/CodeGen/X86/known-pow2.ll
+++ b/llvm/test/CodeGen/X86/known-pow2.ll
@@ -1011,11 +1011,12 @@ define i8 @pow2_trunc_fail(i32 %x, i32 %a){
 ; CHECK-LABEL: pow2_trunc_fail:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    andb $78, %sil
 ; CHECK-NEXT:    subb %sil, %al
 ; CHECK-NEXT:    andb %sil, %al
 ; CHECK-NEXT:    # kill: def $al killed $al killed $eax
 ; CHECK-NEXT:    retq
-  %y = and i32 %a, 255
+  %y = and i32 %a, 78
   %x8 = trunc i32 %x to i8
   %y8 = trunc i32 %y to i8
   %x_sub_y = sub i8 %x8, %y8
@@ -1041,3 +1042,54 @@ define i8 @pow2_trunc(i32 %x, i32 %a){
   %r = and i8 %x_sub_y, %y8
   ret i8 %r
 }
+
+define <4 x i8> @pow2_trun_vec(<4 x i32> %x, <4 x i32> %a) {
+; CHECK-LABEL: pow2_trun_vec:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pshufd {{.*#+}} xmm1 = xmm1[0,0,0,0]
+; CHECK-NEXT:    pxor %xmm2, %xmm2
+; CHECK-NEXT:    psubd %xmm1, %xmm2
+; CHECK-NEXT:    pand %xmm1, %xmm2
+; CHECK-NEXT:    movdqa {{.*#+}} xmm1 = [255,0,255,0,255,0,255,0]
+; CHECK-NEXT:    pand %xmm1, %xmm0
+; CHECK-NEXT:    packuswb %xmm0, %xmm0
+; CHECK-NEXT:    packuswb %xmm0, %xmm0
+; CHECK-NEXT:    pand %xmm1, %xmm2
+; CHECK-NEXT:    packuswb %xmm2, %xmm2
+; CHECK-NEXT:    packuswb %xmm2, %xmm2
+; CHECK-NEXT:    pandn %xmm2, %xmm0
+; CHECK-NEXT:    retq
+
+  %a.splat = shufflevector <4 x i32> %a, <4 x i32> poison, <4 x i32> zeroinitializer
+  %a.splat.neg = sub <4 x i32> zeroinitializer, %a.splat
+  %y = and <4 x i32> %a.splat, %a.splat.neg
+  %x8 = trunc <4 x i32> %x to <4 x i8>
+  %y8 = trunc <4 x i32> %y to <4 x i8>
+  %x_sub_y = sub <4 x i8> %x8, %y8
+  %r = and <4 x i8> %x_sub_y, %y8
+  ret <4 x i8> %r
+}
+
+define <4 x i8> @pow2_trunc_vec_fail(<4 x i32> %x, <4 x i32> %a) {
+; CHECK-LABEL: pow2_trunc_vec_fail:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pshufd {{.*#+}} xmm1 = xmm1[0,0,0,0]
+; CHECK-NEXT:    pand {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; CHECK-NEXT:    pand {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-NEXT:    packuswb %xmm0, %xmm0
+; CHECK-NEXT:    packuswb %xmm0, %xmm0
+; CHECK-NEXT:    packuswb %xmm1, %xmm1
+; CHECK-NEXT:    packuswb %xmm1, %xmm1
+; CHECK-NEXT:    psubb %xmm1, %xmm0
+; CHECK-NEXT:    pand %xmm1, %xmm0
+; CHECK-NEXT:    retq
+
+  %a.splat = shufflevector <4 x i32> %a, <4 x i32> poison, <4 x i32> zeroinitializer
+  %y = and <4 x i32> %a.splat, <i32 78, i32 69, i32 67, i32 100>
+  %x8 = trunc <4 x i32> %x to <4 x i8>
+  %y8 = trunc <4 x i32> %y to <4 x i8>
+  %x_sub_y = sub <4 x i8> %x8, %y8
+  %r = and <4 x i8> %x_sub_y, %y8
+  ret <4 x i8> %r
+}
+

>From e8898c488eaa5cb2216ac3d159613f9a0d708594 Mon Sep 17 00:00:00 2001
From: pranshoe <pranshu.goyal71 at gmail.com>
Date: Thu, 5 Mar 2026 17:49:18 +0000
Subject: [PATCH 3/3] [DAG] SelectionDAG::isKnownToBeAPowerOfTwo - Add
 OrZero==false edge test cases for ISD::TRUNCATE

---
 .../CodeGen/AArch64/knownpow2-trunc-orzero.ll | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/knownpow2-trunc-orzero.ll

diff --git a/llvm/test/CodeGen/AArch64/knownpow2-trunc-orzero.ll b/llvm/test/CodeGen/AArch64/knownpow2-trunc-orzero.ll
new file mode 100644
index 0000000000000..b0c9515376286
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/knownpow2-trunc-orzero.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=arm64-unknown-unknown-gnu | FileCheck %s --check-prefix=CHECK
+
+define i8 @pow2_trunc_orzero_false_notzero(i32 %x, i8 %z){
+; CHECK-LABEL: pow2_trunc_orzero_false_notzero:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    and w8, w1, #0xff
+; CHECK-NEXT:    and w9, w0, #0x7
+; CHECK-NEXT:    lsr w0, w8, w9
+; CHECK-NEXT:    ret
+
+  %amt = and i32 %x, 7
+  %y = shl i32 1, %amt
+  %tr = trunc i32 %y to i8
+  %div = udiv i8 %z, %tr
+  ret i8 %div
+}
+
+define i8 @pow2_trunc_orzero_false_maybezero(i32 %x, i8 %z){
+; CHECK-LABEL: pow2_trunc_orzero_false_maybezero:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    neg w8, w0
+; CHECK-NEXT:    and w9, w1, #0xff
+; CHECK-NEXT:    and w8, w0, w8
+; CHECK-NEXT:    and w8, w8, #0xff
+; CHECK-NEXT:    udiv w0, w9, w8
+; CHECK-NEXT:    ret
+
+  %neg_x = sub i32 0, %x
+  %y = and i32 %x, %neg_x
+  %tr = trunc i32 %y to i8
+  %div = udiv i8 %z, %tr
+  ret i8 %div
+}



More information about the llvm-commits mailing list