[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