[llvm] [AArch64] Improve fixed vector lowering for cttz/ctlz when sve (PR #192427)

Yashwant Singh via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 03:44:53 PDT 2026


https://github.com/yashssh created https://github.com/llvm/llvm-project/pull/192427

When available we should be able to lower fixed size 64/128 bit cttz/ctlz vector instructions using sve. Below are the performance uplifts

  +--------------+--------------+--------------+
  |   Function   | CTTZ Speedup | CTLZ Speedup |
  +--------------+--------------+--------------+
  | u8x8         |    1.33x     |    1.00x     |
  | u16x4        |    1.26x     |    1.00x     |
  | u32x2        |    1.26x     |    1.00x     |
  | u64x1        |    1.00x     |    7.00x     |
  +--------------+--------------+--------------+
  | u8x16        |    1.67x     |    1.00x     |
  | u16x8        |    1.51x     |    1.00x     |
  | u32x4        |    1.51x     |    1.00x     |
  | u64x2        |    1.26x     |    7.00x     |
  +--------------+--------------+--------------+

>From 92e6d98d1abca1563508bf0e239833e6b05543a2 Mon Sep 17 00:00:00 2001
From: Yashwant Singh <yashwants at nvidia.com>
Date: Thu, 16 Apr 2026 02:46:57 -0700
Subject: [PATCH] [AArch64] Improve fixed vector lowering for cttz/ctlz when
 sve

When available we should be able to lower fixed size 64/128 bit
cttz/ctlz vector instructions using sve. Below are the performance
uplifts

  +--------------+--------------+--------------+
  |   Function   | CTTZ Speedup | CTLZ Speedup |
  +--------------+--------------+--------------+
  | u8x8         |    1.33x     |    1.00x     |
  | u16x4        |    1.26x     |    1.00x     |
  | u32x2        |    1.26x     |    1.00x     |
  | u64x1        |    1.00x     |    7.00x     |
  +--------------+--------------+--------------+
  | u8x16        |    1.67x     |    1.00x     |
  | u16x8        |    1.51x     |    1.00x     |
  | u32x4        |    1.51x     |    1.00x     |
  | u64x2        |    1.26x     |    7.00x     |
  +--------------+--------------+--------------+
---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  12 +-
 .../AArch64/ctlz-cttz-fixed-vectors.ll        | 391 ++++++++++++++++++
 .../AArch64/sve-fixed-length-bit-counting.ll  |  48 ++-
 3 files changed, 434 insertions(+), 17 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/ctlz-cttz-fixed-vectors.ll

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 4b6b0758006af..9cae72cedaae5 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1930,6 +1930,12 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::VECREDUCE_UMIN, MVT::v2i64, Custom);
     }
 
