[llvm] [AArch64] SVE Shuffleopt: merge reduction reverse into tbl (PR #206047)

Gaƫtan Bossu via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 07:29:26 PDT 2026


================
@@ -638,5 +638,454 @@ exit:
   ret void
 }
 
+define void @uitofp_nxv8i16_to_nxv8f64_deinterleave_fma_with_reverse_double(ptr %src, ptr %src2, ptr %dst, <vscale x 8 x i1> %mask) #0 {
+; CHECK-LABEL: uitofp_nxv8i16_to_nxv8f64_deinterleave_fma_with_reverse_double:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    index z7.d, #0, #-4
+; CHECK-NEXT:    mov x9, #-4 // =0xfffffffffffffffc
+; CHECK-NEXT:    mov x10, #-3 // =0xfffffffffffffffd
+; CHECK-NEXT:    movk x9, #65534, lsl #16
+; CHECK-NEXT:    movk x10, #65534, lsl #16
+; CHECK-NEXT:    mov z24.d, #0xfffffffffffeffff
+; CHECK-NEXT:    mov z4.d, x9
+; CHECK-NEXT:    mov x9, #-2 // =0xfffffffffffffffe
+; CHECK-NEXT:    mov z5.d, x10
+; CHECK-NEXT:    movk x9, #65534, lsl #16
+; CHECK-NEXT:    movi v0.2d, #0000000000000000
+; CHECK-NEXT:    movi v3.2d, #0000000000000000
+; CHECK-NEXT:    incd z7.d
+; CHECK-NEXT:    mov z6.d, x9
+; CHECK-NEXT:    movi v2.2d, #0000000000000000
+; CHECK-NEXT:    movi v1.2d, #0000000000000000
+; CHECK-NEXT:    ptrue p1.d
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    add x9, x1, #8
+; CHECK-NEXT:    cntw x10
+; CHECK-NEXT:    rdvl x11, #2
+; CHECK-NEXT:    add z4.d, z7.d, z4.d
+; CHECK-NEXT:    add z5.d, z7.d, z5.d
+; CHECK-NEXT:    add z6.d, z7.d, z6.d
+; CHECK-NEXT:    add z7.d, z7.d, z24.d
+; CHECK-NEXT:  .LBB8_1: // %loop
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ld1h { z24.h }, p0/z, [x0]
+; CHECK-NEXT:    ld1d { z28.d }, p1/z, [x9, x8, lsl #3]
+; CHECK-NEXT:    sub x8, x8, x10
+; CHECK-NEXT:    cmn x8, #2048
+; CHECK-NEXT:    add x0, x0, x11
+; 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:    ucvtf z25.d, p1/m, z25.d
+; CHECK-NEXT:    ucvtf z26.d, p1/m, z26.d
+; CHECK-NEXT:    ucvtf z27.d, p1/m, z27.d
+; CHECK-NEXT:    ucvtf z24.d, p1/m, z24.d
+; CHECK-NEXT:    fmul z25.d, z25.d, z28.d
+; CHECK-NEXT:    fmul z26.d, z26.d, z28.d
+; CHECK-NEXT:    fmul z27.d, z27.d, z28.d
+; CHECK-NEXT:    fmul z24.d, z24.d, z28.d
+; CHECK-NEXT:    fadd z0.d, z0.d, z25.d
+; CHECK-NEXT:    fadd z3.d, z3.d, z26.d
+; CHECK-NEXT:    fadd z2.d, z2.d, z27.d
+; CHECK-NEXT:    fadd z1.d, z1.d, z24.d
+; CHECK-NEXT:    b.ne .LBB8_1
+; CHECK-NEXT:  // %bb.2: // %exit
+; CHECK-NEXT:    faddv d0, p1, z0.d
+; CHECK-NEXT:    faddv d3, p1, z3.d
+; CHECK-NEXT:    faddv d2, p1, z2.d
+; CHECK-NEXT:    faddv d1, p1, z1.d
+; CHECK-NEXT:    mov v0.d[1], v3.d[0]
+; CHECK-NEXT:    mov v2.d[1], v1.d[0]
+; CHECK-NEXT:    stp q0, q2, [x2]
+; CHECK-NEXT:    ret
+entry:
+  %vscale = tail call i64 @llvm.vscale.i64()
+  %stride = shl nuw nsw i64 %vscale, 2
+  %common.base = getelementptr double, ptr %src2, i64 1
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+  %acc.b.f64 = phi <vscale x 2 x double> [ splat(double 0.000000e+00), %entry ], [ %fadd.b.f64, %loop ]
+  %acc.g.f64 = phi <vscale x 2 x double> [ splat(double 0.000000e+00), %entry ], [ %fadd.g.f64, %loop ]
+  %acc.r.f64 = phi <vscale x 2 x double> [ splat(double 0.000000e+00), %entry ], [ %fadd.r.f64, %loop ]
+  %acc.a.f64 = phi <vscale x 2 x double> [ splat(double 0.000000e+00), %entry ], [ %fadd.a.f64, %loop ]
+  %negated = mul i64 %iv, -1
+  %common.term.ptr = getelementptr inbounds nuw double, ptr %common.base, i64 %negated
+  %common.term = load <vscale x 2 x double>, ptr %common.term.ptr, align 8
+  %reversed = call <vscale x 2 x double> @llvm.vector.reverse.nxv2f64(<vscale x 2 x double> %common.term)
+  %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.f64 = uitofp <vscale x 2 x i16> %b.i16 to <vscale x 2 x double>
+  %g.f64 = uitofp <vscale x 2 x i16> %g.i16 to <vscale x 2 x double>
+  %r.f64 = uitofp <vscale x 2 x i16> %r.i16 to <vscale x 2 x double>
+  %a.f64 = uitofp <vscale x 2 x i16> %a.i16 to <vscale x 2 x double>
+  %b.mul.f64 = fmul <vscale x 2 x double> %b.f64, %reversed
+  %g.mul.f64 = fmul <vscale x 2 x double> %g.f64, %reversed
+  %r.mul.f64 = fmul <vscale x 2 x double> %r.f64, %reversed
+  %a.mul.f64 = fmul <vscale x 2 x double> %a.f64, %reversed
+  %fadd.b.f64 = fadd <vscale x 2 x double> %acc.b.f64, %b.mul.f64
+  %fadd.g.f64 = fadd <vscale x 2 x double> %acc.g.f64, %g.mul.f64
+  %fadd.r.f64 = fadd <vscale x 2 x double> %acc.r.f64, %r.mul.f64
+  %fadd.a.f64 = fadd <vscale x 2 x double> %acc.a.f64, %a.mul.f64
+  %iv.next = add nuw i64 %iv, %stride
+  %ec = icmp eq i64 %iv.next, 2048
+  br i1 %ec, label %exit, label %loop
----------------
gbossu wrote:

Ah I didn't realise that we used the deinterleave + extend as a source of tbl. In theory we could use a shufflevector as well to avoid using deinterleaving? Or maybe use 2-way deinterleaving to make the tests easier to read?

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


More information about the llvm-commits mailing list