[llvm] [AArch64] Avoid ld4 lowering for deinterleave4 feeding uitofp (PR #200763)
Kamlesh Kumar via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 1 02:25:51 PDT 2026
https://github.com/kamleshbhalui updated https://github.com/llvm/llvm-project/pull/200763
>From 02f1a3fa2e332e1e81a4490b98a4067769867e89 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Fri, 29 May 2026 08:23:24 +0000
Subject: [PATCH] [AArch64] Avoid ld4 lowering for deinterleave4 feeding uitofp
When a fixed-width vector.deinterleave4 load has all extracted results consumed
by widening uitofp operations, the existing shuffle-based lowering produces
better code than lowering through structured ld4.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 54 ++++++
.../aarch64-deinterleave4-i16-to-fp64.ll | 158 +++++++++++++++
.../aarch64-deinterleave4-i8-to-fp32.ll | 183 ++++++++++++++++++
3 files changed, 395 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i16-to-fp64.ll
create mode 100644 llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i8-to-fp32.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index aa137b8f675af..59c0440ffb7d0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -19011,6 +19011,53 @@ bool AArch64TargetLowering::lowerInterleavedStore(Instruction *Store,
return true;
}
+static bool hasSingleWideningUIToFPUse(Value *V) {
+ using namespace llvm::PatternMatch;
+ if (!V->hasOneUse())
+ return false;
+ auto *UserInst = dyn_cast<Instruction>(V->user_back());
+ return UserInst && match(UserInst, m_UIToFP(m_Specific(V))) &&
+ V->getType()->getScalarSizeInBits() * 4 ==
+ UserInst->getType()->getScalarSizeInBits();
+}
+
+static bool areAllDeinterleaveUsersWideningUIToFP(IntrinsicInst *DI,
+ VectorType *VTy) {
+ return all_of(DI->users(), [VTy](User *U) {
+ auto *EV = dyn_cast<ExtractValueInst>(U);
+ return EV && EV->getType() == VTy && hasSingleWideningUIToFPUse(EV);
+ });
+}
+
+static bool tryLowerDeinterleave4UIToFPLoadToShuffle(LoadInst *LI,
+ IntrinsicInst *DI,
+ VectorType *VTy) {
+ if (!areAllDeinterleaveUsersWideningUIToFP(DI, VTy))
+ return false;
+
+ constexpr unsigned Factor = 4;
+ auto *FVTy = cast<FixedVectorType>(VTy);
+ unsigned SubElts = FVTy->getNumElements();
+ unsigned WideElts = SubElts * Factor;
+ auto *WideTy = FixedVectorType::get(FVTy->getElementType(), WideElts);
+ assert(LI->getType() == WideTy &&
+ "Unexpected load type for deinterleave intrinsic");
+
+ IRBuilder<> Builder(LI);
+ LoadInst *ClonedLI = cast<LoadInst>(LI->clone());
+ Builder.Insert(ClonedLI);
+ Value *Result = PoisonValue::get(DI->getType());
+ for (unsigned I = 0; I < Factor; ++I) {
+ SmallVector<int, 16> Mask(SubElts);
+ for (unsigned J = 0; J < SubElts; ++J)
+ Mask[J] = I + J * Factor;
+ Value *Shuf = Builder.CreateShuffleVector(ClonedLI, Mask);
+ Result = Builder.CreateInsertValue(Result, Shuf, I);
+ }
+ DI->replaceAllUsesWith(Result);
+ return true;
+}
+
bool AArch64TargetLowering::lowerDeinterleaveIntrinsicToLoad(
Instruction *Load, Value *Mask, IntrinsicInst *DI,
const APInt &GapMask) const {
@@ -19041,6 +19088,13 @@ bool AArch64TargetLowering::lowerDeinterleaveIntrinsicToLoad(
if (UseScalable && !VTy->isScalableTy())
return false;
+ // When all deinterleaved results feed into uitofp,
+ // Convert the deinterleaved intrinsic load to wider load + shuffle
+ // to benefit from existing shufflevector optimizations.
+ if (Factor == 4 && !VTy->isScalableTy() &&
+ tryLowerDeinterleave4UIToFPLoadToShuffle(LI, DI, VTy))
+ return true;
+
unsigned NumLoads = getNumInterleavedAccesses(VTy, DL, UseScalable);
VectorType *LdTy =
VectorType::get(VTy->getElementType(),
diff --git a/llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i16-to-fp64.ll b/llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i16-to-fp64.ll
new file mode 100644
index 0000000000000..32d85cdbf3745
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i16-to-fp64.ll
@@ -0,0 +1,158 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple aarch64-none-linux-gnu -mattr=+sve | FileCheck %s
+
+
+define <8 x double> @uitofp_fadd_02(ptr %p) {
+; CHECK-LABEL: uitofp_fadd_02:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q3, q2, [x0]
+; CHECK-NEXT: ldp q1, q0, [x0, #32]
+; CHECK-NEXT: ushr v5.2d, v3.2d, #16
+; CHECK-NEXT: ushr v6.2d, v2.2d, #16
+; CHECK-NEXT: ushr v20.2d, v3.2d, #32
+; CHECK-NEXT: ushr v7.2d, v1.2d, #16
+; CHECK-NEXT: ushr v19.2d, v0.2d, #16
+; CHECK-NEXT: ushr v21.2d, v2.2d, #32
+; CHECK-NEXT: ushr v22.2d, v1.2d, #32
+; CHECK-NEXT: ushr v23.2d, v0.2d, #32
+; CHECK-NEXT: movprfx z4, z3
+; CHECK-NEXT: and z4.d, z4.d, #0xffff
+; CHECK-NEXT: movprfx z16, z2
+; CHECK-NEXT: and z16.d, z16.d, #0xffff
+; CHECK-NEXT: movprfx z17, z1
+; CHECK-NEXT: and z17.d, z17.d, #0xffff
+; CHECK-NEXT: movprfx z18, z0
+; CHECK-NEXT: and z18.d, z18.d, #0xffff
+; CHECK-NEXT: and z5.d, z5.d, #0xffff
+; CHECK-NEXT: and z6.d, z6.d, #0xffff
+; CHECK-NEXT: and z7.d, z7.d, #0xffff
+; CHECK-NEXT: and z19.d, z19.d, #0xffff
+; CHECK-NEXT: and z20.d, z20.d, #0xffff
+; CHECK-NEXT: and z21.d, z21.d, #0xffff
+; CHECK-NEXT: and z22.d, z22.d, #0xffff
+; CHECK-NEXT: and z23.d, z23.d, #0xffff
+; CHECK-NEXT: ushr v3.2d, v3.2d, #48
+; CHECK-NEXT: ushr v2.2d, v2.2d, #48
+; CHECK-NEXT: ushr v1.2d, v1.2d, #48
+; CHECK-NEXT: ushr v0.2d, v0.2d, #48
+; CHECK-NEXT: ucvtf v4.2d, v4.2d
+; CHECK-NEXT: ucvtf v16.2d, v16.2d
+; CHECK-NEXT: ucvtf v17.2d, v17.2d
+; CHECK-NEXT: ucvtf v18.2d, v18.2d
+; CHECK-NEXT: ucvtf v5.2d, v5.2d
+; CHECK-NEXT: ucvtf v6.2d, v6.2d
+; CHECK-NEXT: ucvtf v7.2d, v7.2d
+; CHECK-NEXT: ucvtf v19.2d, v19.2d
+; CHECK-NEXT: ucvtf v20.2d, v20.2d
+; CHECK-NEXT: ucvtf v21.2d, v21.2d
+; CHECK-NEXT: ucvtf v22.2d, v22.2d
+; CHECK-NEXT: ucvtf v23.2d, v23.2d
+; CHECK-NEXT: ucvtf v3.2d, v3.2d
+; CHECK-NEXT: ucvtf v2.2d, v2.2d
+; CHECK-NEXT: ucvtf v1.2d, v1.2d
+; CHECK-NEXT: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: fadd v6.2d, v16.2d, v6.2d
+; CHECK-NEXT: fadd v4.2d, v4.2d, v5.2d
+; CHECK-NEXT: fadd v18.2d, v18.2d, v19.2d
+; CHECK-NEXT: fadd v7.2d, v17.2d, v7.2d
+; CHECK-NEXT: fadd v3.2d, v20.2d, v3.2d
+; CHECK-NEXT: fadd v16.2d, v22.2d, v1.2d
+; CHECK-NEXT: fadd v1.2d, v21.2d, v2.2d
+; CHECK-NEXT: fadd v5.2d, v23.2d, v0.2d
+; CHECK-NEXT: fadd v0.2d, v4.2d, v3.2d
+; CHECK-NEXT: fadd v1.2d, v6.2d, v1.2d
+; CHECK-NEXT: fadd v2.2d, v7.2d, v16.2d
+; CHECK-NEXT: fadd v3.2d, v18.2d, v5.2d
+; CHECK-NEXT: ret
+ %l = load <32 x i16>, ptr %p
+ %deint = call {<8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave4(<32 x i16> %l)
+ %s1 = extractvalue {<8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deint, 0
+ %s2 = extractvalue {<8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deint, 1
+ %s3 = extractvalue {<8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deint, 2
+ %s4 = extractvalue {<8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deint, 3
+ %z1 = uitofp <8 x i16> %s1 to <8 x double>
+ %z2 = uitofp <8 x i16> %s2 to <8 x double>
+ %z3 = uitofp <8 x i16> %s3 to <8 x double>
+ %z4 = uitofp <8 x i16> %s4 to <8 x double>
+ %a = fadd <8 x double> %z1, %z2
+ %b = fadd <8 x double> %z3, %z4
+ %c = fadd <8 x double> %a, %b
+ ret <8 x double> %c
+}
+
+define <8 x double> @uitofp_load_fadd(ptr %p) {
+; CHECK-LABEL: uitofp_load_fadd:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldp q3, q2, [x0]
+; CHECK-NEXT: ldp q1, q0, [x0, #32]
+; CHECK-NEXT: ushr v5.2d, v3.2d, #16
+; CHECK-NEXT: ushr v6.2d, v2.2d, #16
+; CHECK-NEXT: ushr v20.2d, v3.2d, #32
+; CHECK-NEXT: ushr v7.2d, v1.2d, #16
+; CHECK-NEXT: ushr v19.2d, v0.2d, #16
+; CHECK-NEXT: ushr v21.2d, v2.2d, #32
+; CHECK-NEXT: ushr v22.2d, v1.2d, #32
+; CHECK-NEXT: ushr v23.2d, v0.2d, #32
+; CHECK-NEXT: movprfx z4, z3
+; CHECK-NEXT: and z4.d, z4.d, #0xffff
+; CHECK-NEXT: movprfx z16, z2
+; CHECK-NEXT: and z16.d, z16.d, #0xffff
+; CHECK-NEXT: movprfx z17, z1
+; CHECK-NEXT: and z17.d, z17.d, #0xffff
+; CHECK-NEXT: movprfx z18, z0
+; CHECK-NEXT: and z18.d, z18.d, #0xffff
+; CHECK-NEXT: and z5.d, z5.d, #0xffff
+; CHECK-NEXT: and z6.d, z6.d, #0xffff
+; CHECK-NEXT: and z7.d, z7.d, #0xffff
+; CHECK-NEXT: and z19.d, z19.d, #0xffff
+; CHECK-NEXT: and z20.d, z20.d, #0xffff
+; CHECK-NEXT: and z21.d, z21.d, #0xffff
+; CHECK-NEXT: and z22.d, z22.d, #0xffff
+; CHECK-NEXT: and z23.d, z23.d, #0xffff
+; CHECK-NEXT: ushr v3.2d, v3.2d, #48
+; CHECK-NEXT: ushr v2.2d, v2.2d, #48
+; CHECK-NEXT: ushr v1.2d, v1.2d, #48
+; CHECK-NEXT: ushr v0.2d, v0.2d, #48
+; CHECK-NEXT: ucvtf v4.2d, v4.2d
+; CHECK-NEXT: ucvtf v16.2d, v16.2d
+; CHECK-NEXT: ucvtf v17.2d, v17.2d
+; CHECK-NEXT: ucvtf v18.2d, v18.2d
+; CHECK-NEXT: ucvtf v5.2d, v5.2d
+; CHECK-NEXT: ucvtf v6.2d, v6.2d
+; CHECK-NEXT: ucvtf v7.2d, v7.2d
+; CHECK-NEXT: ucvtf v19.2d, v19.2d
+; CHECK-NEXT: ucvtf v20.2d, v20.2d
+; CHECK-NEXT: ucvtf v21.2d, v21.2d
+; CHECK-NEXT: ucvtf v22.2d, v22.2d
+; CHECK-NEXT: ucvtf v23.2d, v23.2d
+; CHECK-NEXT: ucvtf v3.2d, v3.2d
+; CHECK-NEXT: ucvtf v2.2d, v2.2d
+; CHECK-NEXT: ucvtf v1.2d, v1.2d
+; CHECK-NEXT: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: fadd v6.2d, v16.2d, v6.2d
+; CHECK-NEXT: fadd v4.2d, v4.2d, v5.2d
+; CHECK-NEXT: fadd v18.2d, v18.2d, v19.2d
+; CHECK-NEXT: fadd v7.2d, v17.2d, v7.2d
+; CHECK-NEXT: fadd v3.2d, v20.2d, v3.2d
+; CHECK-NEXT: fadd v16.2d, v22.2d, v1.2d
+; CHECK-NEXT: fadd v1.2d, v21.2d, v2.2d
+; CHECK-NEXT: fadd v5.2d, v23.2d, v0.2d
+; CHECK-NEXT: fadd v0.2d, v4.2d, v3.2d
+; CHECK-NEXT: fadd v1.2d, v6.2d, v1.2d
+; CHECK-NEXT: fadd v2.2d, v7.2d, v16.2d
+; CHECK-NEXT: fadd v3.2d, v18.2d, v5.2d
+; CHECK-NEXT: ret
+ %l = load <32 x i16>, ptr %p
+ %s1 = shufflevector <32 x i16> %l, <32 x i16> poison, <8 x i32> <i32 0, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24, i32 28>
+ %s2 = shufflevector <32 x i16> %l, <32 x i16> poison, <8 x i32> <i32 1, i32 5, i32 9, i32 13, i32 17, i32 21, i32 25, i32 29>
+ %s3 = shufflevector <32 x i16> %l, <32 x i16> poison, <8 x i32> <i32 2, i32 6, i32 10, i32 14, i32 18, i32 22, i32 26, i32 30>
+ %s4 = shufflevector <32 x i16> %l, <32 x i16> poison, <8 x i32> <i32 3, i32 7, i32 11, i32 15, i32 19, i32 23, i32 27, i32 31>
+ %z1 = uitofp <8 x i16> %s1 to <8 x double>
+ %z2 = uitofp <8 x i16> %s2 to <8 x double>
+ %z3 = uitofp <8 x i16> %s3 to <8 x double>
+ %z4 = uitofp <8 x i16> %s4 to <8 x double>
+ %a = fadd <8 x double> %z1, %z2
+ %b = fadd <8 x double> %z3, %z4
+ %c = fadd <8 x double> %a, %b
+ ret <8 x double> %c
+}
diff --git a/llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i8-to-fp32.ll b/llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i8-to-fp32.ll
new file mode 100644
index 0000000000000..1acc08e7e9ed7
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-deinterleave4-i8-to-fp32.ll
@@ -0,0 +1,183 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple aarch64-none-linux-gnu -mattr=+sve | FileCheck %s
+
+define void @deinterleave_intrinsic_uitofp(ptr %src, ptr %dst0, ptr %dst1,
+; CHECK-LABEL: deinterleave_intrinsic_uitofp:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: cbz x5, .LBB0_3
+; CHECK-NEXT: // %bb.1: // %loop.preheader
+; CHECK-NEXT: adrp x8, .LCPI0_0
+; CHECK-NEXT: adrp x9, .LCPI0_1
+; CHECK-NEXT: adrp x10, .LCPI0_2
+; CHECK-NEXT: adrp x11, .LCPI0_3
+; CHECK-NEXT: ldr q0, [x8, :lo12:.LCPI0_0]
+; CHECK-NEXT: ldr q1, [x9, :lo12:.LCPI0_1]
+; CHECK-NEXT: ldr q2, [x10, :lo12:.LCPI0_2]
+; CHECK-NEXT: ldr q3, [x11, :lo12:.LCPI0_3]
+; CHECK-NEXT: mov x8, xzr
+; CHECK-NEXT: .LBB0_2: // %loop
+; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: lsl x9, x8, #5
+; CHECK-NEXT: add x8, x8, #1
+; CHECK-NEXT: cmp x8, x5
+; CHECK-NEXT: add x10, x0, x9
+; CHECK-NEXT: add x11, x2, x9
+; CHECK-NEXT: ldp q5, q4, [x10]
+; CHECK-NEXT: add x10, x1, x9
+; CHECK-NEXT: tbl v6.16b, { v4.16b }, v0.16b
+; CHECK-NEXT: tbl v7.16b, { v5.16b }, v0.16b
+; CHECK-NEXT: tbl v16.16b, { v4.16b }, v1.16b
+; CHECK-NEXT: tbl v17.16b, { v5.16b }, v1.16b
+; CHECK-NEXT: tbl v18.16b, { v4.16b }, v2.16b
+; CHECK-NEXT: tbl v19.16b, { v5.16b }, v2.16b
+; CHECK-NEXT: tbl v4.16b, { v4.16b }, v3.16b
+; CHECK-NEXT: tbl v5.16b, { v5.16b }, v3.16b
+; CHECK-NEXT: ucvtf v6.4s, v6.4s
+; CHECK-NEXT: ucvtf v7.4s, v7.4s
+; CHECK-NEXT: ucvtf v16.4s, v16.4s
+; CHECK-NEXT: ucvtf v17.4s, v17.4s
+; CHECK-NEXT: ucvtf v18.4s, v18.4s
+; CHECK-NEXT: ucvtf v4.4s, v4.4s
+; CHECK-NEXT: ucvtf v5.4s, v5.4s
+; CHECK-NEXT: stp q7, q6, [x10]
+; CHECK-NEXT: ucvtf v6.4s, v19.4s
+; CHECK-NEXT: add x10, x3, x9
+; CHECK-NEXT: add x9, x4, x9
+; CHECK-NEXT: stp q17, q16, [x11]
+; CHECK-NEXT: stp q6, q18, [x10]
+; CHECK-NEXT: stp q5, q4, [x9]
+; CHECK-NEXT: b.lo .LBB0_2
+; CHECK-NEXT: .LBB0_3: // %exit
+; CHECK-NEXT: ret
+ptr %dst2, ptr %dst3, i64 %n) {
+entry:
+%empty = icmp eq i64 %n, 0
+br i1 %empty, label %exit, label %loop
+
+loop:
+%i = phi i64 [ 0, %entry ], [ %next, %loop ]
+%src.off = mul i64 %i, 32
+%dst.off = mul i64 %i, 8
+%src.ptr = getelementptr i8, ptr %src, i64 %src.off
+%p0 = getelementptr float, ptr %dst0, i64 %dst.off
+%p1 = getelementptr float, ptr %dst1, i64 %dst.off
+%p2 = getelementptr float, ptr %dst2, i64 %dst.off
+%p3 = getelementptr float, ptr %dst3, i64 %dst.off
+
+%wide = load <32 x i8>, ptr %src.ptr, align 1
+%di = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.vector.deinterleave4.v32i8(<32 x i8> %wide)
+
+%v0 = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %di, 0
+%v1 = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %di, 1
+%v2 = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %di, 2
+%v3 = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %di, 3
+
+%f0 = uitofp <8 x i8> %v0 to <8 x float>
+%f1 = uitofp <8 x i8> %v1 to <8 x float>
+%f2 = uitofp <8 x i8> %v2 to <8 x float>
+%f3 = uitofp <8 x i8> %v3 to <8 x float>
+
+store <8 x float> %f0, ptr %p0, align 4
+store <8 x float> %f1, ptr %p1, align 4
+store <8 x float> %f2, ptr %p2, align 4
+store <8 x float> %f3, ptr %p3, align 4
+
+%next = add i64 %i, 1
+%more = icmp ult i64 %next, %n
+br i1 %more, label %loop, label %exit
+
+exit:
+ret void
+}
+
+define void @shuffle_uitofp(ptr %src, ptr %dst0, ptr %dst1,
+; CHECK-LABEL: shuffle_uitofp:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: cbz x5, .LBB1_3
+; CHECK-NEXT: // %bb.1: // %loop.preheader
+; CHECK-NEXT: adrp x8, .LCPI1_0
+; CHECK-NEXT: adrp x9, .LCPI1_1
+; CHECK-NEXT: adrp x10, .LCPI1_2
+; CHECK-NEXT: adrp x11, .LCPI1_3
+; CHECK-NEXT: ldr q0, [x8, :lo12:.LCPI1_0]
+; CHECK-NEXT: ldr q1, [x9, :lo12:.LCPI1_1]
+; CHECK-NEXT: ldr q2, [x10, :lo12:.LCPI1_2]
+; CHECK-NEXT: ldr q3, [x11, :lo12:.LCPI1_3]
+; CHECK-NEXT: mov x8, xzr
+; CHECK-NEXT: .LBB1_2: // %loop
+; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: lsl x9, x8, #5
+; CHECK-NEXT: add x8, x8, #1
+; CHECK-NEXT: cmp x8, x5
+; CHECK-NEXT: add x10, x0, x9
+; CHECK-NEXT: add x11, x2, x9
+; CHECK-NEXT: ldp q5, q4, [x10]
+; CHECK-NEXT: add x10, x1, x9
+; CHECK-NEXT: tbl v6.16b, { v4.16b }, v0.16b
+; CHECK-NEXT: tbl v7.16b, { v5.16b }, v0.16b
+; CHECK-NEXT: tbl v16.16b, { v4.16b }, v1.16b
+; CHECK-NEXT: tbl v17.16b, { v5.16b }, v1.16b
+; CHECK-NEXT: tbl v18.16b, { v4.16b }, v2.16b
+; CHECK-NEXT: tbl v19.16b, { v5.16b }, v2.16b
+; CHECK-NEXT: tbl v4.16b, { v4.16b }, v3.16b
+; CHECK-NEXT: tbl v5.16b, { v5.16b }, v3.16b
+; CHECK-NEXT: ucvtf v6.4s, v6.4s
+; CHECK-NEXT: ucvtf v7.4s, v7.4s
+; CHECK-NEXT: ucvtf v16.4s, v16.4s
+; CHECK-NEXT: ucvtf v17.4s, v17.4s
+; CHECK-NEXT: ucvtf v18.4s, v18.4s
+; CHECK-NEXT: ucvtf v4.4s, v4.4s
+; CHECK-NEXT: ucvtf v5.4s, v5.4s
+; CHECK-NEXT: stp q7, q6, [x10]
+; CHECK-NEXT: ucvtf v6.4s, v19.4s
+; CHECK-NEXT: add x10, x3, x9
+; CHECK-NEXT: add x9, x4, x9
+; CHECK-NEXT: stp q17, q16, [x11]
+; CHECK-NEXT: stp q6, q18, [x10]
+; CHECK-NEXT: stp q5, q4, [x9]
+; CHECK-NEXT: b.lo .LBB1_2
+; CHECK-NEXT: .LBB1_3: // %exit
+; CHECK-NEXT: ret
+ptr %dst2, ptr %dst3, i64 %n) {
+entry:
+%empty = icmp eq i64 %n, 0
+br i1 %empty, label %exit, label %loop
+
+loop:
+%i = phi i64 [ 0, %entry ], [ %next, %loop ]
+%src.off = mul i64 %i, 32
+%dst.off = mul i64 %i, 8
+%src.ptr = getelementptr i8, ptr %src, i64 %src.off
+%p0 = getelementptr float, ptr %dst0, i64 %dst.off
+%p1 = getelementptr float, ptr %dst1, i64 %dst.off
+%p2 = getelementptr float, ptr %dst2, i64 %dst.off
+%p3 = getelementptr float, ptr %dst3, i64 %dst.off
+
+%wide = load <32 x i8>, ptr %src.ptr, align 1
+
+%v0 = shufflevector <32 x i8> %wide, <32 x i8> poison,
+<8 x i32> <i32 0, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24, i32 28>
+%v1 = shufflevector <32 x i8> %wide, <32 x i8> poison,
+<8 x i32> <i32 1, i32 5, i32 9, i32 13, i32 17, i32 21, i32 25, i32 29>
+%v2 = shufflevector <32 x i8> %wide, <32 x i8> poison,
+<8 x i32> <i32 2, i32 6, i32 10, i32 14, i32 18, i32 22, i32 26, i32 30>
+%v3 = shufflevector <32 x i8> %wide, <32 x i8> poison,
+<8 x i32> <i32 3, i32 7, i32 11, i32 15, i32 19, i32 23, i32 27, i32 31>
+
+%f0 = uitofp <8 x i8> %v0 to <8 x float>
+%f1 = uitofp <8 x i8> %v1 to <8 x float>
+%f2 = uitofp <8 x i8> %v2 to <8 x float>
+%f3 = uitofp <8 x i8> %v3 to <8 x float>
+
+store <8 x float> %f0, ptr %p0, align 4
+store <8 x float> %f1, ptr %p1, align 4
+store <8 x float> %f2, ptr %p2, align 4
+store <8 x float> %f3, ptr %p3, align 4
+
+%next = add i64 %i, 1
+%more = icmp ult i64 %next, %n
+br i1 %more, label %loop, label %exit
+
+exit:
+ret void
+}
More information about the llvm-commits
mailing list