+    for (auto VT : {MVT::v8i8, MVT::v16i8, MVT::v4i16, MVT::v8i16,
+      MVT::v2i32, MVT::v4i32, MVT::v1i64, MVT::v2i64}) {
+        setOperationAction(ISD::CTLZ, VT, Custom);
+        setOperationAction(ISD::CTTZ, VT, Custom);
+    }
+
     // NOTE: Currently this has to happen after computeRegisterProperties rather
     // than the preferred option of combining it with the addRegisterClass call.
     if (Subtarget->useSVEForFixedLengthVectors()) {
@@ -1957,9 +1963,6 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
 
       // These operations are not supported on NEON but SVE can do them.
       setOperationAction(ISD::BITREVERSE, MVT::v1i64, Custom);
-      setOperationAction(ISD::CTLZ, MVT::v1i64, Custom);
-      setOperationAction(ISD::CTLZ, MVT::v2i64, Custom);
-      setOperationAction(ISD::CTTZ, MVT::v1i64, Custom);
       setOperationAction(ISD::SMAX, MVT::v1i64, Custom);
       setOperationAction(ISD::SMAX, MVT::v2i64, Custom);
       setOperationAction(ISD::SMIN, MVT::v1i64, Custom);
@@ -1977,7 +1980,6 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
       for (auto VT : {MVT::v8i8, MVT::v16i8, MVT::v4i16, MVT::v8i16,
                       MVT::v2i32, MVT::v4i32, MVT::v2i64}) {
         setOperationAction(ISD::BITREVERSE, VT, Custom);
-        setOperationAction(ISD::CTTZ, VT, Custom);
         setOperationAction(ISD::VECREDUCE_AND, VT, Custom);
         setOperationAction(ISD::VECREDUCE_OR, VT, Custom);
         setOperationAction(ISD::VECREDUCE_XOR, VT, Custom);
@@ -12070,7 +12072,7 @@ SDValue AArch64TargetLowering::LowerCTTZ(SDValue Op, SelectionDAG &DAG) const {
   EVT VT = Op.getValueType();
   assert(VT.isScalableVector() ||
          useSVEForFixedLengthVectorVT(
-             VT, /*OverrideNEON=*/Subtarget->useSVEForFixedLengthVectors()));
+             VT, /*OverrideNEON=*/Subtarget->isSVEorStreamingSVEAvailable()));
 
   SDLoc DL(Op);
   SDValue RBIT = DAG.getNode(ISD::BITREVERSE, DL, VT, Op.getOperand(0));
diff --git a/llvm/test/CodeGen/AArch64/ctlz-cttz-fixed-vectors.ll b/llvm/test/CodeGen/AArch64/ctlz-cttz-fixed-vectors.ll
new file mode 100644
index 0000000000000..f17439e5f944a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ctlz-cttz-fixed-vectors.ll
@@ -0,0 +1,391 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+neon | FileCheck %s --check-prefix=NEON
+; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+sve  | FileCheck %s --check-prefix=SVE
+
+; ============================================================
+; CTLZ
+; ============================================================
+
+; --- 64-bit vectors ---
+
+define <8 x i8> @ctlz_v8i8(<8 x i8> %a) {
+; NEON-LABEL: ctlz_v8i8:
+; NEON:       // %bb.0:
+; NEON-NEXT:    clz v0.8b, v0.8b
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v8i8:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.b, vl8
+; SVE-NEXT:    // kill: def $d0 killed $d0 def $z0
+; SVE-NEXT:    clz z0.b, p0/m, z0.b
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false)
+  ret <8 x i8> %r
+}
+
+define <4 x i16> @ctlz_v4i16(<4 x i16> %a) {
+; NEON-LABEL: ctlz_v4i16:
+; NEON:       // %bb.0:
+; NEON-NEXT:    clz v0.4h, v0.4h
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v4i16:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.h, vl4
+; SVE-NEXT:    // kill: def $d0 killed $d0 def $z0
+; SVE-NEXT:    clz z0.h, p0/m, z0.h
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false)
+  ret <4 x i16> %r
+}
+
+define <2 x i32> @ctlz_v2i32(<2 x i32> %a) {
+; NEON-LABEL: ctlz_v2i32:
+; NEON:       // %bb.0:
+; NEON-NEXT:    clz v0.2s, v0.2s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v2i32:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.s, vl2
+; SVE-NEXT:    // kill: def $d0 killed $d0 def $z0
+; SVE-NEXT:    clz z0.s, p0/m, z0.s
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
+  ret <2 x i32> %r
+}
+
+define <1 x i64> @ctlz_v1i64(<1 x i64> %a) {
+; NEON-LABEL: ctlz_v1i64:
+; NEON:       // %bb.0:
+; NEON-NEXT:    ushr d1, d0, #1
+; NEON-NEXT:    orr v0.8b, v0.8b, v1.8b
+; NEON-NEXT:    ushr d1, d0, #2
+; NEON-NEXT:    orr v0.8b, v0.8b, v1.8b
+; NEON-NEXT:    ushr d1, d0, #4
+; NEON-NEXT:    orr v0.8b, v0.8b, v1.8b
+; NEON-NEXT:    ushr d1, d0, #8
+; NEON-NEXT:    orr v0.8b, v0.8b, v1.8b
+; NEON-NEXT:    ushr d1, d0, #16
+; NEON-NEXT:    orr v0.8b, v0.8b, v1.8b
+; NEON-NEXT:    ushr d1, d0, #32
+; NEON-NEXT:    orr v0.8b, v0.8b, v1.8b
+; NEON-NEXT:    mvn v0.8b, v0.8b
+; NEON-NEXT:    cnt v0.8b, v0.8b
+; NEON-NEXT:    uaddlp v0.4h, v0.8b
+; NEON-NEXT:    uaddlp v0.2s, v0.4h
+; NEON-NEXT:    uaddlp v0.1d, v0.2s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v1i64:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.d, vl1
+; SVE-NEXT:    // kill: def $d0 killed $d0 def $z0
+; SVE-NEXT:    clz z0.d, p0/m, z0.d
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <1 x i64> @llvm.ctlz.v1i64(<1 x i64> %a, i1 false)
+  ret <1 x i64> %r
+}
+
+; --- 128-bit vectors ---
+
+define <16 x i8> @ctlz_v16i8(<16 x i8> %a) {
+; NEON-LABEL: ctlz_v16i8:
+; NEON:       // %bb.0:
+; NEON-NEXT:    clz v0.16b, v0.16b
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v16i8:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.b, vl16
+; SVE-NEXT:    // kill: def $q0 killed $q0 def $z0
+; SVE-NEXT:    clz z0.b, p0/m, z0.b
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false)
+  ret <16 x i8> %r
+}
+
+define <8 x i16> @ctlz_v8i16(<8 x i16> %a) {
+; NEON-LABEL: ctlz_v8i16:
+; NEON:       // %bb.0:
+; NEON-NEXT:    clz v0.8h, v0.8h
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v8i16:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.h, vl8
+; SVE-NEXT:    // kill: def $q0 killed $q0 def $z0
+; SVE-NEXT:    clz z0.h, p0/m, z0.h
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false)
+  ret <8 x i16> %r
+}
+
+define <4 x i32> @ctlz_v4i32(<4 x i32> %a) {
+; NEON-LABEL: ctlz_v4i32:
+; NEON:       // %bb.0:
+; NEON-NEXT:    clz v0.4s, v0.4s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v4i32:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.s, vl4
+; SVE-NEXT:    // kill: def $q0 killed $q0 def $z0
+; SVE-NEXT:    clz z0.s, p0/m, z0.s
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false)
+  ret <4 x i32> %r
+}
+
+define <2 x i64> @ctlz_v2i64(<2 x i64> %a) {
+; NEON-LABEL: ctlz_v2i64:
+; NEON:       // %bb.0:
+; NEON-NEXT:    ushr v1.2d, v0.2d, #1
+; NEON-NEXT:    orr v0.16b, v0.16b, v1.16b
+; NEON-NEXT:    ushr v1.2d, v0.2d, #2
+; NEON-NEXT:    orr v0.16b, v0.16b, v1.16b
+; NEON-NEXT:    ushr v1.2d, v0.2d, #4
+; NEON-NEXT:    orr v0.16b, v0.16b, v1.16b
+; NEON-NEXT:    ushr v1.2d, v0.2d, #8
+; NEON-NEXT:    orr v0.16b, v0.16b, v1.16b
+; NEON-NEXT:    ushr v1.2d, v0.2d, #16
+; NEON-NEXT:    orr v0.16b, v0.16b, v1.16b
+; NEON-NEXT:    ushr v1.2d, v0.2d, #32
+; NEON-NEXT:    orr v0.16b, v0.16b, v1.16b
+; NEON-NEXT:    mvn v0.16b, v0.16b
+; NEON-NEXT:    cnt v0.16b, v0.16b
+; NEON-NEXT:    uaddlp v0.8h, v0.16b
+; NEON-NEXT:    uaddlp v0.4s, v0.8h
+; NEON-NEXT:    uaddlp v0.2d, v0.4s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: ctlz_v2i64:
+; SVE:       // %bb.0:
+; SVE-NEXT:    ptrue p0.d, vl2
+; SVE-NEXT:    // kill: def $q0 killed $q0 def $z0
+; SVE-NEXT:    clz z0.d, p0/m, z0.d
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %a, i1 false)
+  ret <2 x i64> %r
+}
+
+; ============================================================
+; CTTZ
+; ============================================================
+
+; --- 64-bit vectors ---
+
+define <8 x i8> @cttz_v8i8(<8 x i8> %a) {
+; NEON-LABEL: cttz_v8i8:
+; NEON:       // %bb.0:
+; NEON-NEXT:    movi v1.8b, #1
+; NEON-NEXT:    sub v1.8b, v0.8b, v1.8b
+; NEON-NEXT:    bic v0.8b, v1.8b, v0.8b
+; NEON-NEXT:    cnt v0.8b, v0.8b
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v8i8:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rbit v0.8b, v0.8b
+; SVE-NEXT:    ptrue p0.b, vl8
+; SVE-NEXT:    clz z0.b, p0/m, z0.b
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <8 x i8> @llvm.cttz.v8i8(<8 x i8> %a, i1 false)
+  ret <8 x i8> %r
+}
+
+define <4 x i16> @cttz_v4i16(<4 x i16> %a) {
+; NEON-LABEL: cttz_v4i16:
+; NEON:       // %bb.0:
+; NEON-NEXT:    movi v1.4h, #1
+; NEON-NEXT:    sub v1.4h, v0.4h, v1.4h
+; NEON-NEXT:    bic v0.8b, v1.8b, v0.8b
+; NEON-NEXT:    movi v1.4h, #16
+; NEON-NEXT:    clz v0.4h, v0.4h
+; NEON-NEXT:    sub v0.4h, v1.4h, v0.4h
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v4i16:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rev16 v0.8b, v0.8b
+; SVE-NEXT:    ptrue p0.h, vl4
+; SVE-NEXT:    rbit v0.8b, v0.8b
+; SVE-NEXT:    clz z0.h, p0/m, z0.h
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <4 x i16> @llvm.cttz.v4i16(<4 x i16> %a, i1 false)
+  ret <4 x i16> %r
+}
+
+define <2 x i32> @cttz_v2i32(<2 x i32> %a) {
+; NEON-LABEL: cttz_v2i32:
+; NEON:       // %bb.0:
+; NEON-NEXT:    movi v1.2s, #1
+; NEON-NEXT:    sub v1.2s, v0.2s, v1.2s
+; NEON-NEXT:    bic v0.8b, v1.8b, v0.8b
+; NEON-NEXT:    movi v1.2s, #32
+; NEON-NEXT:    clz v0.2s, v0.2s
+; NEON-NEXT:    sub v0.2s, v1.2s, v0.2s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v2i32:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rev32 v0.8b, v0.8b
+; SVE-NEXT:    ptrue p0.s, vl2
+; SVE-NEXT:    rbit v0.8b, v0.8b
+; SVE-NEXT:    clz z0.s, p0/m, z0.s
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %a, i1 false)
+  ret <2 x i32> %r
+}
+
+define <1 x i64> @cttz_v1i64(<1 x i64> %a) {
+; NEON-LABEL: cttz_v1i64:
+; NEON:       // %bb.0:
+; NEON-NEXT:    mov w8, #1 // =0x1
+; NEON-NEXT:    fmov d1, x8
+; NEON-NEXT:    sub d1, d0, d1
+; NEON-NEXT:    bic v0.8b, v1.8b, v0.8b
+; NEON-NEXT:    cnt v0.8b, v0.8b
+; NEON-NEXT:    uaddlp v0.4h, v0.8b
+; NEON-NEXT:    uaddlp v0.2s, v0.4h
+; NEON-NEXT:    uaddlp v0.1d, v0.2s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v1i64:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rev64 v0.8b, v0.8b
+; SVE-NEXT:    ptrue p0.d, vl1
+; SVE-NEXT:    rbit v0.8b, v0.8b
+; SVE-NEXT:    clz z0.d, p0/m, z0.d
+; SVE-NEXT:    // kill: def $d0 killed $d0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <1 x i64> @llvm.cttz.v1i64(<1 x i64> %a, i1 false)
+  ret <1 x i64> %r
+}
+
+; --- 128-bit vectors ---
+
+define <16 x i8> @cttz_v16i8(<16 x i8> %a) {
+; NEON-LABEL: cttz_v16i8:
+; NEON:       // %bb.0:
+; NEON-NEXT:    movi v1.16b, #1
+; NEON-NEXT:    sub v1.16b, v0.16b, v1.16b
+; NEON-NEXT:    bic v0.16b, v1.16b, v0.16b
+; NEON-NEXT:    cnt v0.16b, v0.16b
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v16i8:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rbit v0.16b, v0.16b
+; SVE-NEXT:    ptrue p0.b, vl16
+; SVE-NEXT:    clz z0.b, p0/m, z0.b
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <16 x i8> @llvm.cttz.v16i8(<16 x i8> %a, i1 false)
+  ret <16 x i8> %r
+}
+
+define <8 x i16> @cttz_v8i16(<8 x i16> %a) {
+; NEON-LABEL: cttz_v8i16:
+; NEON:       // %bb.0:
+; NEON-NEXT:    movi v1.8h, #1
+; NEON-NEXT:    sub v1.8h, v0.8h, v1.8h
+; NEON-NEXT:    bic v0.16b, v1.16b, v0.16b
+; NEON-NEXT:    movi v1.8h, #16
+; NEON-NEXT:    clz v0.8h, v0.8h
+; NEON-NEXT:    sub v0.8h, v1.8h, v0.8h
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v8i16:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rev16 v0.16b, v0.16b
+; SVE-NEXT:    ptrue p0.h, vl8
+; SVE-NEXT:    rbit v0.16b, v0.16b
+; SVE-NEXT:    clz z0.h, p0/m, z0.h
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <8 x i16> @llvm.cttz.v8i16(<8 x i16> %a, i1 false)
+  ret <8 x i16> %r
+}
+
+define <4 x i32> @cttz_v4i32(<4 x i32> %a) {
+; NEON-LABEL: cttz_v4i32:
+; NEON:       // %bb.0:
+; NEON-NEXT:    movi v1.4s, #1
+; NEON-NEXT:    sub v1.4s, v0.4s, v1.4s
+; NEON-NEXT:    bic v0.16b, v1.16b, v0.16b
+; NEON-NEXT:    movi v1.4s, #32
+; NEON-NEXT:    clz v0.4s, v0.4s
+; NEON-NEXT:    sub v0.4s, v1.4s, v0.4s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v4i32:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rev32 v0.16b, v0.16b
+; SVE-NEXT:    ptrue p0.s, vl4
+; SVE-NEXT:    rbit v0.16b, v0.16b
+; SVE-NEXT:    clz z0.s, p0/m, z0.s
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <4 x i32> @llvm.cttz.v4i32(<4 x i32> %a, i1 false)
+  ret <4 x i32> %r
+}
+
+define <2 x i64> @cttz_v2i64(<2 x i64> %a) {
+; NEON-LABEL: cttz_v2i64:
+; NEON:       // %bb.0:
+; NEON-NEXT:    mov w8, #1 // =0x1
+; NEON-NEXT:    dup v1.2d, x8
+; NEON-NEXT:    sub v1.2d, v0.2d, v1.2d
+; NEON-NEXT:    bic v0.16b, v1.16b, v0.16b
+; NEON-NEXT:    cnt v0.16b, v0.16b
+; NEON-NEXT:    uaddlp v0.8h, v0.16b
+; NEON-NEXT:    uaddlp v0.4s, v0.8h
+; NEON-NEXT:    uaddlp v0.2d, v0.4s
+; NEON-NEXT:    ret
+;
+; SVE-LABEL: cttz_v2i64:
+; SVE:       // %bb.0:
+; SVE-NEXT:    rev64 v0.16b, v0.16b
+; SVE-NEXT:    ptrue p0.d, vl2
+; SVE-NEXT:    rbit v0.16b, v0.16b
+; SVE-NEXT:    clz z0.d, p0/m, z0.d
+; SVE-NEXT:    // kill: def $q0 killed $q0 killed $z0
+; SVE-NEXT:    ret
+  %r = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> %a, i1 false)
+  ret <2 x i64> %r
+}
+
+; ============================================================
+; Declare intrinsics
+; ============================================================
+
+declare <8 x i8>   @llvm.ctlz.v8i8 (<8 x i8>,   i1)
+declare <4 x i16>  @llvm.ctlz.v4i16(<4 x i16>,  i1)
+declare <2 x i32>  @llvm.ctlz.v2i32(<2 x i32>,  i1)
+declare <1 x i64>  @llvm.ctlz.v1i64(<1 x i64>,  i1)
+declare <16 x i8>  @llvm.ctlz.v16i8 (<16 x i8>, i1)
+declare <8 x i16>  @llvm.ctlz.v8i16(<8 x i16>,  i1)
+declare <4 x i32>  @llvm.ctlz.v4i32(<4 x i32>,  i1)
+declare <2 x i64>  @llvm.ctlz.v2i64(<2 x i64>,  i1)
+
+declare <8 x i8>   @llvm.cttz.v8i8 (<8 x i8>,   i1)
+declare <4 x i16>  @llvm.cttz.v4i16(<4 x i16>,  i1)
+declare <2 x i32>  @llvm.cttz.v2i32(<2 x i32>,  i1)
+declare <1 x i64>  @llvm.cttz.v1i64(<1 x i64>,  i1)
+declare <16 x i8>  @llvm.cttz.v16i8 (<16 x i8>, i1)
+declare <8 x i16>  @llvm.cttz.v8i16(<8 x i16>,  i1)
+declare <4 x i32>  @llvm.cttz.v4i32(<4 x i32>,  i1)
+declare <2 x i64>  @llvm.cttz.v2i64(<2 x i64>,  i1)
diff --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-bit-counting.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-bit-counting.ll
index b62b850434469..ef3c5d1dac26e 100644
--- a/llvm/test/CodeGen/AArch64/sve-fixed-length-bit-counting.ll
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-bit-counting.ll
@@ -13,7 +13,10 @@ target triple = "aarch64-unknown-linux-gnu"
 define <8 x i8> @ctlz_v8i8(<8 x i8> %op) vscale_range(2,0) #0 {
 ; CHECK-LABEL: ctlz_v8i8:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    clz v0.8b, v0.8b
