[llvm] [InstCombine] Added optimisation for trunc (Pow2 >> x) to 1 (PR #157030)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 5 00:14:00 PDT 2025


https://github.com/kper created https://github.com/llvm/llvm-project/pull/157030

Closes #156898

I have added two cases. The first one matches when the constant is exactly power of 2. The second case was to address the general case mentioned in the linked issue. I, however, did not really solve the general case.
We can only emit a `icmp ult` if all the bits are one and that's only the case when the constant + 1 is a power of 2. Otherwise, we need to create `icmp eq` for every bit that is one.

Here are a few examples which won't be working with the two cases:
-  constant is `9`: https://alive2.llvm.org/ce/z/S5FLJZ
- subrange in `56`: https://alive2.llvm.org/ce/z/yn_ZNG
- and finally an example as worst case (because it alternates the bits): https://alive2.llvm.org/ce/z/nDitNA

I wonder whether I should still implement the general case since it increments the number of instructions?

cc @nikic @andjo403 

>From 235c6a78a18b27235a86aba007fa4b95a7874121 Mon Sep 17 00:00:00 2001
From: Kevin Per <kevin.per at protonmail.com>
Date: Fri, 5 Sep 2025 06:23:45 +0000
Subject: [PATCH 1/2] [InstCombine] trunc(Pow2 >> X) to i1

---
 llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 12 ++++++++++++
 llvm/test/Transforms/InstCombine/trunc-lshr.ll       | 10 ++++++++++
 2 files changed, 22 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index fdef49e310f81..ef6535dcd319f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -16,6 +16,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/PatternMatch.h"
+#include "llvm/IR/Value.h"
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Transforms/InstCombine/InstCombiner.h"
 #include <optional>
@@ -968,6 +969,17 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
     Trunc.setHasNoUnsignedWrap(true);
     Changed = true;
   }
+  
+  const APInt *C1;
+  Value *V1;
+  // trunc (lshr i8 %C1, %V1) to i1 -> icmp eq %V1, sqrt(%C1)
+  if(DestWidth == 1 &&
+    match(Src, m_OneUse(m_Shr(m_Power2(C1), m_Value(V1))))) {
+      const APInt Sqrt = C1->sqrt();
+      Value *Right = ConstantInt::get(V1->getType(), Sqrt);
+      Value *Icmp = Builder.CreateICmpEQ(V1, Right);
+      return replaceInstUsesWith(Trunc, Icmp);
+  }
 
   return Changed ? &Trunc : nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/trunc-lshr.ll b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
index 4364b09cfa709..38db57dd53f2b 100644
--- a/llvm/test/Transforms/InstCombine/trunc-lshr.ll
+++ b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
@@ -93,3 +93,13 @@ define i1 @test5(i32 %i, ptr %p) {
   ret i1 %op
 }
 
+define i1 @test6(i8 %x) {
+; CHECK-LABEL: define i1 @test6(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[TRUNC:%.*]] = icmp eq i8 [[X]], 2
+; CHECK-NEXT:    ret i1 [[TRUNC]]
+;
+  %lshr = lshr i8 4, %x
+  %trunc = trunc i8 %lshr to i1
+  ret i1 %trunc
+}

>From 3aadd9b95ea582b8bcb48a1d5d96335514f2841b Mon Sep 17 00:00:00 2001
From: Kevin Per <kevin.per at protonmail.com>
Date: Fri, 5 Sep 2025 06:42:09 +0000
Subject: [PATCH 2/2] [InstCombine] trunc(C >> X) to i1 iff (C + 1) is power of
 2

---
 .../InstCombine/InstCombineCasts.cpp          | 27 +++++++++++++------
 .../test/Transforms/InstCombine/trunc-lshr.ll | 11 ++++++++
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index ef6535dcd319f..a3e9969503f02 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "InstCombineInternal.h"
+#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/Analysis/ConstantFolding.h"
 #include "llvm/IR/DataLayout.h"
@@ -969,16 +970,26 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
     Trunc.setHasNoUnsignedWrap(true);
     Changed = true;
   }
-  
+
   const APInt *C1;
   Value *V1;
-  // trunc (lshr i8 %C1, %V1) to i1 -> icmp eq %V1, sqrt(%C1)
-  if(DestWidth == 1 &&
-    match(Src, m_OneUse(m_Shr(m_Power2(C1), m_Value(V1))))) {
-      const APInt Sqrt = C1->sqrt();
-      Value *Right = ConstantInt::get(V1->getType(), Sqrt);
-      Value *Icmp = Builder.CreateICmpEQ(V1, Right);
-      return replaceInstUsesWith(Trunc, Icmp);
+  // trunc (lshr i8 C1, V1) to i1 -> icmp eq V1, sqrt(C1) iff C1 is power of 2
+  if (DestWidth == 1 &&
+      match(Src, m_OneUse(m_Shr(m_Power2(C1), m_Value(V1))))) {
+    const APInt Sqrt = C1->sqrt();
+    Value *Right = ConstantInt::get(V1->getType(), Sqrt);
+    Value *Icmp = Builder.CreateICmpEQ(V1, Right);
+    return replaceInstUsesWith(Trunc, Icmp);
+  }
+
+  // trunc (lshr i8 C1, V1) to i1 -> icmp ult V1, sqrt(C1 + 1) iff (C1 + 1) is
+  // power of 2
+  if (DestWidth == 1 && match(Src, m_OneUse(m_Shr(m_APInt(C1), m_Value(V1)))) &&
+      (*C1 + 1).isPowerOf2()) {
+    const APInt Sqrt = (*C1 + 1).sqrt();
+    Value *Right = ConstantInt::get(V1->getType(), Sqrt);
+    Value *Icmp = Builder.CreateICmpULT(V1, Right);
+    return replaceInstUsesWith(Trunc, Icmp);
   }
 
   return Changed ? &Trunc : nullptr;
diff --git a/llvm/test/Transforms/InstCombine/trunc-lshr.ll b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
index 38db57dd53f2b..84daba3d13b9a 100644
--- a/llvm/test/Transforms/InstCombine/trunc-lshr.ll
+++ b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
@@ -103,3 +103,14 @@ define i1 @test6(i8 %x) {
   %trunc = trunc i8 %lshr to i1
   ret i1 %trunc
 }
+
+define i1 @test7(i8 %x) {
+; CHECK-LABEL: define i1 @test7(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[TRUNC:%.*]] = icmp ult i8 [[X]], 4
+; CHECK-NEXT:    ret i1 [[TRUNC]]
+;
+  %lshr = lshr i8 15, %x
+  %trunc = trunc i8 %lshr to i1
+  ret i1 %trunc
+}



More information about the llvm-commits mailing list