[llvm] [AArch64][GlobalISel] Add handling for cls intrinsic (PR #200440)

Joshua Rodriguez via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 06:23:00 PDT 2026


https://github.com/JoshdRod updated https://github.com/llvm/llvm-project/pull/200440

>From 473c00533ac0102239c5c88f6c1c6da966277fed Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Fri, 29 May 2026 15:59:09 +0000
Subject: [PATCH 1/3] [AArch64][GlobalISel] Add handling for cls intrinsic

Neon intrinsic neon.cls wasn't linked to the generic node G_CTLS, which wasn't linked to AArch64 specific SDAG node ctls.
Add in these links to allow the intrinsic to properly lower.
---
 llvm/lib/Target/AArch64/AArch64InstrGISel.td           | 2 ++
 llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp | 2 ++
 llvm/test/CodeGen/AArch64/arm64-vcnt.ll                | 1 +
 3 files changed, 5 insertions(+)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrGISel.td b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
index ec95448f61043..b4d04f428bcd2 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrGISel.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
@@ -355,6 +355,8 @@ def : GINodeEquiv<G_AARCH64_RANGE_PREFETCH, AArch64RangePrefetch>;
 
 def : GINodeEquiv<G_FPTRUNC_ODD, AArch64fcvtxn_n>;
 
+def : GINodeEquiv<G_CTLS, ctls>;
+
 // These are patterns that we only use for GlobalISel via the importer.
 def : Pat<(f32 (fadd (vector_extract (v2f32 FPR64:$Rn), (i64 0)),
                      (vector_extract (v2f32 FPR64:$Rn), (i64 1)))),
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 6092f63fcde72..78c2268aac986 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -2106,6 +2106,8 @@ bool AArch64LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
     return LowerUnaryOp(TargetOpcode::G_FPTOUI_SAT);
   case Intrinsic::aarch64_neon_fcvtzs:
     return LowerUnaryOp(TargetOpcode::G_FPTOSI_SAT);
+  case Intrinsic::aarch64_neon_cls:
+    return LowerUnaryOp(TargetOpcode::G_CTLS);
 
   case Intrinsic::vector_reverse:
     // TODO: Add support for vector_reverse
diff --git a/llvm/test/CodeGen/AArch64/arm64-vcnt.ll b/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
index f2113d45589b3..c5ef62293c25a 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
@@ -1,4 +1,5 @@
 ; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s
+; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple -global-isel -global-isel-abort=2 2>&1 | FileCheck %s
 
 define <8 x i8> @cls_8b(ptr %A) nounwind {
 ;CHECK-LABEL: cls_8b:

>From 9bec3bbd6d49a1f65a58d55d68f880306eb9db60 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 2 Jun 2026 13:11:50 +0000
Subject: [PATCH 2/3] [AArch64][GlobalISel] Remove duplicate GI node
 equivalence statement

The generic opcode G_CTLS is already defined as equivalent to the SDAG node ctls in a generic SelectionDAGCompat file.
Hence, we can remove this AArch64-specific duplicate definition.
---
 llvm/lib/Target/AArch64/AArch64InstrGISel.td | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrGISel.td b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
index b4d04f428bcd2..9c646c43cdcbf 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrGISel.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
@@ -355,7 +355,6 @@ def : GINodeEquiv<G_AARCH64_RANGE_PREFETCH, AArch64RangePrefetch>;
 
 def : GINodeEquiv<G_FPTRUNC_ODD, AArch64fcvtxn_n>;
 
-def : GINodeEquiv<G_CTLS, ctls>;
 
 // These are patterns that we only use for GlobalISel via the importer.
 def : Pat<(f32 (fadd (vector_extract (v2f32 FPR64:$Rn), (i64 0)),

>From 2fdd74d7654f52891c69610cf0a1a3a12e8302aa Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 2 Jun 2026 13:20:00 +0000
Subject: [PATCH 3/3] [AArch64] Modernise test arm64-vcnt.ll

---
 llvm/test/CodeGen/AArch64/arm64-vcnt.ll | 43 ++++++++++++++++++-------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/arm64-vcnt.ll b/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
index c5ef62293c25a..6e4d5d5fe418b 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
@@ -1,49 +1,68 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s
 ; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple -global-isel -global-isel-abort=2 2>&1 | FileCheck %s
 
 define <8 x i8> @cls_8b(ptr %A) nounwind {
-;CHECK-LABEL: cls_8b:
-;CHECK: cls.8b
+; CHECK-LABEL: cls_8b:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ldr d0, [x0]
+; CHECK-NEXT:    cls.8b v0, v0
+; CHECK-NEXT:    ret
 	%tmp1 = load <8 x i8>, ptr %A
 	%tmp3 = call <8 x i8> @llvm.aarch64.neon.cls.v8i8(<8 x i8> %tmp1)
 	ret <8 x i8> %tmp3
 }
 
 define <16 x i8> @cls_16b(ptr %A) nounwind {
-;CHECK-LABEL: cls_16b:
-;CHECK: cls.16b
+; CHECK-LABEL: cls_16b:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ldr q0, [x0]
+; CHECK-NEXT:    cls.16b v0, v0
+; CHECK-NEXT:    ret
 	%tmp1 = load <16 x i8>, ptr %A
 	%tmp3 = call <16 x i8> @llvm.aarch64.neon.cls.v16i8(<16 x i8> %tmp1)
 	ret <16 x i8> %tmp3
 }
 
 define <4 x i16> @cls_4h(ptr %A) nounwind {
-;CHECK-LABEL: cls_4h:
-;CHECK: cls.4h
+; CHECK-LABEL: cls_4h:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ldr d0, [x0]
+; CHECK-NEXT:    cls.4h v0, v0
+; CHECK-NEXT:    ret
 	%tmp1 = load <4 x i16>, ptr %A
 	%tmp3 = call <4 x i16> @llvm.aarch64.neon.cls.v4i16(<4 x i16> %tmp1)
 	ret <4 x i16> %tmp3
 }
 
 define <8 x i16> @cls_8h(ptr %A) nounwind {
-;CHECK-LABEL: cls_8h:
-;CHECK: cls.8h
+; CHECK-LABEL: cls_8h:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ldr q0, [x0]
+; CHECK-NEXT:    cls.8h v0, v0
+; CHECK-NEXT:    ret
 	%tmp1 = load <8 x i16>, ptr %A
 	%tmp3 = call <8 x i16> @llvm.aarch64.neon.cls.v8i16(<8 x i16> %tmp1)
 	ret <8 x i16> %tmp3
 }
 
 define <2 x i32> @cls_2s(ptr %A) nounwind {
-;CHECK-LABEL: cls_2s:
-;CHECK: cls.2s
+; CHECK-LABEL: cls_2s:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ldr d0, [x0]
+; CHECK-NEXT:    cls.2s v0, v0
+; CHECK-NEXT:    ret
 	%tmp1 = load <2 x i32>, ptr %A
 	%tmp3 = call <2 x i32> @llvm.aarch64.neon.cls.v2i32(<2 x i32> %tmp1)
 	ret <2 x i32> %tmp3
 }
 
 define <4 x i32> @cls_4s(ptr %A) nounwind {
-;CHECK-LABEL: cls_4s:
-;CHECK: cls.4s
+; CHECK-LABEL: cls_4s:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ldr q0, [x0]
+; CHECK-NEXT:    cls.4s v0, v0
+; CHECK-NEXT:    ret
 	%tmp1 = load <4 x i32>, ptr %A
 	%tmp3 = call <4 x i32> @llvm.aarch64.neon.cls.v4i32(<4 x i32> %tmp1)
 	ret <4 x i32> %tmp3



More information about the llvm-commits mailing list