+; CHECK-NEXT:    ptrue p0.b, vl8
+; CHECK-NEXT:    // kill: def $d0 killed $d0 def $z0
+; CHECK-NEXT:    clz z0.b, p0/m, z0.b
+; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %op)
   ret <8 x i8> %res
@@ -23,7 +26,10 @@ define <8 x i8> @ctlz_v8i8(<8 x i8> %op) vscale_range(2,0) #0 {
 define <16 x i8> @ctlz_v16i8(<16 x i8> %op) vscale_range(2,0) #0 {
 ; CHECK-LABEL: ctlz_v16i8:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    clz v0.16b, v0.16b
+; CHECK-NEXT:    ptrue p0.b, vl16
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    clz z0.b, p0/m, z0.b
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %op)
   ret <16 x i8> %res
@@ -101,7 +107,10 @@ define void @ctlz_v256i8(ptr %a) vscale_range(16,0) #0 {
 define <4 x i16> @ctlz_v4i16(<4 x i16> %op) vscale_range(2,0) #0 {
 ; CHECK-LABEL: ctlz_v4i16:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    clz v0.4h, v0.4h
+; CHECK-NEXT:    ptrue p0.h, vl4
+; CHECK-NEXT:    // kill: def $d0 killed $d0 def $z0
+; CHECK-NEXT:    clz z0.h, p0/m, z0.h
+; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %op)
   ret <4 x i16> %res
