[llvm] [AArch64] Add SVE shuffle optimization pass (PR #193951)

Sander de Smalen via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 03:05:45 PDT 2026


================
@@ -0,0 +1,602 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -O3 -mtriple=aarch64-linux-gnu -mattr=+sve < %s | FileCheck %s
+
+define void @zext_nxv8i16_to_nxv8i64_deinterleave_in_loop(ptr %src, ptr %dst, <vscale x 8 x i1> %mask) #0 {
+; CHECK-LABEL: zext_nxv8i16_to_nxv8i64_deinterleave_in_loop:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    index z7.d, #0, #4
+; CHECK-NEXT:    mov z4.d, #0xffffffffffff0000
+; CHECK-NEXT:    mov z5.d, #0xffffffffffff0001
+; CHECK-NEXT:    mov x8, #-65534 // =0xffffffffffff0002
+; CHECK-NEXT:    mov z24.d, #0xffffffffffff0003
+; CHECK-NEXT:    movi v0.2d, #0000000000000000
+; CHECK-NEXT:    mov z6.d, x8
+; CHECK-NEXT:    movi v1.2d, #0000000000000000
+; CHECK-NEXT:    mov w8, #2048 // =0x800
+; CHECK-NEXT:    movi v2.2d, #0000000000000000
+; CHECK-NEXT:    movi v3.2d, #0000000000000000
+; CHECK-NEXT:    cntd x9
+; CHECK-NEXT:    add z4.d, z7.d, z4.d
+; CHECK-NEXT:    add z5.d, z7.d, z5.d
+; CHECK-NEXT:    rdvl x10, #1
+; CHECK-NEXT:    add z6.d, z7.d, z6.d
+; CHECK-NEXT:    add z7.d, z7.d, z24.d
+; CHECK-NEXT:  .LBB0_1: // %loop
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ld1h { z24.h }, p0/z, [x0]
+; CHECK-NEXT:    subs x8, x8, x9
+; CHECK-NEXT:    add x0, x0, x10
+; CHECK-NEXT:    tbl z25.h, { z24.h }, z4.h
+; CHECK-NEXT:    tbl z26.h, { z24.h }, z5.h
+; CHECK-NEXT:    tbl z27.h, { z24.h }, z6.h
+; CHECK-NEXT:    tbl z24.h, { z24.h }, z7.h
+; CHECK-NEXT:    add z0.d, z0.d, z25.d
+; CHECK-NEXT:    add z1.d, z1.d, z26.d
+; CHECK-NEXT:    add z2.d, z2.d, z27.d
+; CHECK-NEXT:    add z3.d, z3.d, z24.d
+; CHECK-NEXT:    b.ne .LBB0_1
+; CHECK-NEXT:  // %bb.2: // %exit
+; CHECK-NEXT:    str z0, [x1]
+; CHECK-NEXT:    str z1, [x1, #1, mul vl]
+; CHECK-NEXT:    str z2, [x1, #2, mul vl]
+; CHECK-NEXT:    str z3, [x1, #3, mul vl]
+; CHECK-NEXT:    ret
+entry:
+  %vscale = tail call i64 @llvm.vscale.i64()
+  %stride = shl nuw nsw i64 %vscale, 1
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+  %acc.b.i64 = phi <vscale x 2 x i64> [ splat(i64 0), %entry ], [ %add.b.i64, %loop ]
+  %acc.g.i64 = phi <vscale x 2 x i64> [ splat(i64 0), %entry ], [ %add.g.i64, %loop ]
+  %acc.r.i64 = phi <vscale x 2 x i64> [ splat(i64 0), %entry ], [ %add.r.i64, %loop ]
+  %acc.a.i64 = phi <vscale x 2 x i64> [ splat(i64 0), %entry ], [ %add.a.i64, %loop ]
+  %src.gep = getelementptr inbounds nuw [4 x i16], ptr %src, i64 %iv
+  %bgra = call <vscale x 8 x i16> @llvm.masked.load(ptr %src.gep, <vscale x 8 x i1> %mask, <vscale x 8 x i16> zeroinitializer)
+  %deinterleave = tail call { <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16> } @llvm.vector.deinterleave4(<vscale x 8 x i16> %bgra)
+  %b.i16 = extractvalue { <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16> } %deinterleave, 0
+  %g.i16 = extractvalue { <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16> } %deinterleave, 1
+  %r.i16 = extractvalue { <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16> } %deinterleave, 2
+  %a.i16 = extractvalue { <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16>, <vscale x 2 x i16> } %deinterleave, 3
+  %b.i64 = zext <vscale x 2 x i16> %b.i16 to <vscale x 2 x i64>
+  %g.i64 = zext <vscale x 2 x i16> %g.i16 to <vscale x 2 x i64>
+  %r.i64 = zext <vscale x 2 x i16> %r.i16 to <vscale x 2 x i64>
+  %a.i64 = zext <vscale x 2 x i16> %a.i16 to <vscale x 2 x i64>
+  %add.b.i64 = add <vscale x 2 x i64> %acc.b.i64, %b.i64
+  %add.g.i64 = add <vscale x 2 x i64> %acc.g.i64, %g.i64
+  %add.r.i64 = add <vscale x 2 x i64> %acc.r.i64, %r.i64
+  %add.a.i64 = add <vscale x 2 x i64> %acc.a.i64, %a.i64
+  %iv.next = add nuw i64 %iv, %stride
+  %ec = icmp eq i64 %iv.next, 2048
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  store <vscale x 2 x i64> %add.b.i64, ptr %dst
+  %g.i64.gep = getelementptr <vscale x 2 x i64>, ptr %dst, i64 1
+  store <vscale x 2 x i64> %add.g.i64, ptr %g.i64.gep
+  %r.i64.gep = getelementptr <vscale x 2 x i64>, ptr %dst, i64 2
+  store <vscale x 2 x i64> %add.r.i64, ptr %r.i64.gep
+  %a.i64.gep = getelementptr <vscale x 2 x i64>, ptr %dst, i64 3
+  store <vscale x 2 x i64> %add.a.i64, ptr %a.i64.gep
+  ret void
+}
+
+;; TODO: Do we want to perform the sext equivalent? Requires a splat of the
----------------
sdesmalen-arm wrote:

That seems like a sensible follow-up to me, and yes it could use the two-source TBL for this case.

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


More information about the llvm-commits mailing list