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

Ricardo Jesus via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 03:50:20 PDT 2026


================
@@ -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)
----------------
rj-jesus wrote:

I think you don't need these anymore.

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


More information about the llvm-commits mailing list