@@ -111,7 +120,10 @@ define <4 x i16> @ctlz_v4i16(<4 x i16> %op) vscale_range(2,0) #0 {
 define <8 x i16> @ctlz_v8i16(<8 x i16> %op) vscale_range(2,0) #0 {
 ; CHECK-LABEL: ctlz_v8i16:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    clz v0.8h, v0.8h
+; CHECK-NEXT:    ptrue p0.h, vl8
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    clz z0.h, p0/m, z0.h
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %op)
   ret <8 x i16> %res
@@ -189,7 +201,10 @@ define void @ctlz_v128i16(ptr %a) vscale_range(16,0) #0 {
 define <2 x i32> @ctlz_v2i32(<2 x i32> %op) vscale_range(2,0) #0 {
 ; CHECK-LABEL: ctlz_v2i32:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    clz v0.2s, v0.2s
+; CHECK-NEXT:    ptrue p0.s, vl2
+; CHECK-NEXT:    // kill: def $d0 killed $d0 def $z0
+; CHECK-NEXT:    clz z0.s, p0/m, z0.s
+; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %op)
   ret <2 x i32> %res
@@ -199,7 +214,10 @@ define <2 x i32> @ctlz_v2i32(<2 x i32> %op) vscale_range(2,0) #0 {
 define <4 x i32> @ctlz_v4i32(<4 x i32> %op) vscale_range(2,0) #0 {
 ; CHECK-LABEL: ctlz_v4i32:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    clz v0.4s, v0.4s
