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

Joshua Rodriguez via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 3 03:35:08 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/6] [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/6] [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/6] [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

>From 83e577b07802785de8707050c8a84f62287b7f5d Mon Sep 17 00:00:00 2001
From: Joshua Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 2 Jun 2026 17:36:24 +0100
Subject: [PATCH 4/6] [AArch64] Remove newline

Removed an empty line in the AArch64InstrGISel.td file.
---
 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 9c646c43cdcbf..ec95448f61043 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>;
 
-
 // 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)))),

>From b43f5b7bec7177a995329aff4d7aefe793e09132 Mon Sep 17 00:00:00 2001
From: Joshua Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 2 Jun 2026 17:39:32 +0100
Subject: [PATCH 5/6] [AArch64][GlobalISel] Remove -global-isel-fallback from
 test line

As there are now no functions in this file that fallback to SDAG, remove the flag allowing fallbacks.
This means that if a change causes one of these function's code generation to fallback to SDAG, the test will fail.
---
 llvm/test/CodeGen/AArch64/arm64-vcvt.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/AArch64/arm64-vcvt.ll b/llvm/test/CodeGen/AArch64/arm64-vcvt.ll
index 7f6b16d3ccbb4..c9644c381b73d 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vcvt.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vcvt.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple -global-isel 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
 define <2 x i32> @fcvtas_2s(<2 x float> %A) nounwind {
 ; CHECK-LABEL: fcvtas_2s:

>From 98f121a9762add5390b1de6948273b2cd624ef4d Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Wed, 3 Jun 2026 10:34:44 +0000
Subject: [PATCH 6/6] [AArch64][GlobalISel] Remove -global-isel-fallback from
 correct test file

Previous commit removed the -global-isel-fallback flag from the wrong test (typo in file name). Fix this by re-adding the flag into the wrong file, and removing it from the correct one.
---
 llvm/test/CodeGen/AArch64/arm64-vcnt.ll | 2 +-
 llvm/test/CodeGen/AArch64/arm64-vcvt.ll | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/arm64-vcnt.ll b/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
index 6e4d5d5fe418b..0bd34eb91079b 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vcnt.ll
@@ -1,6 +1,6 @@
 ; 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
+; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple -global-isel | FileCheck %s
 
 define <8 x i8> @cls_8b(ptr %A) nounwind {
 ; CHECK-LABEL: cls_8b:
diff --git a/llvm/test/CodeGen/AArch64/arm64-vcvt.ll b/llvm/test/CodeGen/AArch64/arm64-vcvt.ll
index c9644c381b73d..7f6b16d3ccbb4 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vcvt.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vcvt.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple -global-isel 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
 define <2 x i32> @fcvtas_2s(<2 x float> %A) nounwind {
 ; CHECK-LABEL: fcvtas_2s:



More information about the llvm-commits mailing list