[llvm] [Analysis] computeKnownBitsFromOperator - add @llvm.clmul knownbits handling and tests (PR #177893)

Lleu Yang via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 26 06:19:15 PST 2026


https://github.com/megakite updated https://github.com/llvm/llvm-project/pull/177893

>From 8c6641f287df1d7fd1975cd983d3d1e3bd8230cd Mon Sep 17 00:00:00 2001
From: Lleu Yang <hello at megakite.icu>
Date: Sun, 25 Jan 2026 19:45:50 +0800
Subject: [PATCH 1/3] [Analysis] Add baseline test for @llvm.clmul knownbits

---
 .../Analysis/ValueTracking/knownbits-clmul.ll | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 llvm/test/Analysis/ValueTracking/knownbits-clmul.ll

diff --git a/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll b/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
new file mode 100644
index 0000000000000..4ce543c60c8bf
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
@@ -0,0 +1,89 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+define i1 @clmul_zero(i8 %a) nounwind {
+; CHECK-LABEL: @clmul_zero(
+; CHECK-NEXT:    [[CLMUL:%.*]] = call i8 @llvm.clmul.i8(i8 [[A:%.*]], i8 0)
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[CLMUL]], 1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %clmul = call i8 @llvm.clmul.i8(i8 %a, i8 0)
+  %r = icmp eq i8 %clmul, 1
+  ret i1 %r
+}
+
+define i1 @clmul_low_bits(i8 %a) nounwind {
+; CHECK-LABEL: @clmul_low_bits(
+; CHECK-NEXT:    [[CLMUL:%.*]] = call i8 @llvm.clmul.i8(i8 [[A:%.*]], i8 4)
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[CLMUL]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %clmul = call i8 @llvm.clmul.i8(i8 %a, i8 4)
+  %and = and i8 %clmul, 3
+  %r = icmp eq i8 %and, 0
+  ret i1 %r
+}
+
+define i1 @clmul_low_bits_negative(i8 %a) nounwind {
+; CHECK-LABEL: @clmul_low_bits_negative(
+; CHECK-NEXT:    [[CLMUL:%.*]] = call i8 @llvm.clmul.i8(i8 [[A:%.*]], i8 4)
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[CLMUL]], 4
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %clmul = call i8 @llvm.clmul.i8(i8 %a, i8 4)
+  %and = and i8 %clmul, 4
+  %r = icmp eq i8 %and, 0
+  ret i1 %r
+}
+
+define i1 @clmul_high_bits(i8 %a, i8 %b) nounwind {
+; CHECK-LABEL: @clmul_high_bits(
+; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext i8 [[A:%.*]] to i16
+; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext i8 [[B:%.*]] to i16
+; CHECK-NEXT:    [[CLMUL:%.*]] = call i16 @llvm.clmul.i16(i16 [[ZEXT_A]], i16 [[ZEXT_B]])
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i16 [[CLMUL]], -1
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %zext_a = zext i8 %a to i16
+  %zext_b = zext i8 %b to i16
+  %clmul = call i16 @llvm.clmul.i16(i16 %zext_a, i16 %zext_b)
+  %and = and i16 %clmul, u0x8000
+  %r = icmp eq i16 %and, 0
+  ret i1 %r
+}
+
+define i1 @clmul_high_bits_boundary(i8 %a, i8 %b) nounwind {
+; CHECK-LABEL: @clmul_high_bits_boundary(
+; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext i8 [[A:%.*]] to i16
+; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext i8 [[B:%.*]] to i16
+; CHECK-NEXT:    [[CLMUL:%.*]] = call i16 @llvm.clmul.i16(i16 [[ZEXT_A]], i16 [[ZEXT_B]])
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[CLMUL]], 16384
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i16 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %zext_a = zext i8 %a to i16
+  %zext_b = zext i8 %b to i16
+  %clmul = call i16 @llvm.clmul.i16(i16 %zext_a, i16 %zext_b)
+  %and = and i16 %clmul, u0x4000
+  %r = icmp eq i16 %and, 0
+  ret i1 %r
+}
+
+define i1 @clmul_high_bits_negative(i8 %a, i8 %b) nounwind {
+; CHECK-LABEL: @clmul_high_bits_negative(
+; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext i8 [[A:%.*]] to i16
+; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext i8 [[B:%.*]] to i16
+; CHECK-NEXT:    [[CLMUL:%.*]] = call i16 @llvm.clmul.i16(i16 [[ZEXT_A]], i16 [[ZEXT_B]])
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[CLMUL]], 8192
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i16 [[AND]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %zext_a = zext i8 %a to i16
+  %zext_b = zext i8 %b to i16
+  %clmul = call i16 @llvm.clmul.i16(i16 %zext_a, i16 %zext_b)
+  %and = and i16 %clmul, u0x2000
+  %r = icmp eq i16 %and, 0
+  ret i1 %r
+}

>From fdc2f87a3773de5130f3c2f26f58bdd76473211c Mon Sep 17 00:00:00 2001
From: Lleu Yang <hello at megakite.icu>
Date: Mon, 26 Jan 2026 11:11:15 +0800
Subject: [PATCH 2/3] [Analysis] computeKnownBitsFromOperator - add @llvm.clmul
 knownbits handling and tests

---
 llvm/lib/Analysis/ValueTracking.cpp            |  5 +++++
 .../Analysis/ValueTracking/knownbits-clmul.ll  | 18 ++++--------------
 2 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b84919d89388d..a36ff1b1bbed5 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2097,6 +2097,11 @@ static void computeKnownBitsFromOperator(const Operator *I,
         Known = Known2.unionWith(Known3);
         break;
       }
+      case Intrinsic::clmul:
+        computeKnownBits(I->getOperand(0), DemandedElts, Known, Q, Depth + 1);
+        computeKnownBits(I->getOperand(1), DemandedElts, Known2, Q, Depth + 1);
+        Known = KnownBits::clmul(Known, Known2);
+        break;
       case Intrinsic::uadd_sat:
         computeKnownBits(I->getOperand(0), DemandedElts, Known, Q, Depth + 1);
         computeKnownBits(I->getOperand(1), DemandedElts, Known2, Q, Depth + 1);
diff --git a/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll b/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
index 4ce543c60c8bf..92c65f18bed05 100644
--- a/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
+++ b/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
@@ -3,9 +3,7 @@
 
 define i1 @clmul_zero(i8 %a) nounwind {
 ; CHECK-LABEL: @clmul_zero(
-; CHECK-NEXT:    [[CLMUL:%.*]] = call i8 @llvm.clmul.i8(i8 [[A:%.*]], i8 0)
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[CLMUL]], 1
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %clmul = call i8 @llvm.clmul.i8(i8 %a, i8 0)
   %r = icmp eq i8 %clmul, 1
@@ -14,10 +12,7 @@ define i1 @clmul_zero(i8 %a) nounwind {
 
 define i1 @clmul_low_bits(i8 %a) nounwind {
 ; CHECK-LABEL: @clmul_low_bits(
-; CHECK-NEXT:    [[CLMUL:%.*]] = call i8 @llvm.clmul.i8(i8 [[A:%.*]], i8 4)
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[CLMUL]], 3
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %clmul = call i8 @llvm.clmul.i8(i8 %a, i8 4)
   %and = and i8 %clmul, 3
@@ -40,11 +35,7 @@ define i1 @clmul_low_bits_negative(i8 %a) nounwind {
 
 define i1 @clmul_high_bits(i8 %a, i8 %b) nounwind {
 ; CHECK-LABEL: @clmul_high_bits(
-; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext i8 [[A:%.*]] to i16
-; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext i8 [[B:%.*]] to i16
-; CHECK-NEXT:    [[CLMUL:%.*]] = call i16 @llvm.clmul.i16(i16 [[ZEXT_A]], i16 [[ZEXT_B]])
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt i16 [[CLMUL]], -1
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %zext_a = zext i8 %a to i16
   %zext_b = zext i8 %b to i16
@@ -59,8 +50,7 @@ define i1 @clmul_high_bits_boundary(i8 %a, i8 %b) nounwind {
 ; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext i8 [[A:%.*]] to i16
 ; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext i8 [[B:%.*]] to i16
 ; CHECK-NEXT:    [[CLMUL:%.*]] = call i16 @llvm.clmul.i16(i16 [[ZEXT_A]], i16 [[ZEXT_B]])
-; CHECK-NEXT:    [[AND:%.*]] = and i16 [[CLMUL]], 16384
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i16 [[AND]], 0
+; CHECK-NEXT:    [[R:%.*]] = icmp samesign ult i16 [[CLMUL]], 16384
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %zext_a = zext i8 %a to i16

>From a19870a24d7aa1f4c0c84080276680e450f8394d Mon Sep 17 00:00:00 2001
From: Lleu Yang <hello at megakite.icu>
Date: Mon, 26 Jan 2026 22:18:40 +0800
Subject: [PATCH 3/3] [Analysis] Add vector test for @llvm.clmul knownbits

---
 .../Analysis/ValueTracking/knownbits-clmul.ll | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll b/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
index 92c65f18bed05..fd4374e9d39f2 100644
--- a/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
+++ b/llvm/test/Analysis/ValueTracking/knownbits-clmul.ll
@@ -33,6 +33,29 @@ define i1 @clmul_low_bits_negative(i8 %a) nounwind {
   ret i1 %r
 }
 
+define <2 x i1> @clmul_low_bits_vector(<2 x i8> %a) nounwind {
+; CHECK-LABEL: @clmul_low_bits_vector(
+; CHECK-NEXT:    ret <2 x i1> splat (i1 true)
+;
+  %clmul = call <2 x i8> @llvm.clmul.v2i8(<2 x i8> %a, <2 x i8> splat (i8 4))
+  %and = and <2 x i8> %clmul, splat (i8 3)
+  %r = icmp eq <2 x i8> %and, zeroinitializer
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @clmul_low_bits_vector_negative(<2 x i8> %a) nounwind {
+; CHECK-LABEL: @clmul_low_bits_vector_negative(
+; CHECK-NEXT:    [[CLMUL:%.*]] = call <2 x i8> @llvm.clmul.v2i8(<2 x i8> [[A:%.*]], <2 x i8> splat (i8 4))
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i8> [[CLMUL]], splat (i8 4)
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[AND]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %clmul = call <2 x i8> @llvm.clmul.v2i8(<2 x i8> %a, <2 x i8> splat (i8 4))
+  %and = and <2 x i8> %clmul, splat (i8 4)
+  %r = icmp eq <2 x i8> %and, zeroinitializer
+  ret <2 x i1> %r
+}
+
 define i1 @clmul_high_bits(i8 %a, i8 %b) nounwind {
 ; CHECK-LABEL: @clmul_high_bits(
 ; CHECK-NEXT:    ret i1 true
@@ -77,3 +100,48 @@ define i1 @clmul_high_bits_negative(i8 %a, i8 %b) nounwind {
   %r = icmp eq i16 %and, 0
   ret i1 %r
 }
+
+define <2 x i1> @clmul_high_bits_vector(<2 x i8> %a, <2 x i8> %b) nounwind {
+; CHECK-LABEL: @clmul_high_bits_vector(
+; CHECK-NEXT:    ret <2 x i1> splat (i1 true)
+;
+  %zext_a = zext <2 x i8> %a to <2 x i16>
+  %zext_b = zext <2 x i8> %b to <2 x i16>
+  %clmul = call <2 x i16> @llvm.clmul.v2i16(<2 x i16> %zext_a, <2 x i16> %zext_b)
+  %and = and <2 x i16> %clmul, splat (i16 u0x8000)
+  %r = icmp eq <2 x i16> %and, zeroinitializer
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @clmul_high_bits_boundary_vector(<2 x i8> %a, <2 x i8> %b) nounwind {
+; CHECK-LABEL: @clmul_high_bits_boundary_vector(
+; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext <2 x i8> [[B:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[CLMUL:%.*]] = call <2 x i16> @llvm.clmul.v2i16(<2 x i16> [[ZEXT_A]], <2 x i16> [[ZEXT_B]])
+; CHECK-NEXT:    [[R:%.*]] = icmp samesign ult <2 x i16> [[CLMUL]], splat (i16 16384)
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %zext_a = zext <2 x i8> %a to <2 x i16>
+  %zext_b = zext <2 x i8> %b to <2 x i16>
+  %clmul = call <2 x i16> @llvm.clmul.v2i16(<2 x i16> %zext_a, <2 x i16> %zext_b)
+  %and = and <2 x i16> %clmul, splat (i16 u0x4000)
+  %r = icmp eq <2 x i16> %and, zeroinitializer
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @clmul_high_bits_negative_vector(<2 x i8> %a, <2 x i8> %b) nounwind {
+; CHECK-LABEL: @clmul_high_bits_negative_vector(
+; CHECK-NEXT:    [[ZEXT_A:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[ZEXT_B:%.*]] = zext <2 x i8> [[B:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[CLMUL:%.*]] = call <2 x i16> @llvm.clmul.v2i16(<2 x i16> [[ZEXT_A]], <2 x i16> [[ZEXT_B]])
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i16> [[CLMUL]], splat (i16 8192)
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i16> [[AND]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %zext_a = zext <2 x i8> %a to <2 x i16>
+  %zext_b = zext <2 x i8> %b to <2 x i16>
+  %clmul = call <2 x i16> @llvm.clmul.v2i16(<2 x i16> %zext_a, <2 x i16> %zext_b)
+  %and = and <2 x i16> %clmul, splat (i16 u0x2000)
+  %r = icmp eq <2 x i16> %and, zeroinitializer
+  ret <2 x i1> %r
+}



More information about the llvm-commits mailing list