+; CHECK-NEXT:    ptrue p0.s, vl4
+; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
+; CHECK-NEXT:    clz z0.s, p0/m, z0.s
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %op)
   ret <4 x i32> %res
@@ -743,7 +761,8 @@ define <8 x i8> @cttz_v8i8(<8 x i8> %op) vscale_range(2,0) #0 {
 ; CHECK-NEXT:    ptrue p0.b, vl8
 ; CHECK-NEXT:    // kill: def $d0 killed $d0 def $z0
 ; CHECK-NEXT:    rbit z0.b, p0/m, z0.b
-; CHECK-NEXT:    clz v0.8b, v0.8b
+; CHECK-NEXT:    clz z0.b, p0/m, z0.b
+; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <8 x i8> @llvm.cttz.v8i8(<8 x i8> %op)
   ret <8 x i8> %res
@@ -755,7 +774,8 @@ define <16 x i8> @cttz_v16i8(<16 x i8> %op) vscale_range(2,0) #0 {
 ; CHECK-NEXT:    ptrue p0.b, vl16
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
 ; CHECK-NEXT:    rbit z0.b, p0/m, z0.b
-; CHECK-NEXT:    clz v0.16b, v0.16b
+; CHECK-NEXT:    clz z0.b, p0/m, z0.b
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <16 x i8> @llvm.cttz.v16i8(<16 x i8> %op)
   ret <16 x i8> %res
@@ -841,7 +861,8 @@ define <4 x i16> @cttz_v4i16(<4 x i16> %op) vscale_range(2,0) #0 {
 ; CHECK-NEXT:    ptrue p0.h, vl4
 ; CHECK-NEXT:    // kill: def $d0 killed $d0 def $z0
 ; CHECK-NEXT:    rbit z0.h, p0/m, z0.h
-; CHECK-NEXT:    clz v0.4h, v0.4h
+; CHECK-NEXT:    clz z0.h, p0/m, z0.h
+; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <4 x i16> @llvm.cttz.v4i16(<4 x i16> %op)
   ret <4 x i16> %res
@@ -853,7 +874,8 @@ define <8 x i16> @cttz_v8i16(<8 x i16> %op) vscale_range(2,0) #0 {
 ; CHECK-NEXT:    ptrue p0.h, vl8
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
 ; CHECK-NEXT:    rbit z0.h, p0/m, z0.h
-; CHECK-NEXT:    clz v0.8h, v0.8h
+; CHECK-NEXT:    clz z0.h, p0/m, z0.h
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <8 x i16> @llvm.cttz.v8i16(<8 x i16> %op)
   ret <8 x i16> %res
@@ -940,7 +962,8 @@ define <2 x i32> @cttz_v2i32(<2 x i32> %op) vscale_range(2,0) #0 {
 ; CHECK-NEXT:    ptrue p0.s, vl2
 ; CHECK-NEXT:    // kill: def $d0 killed $d0 def $z0
 ; CHECK-NEXT:    rbit z0.s, p0/m, z0.s
-; CHECK-NEXT:    clz v0.2s, v0.2s
+; CHECK-NEXT:    clz z0.s, p0/m, z0.s
+; CHECK-NEXT:    // kill: def $d0 killed $d0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> %op)
   ret <2 x i32> %res
@@ -953,7 +976,8 @@ define <4 x i32> @cttz_v4i32(<4 x i32> %op) vscale_range(2,0) #0 {
 ; CHECK-NEXT:    ptrue p0.s, vl4
 ; CHECK-NEXT:    // kill: def $q0 killed $q0 def $z0
 ; CHECK-NEXT:    rbit z0.s, p0/m, z0.s
-; CHECK-NEXT:    clz v0.4s, v0.4s
+; CHECK-NEXT:    clz z0.s, p0/m, z0.s
+; CHECK-NEXT:    // kill: def $q0 killed $q0 killed $z0
 ; CHECK-NEXT:    ret
   %res = call <4 x i32> @llvm.cttz.v4i32(<4 x i32> %op)
   ret <4 x i32> %res



More information about the llvm-commits mailing list