[llvm] Add interleaved load combine on ARM (PR #196677)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 8 18:46:58 PDT 2026
https://github.com/LumioseSil created https://github.com/llvm/llvm-project/pull/196677
This works great for MVE and NEON vectors.
>From 108d931fd3b2846f6e245db4b4e85aff10f06486 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Fri, 8 May 2026 21:40:02 -0400
Subject: [PATCH] Add interleaved load combine on ARM
This works great for MVE and NEON vectors.
---
llvm/lib/Target/ARM/ARMTargetMachine.cpp | 11 +-
llvm/test/CodeGen/ARM/O3-pipeline.ll | 5 +
.../CodeGen/ARM/arm-interleaved-ld-combine.ll | 357 ++++++++++++++++++
3 files changed, 371 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/ARM/arm-interleaved-ld-combine.ll
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index 0de6f3d16eff4..1dd2f008566dd 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -365,7 +365,12 @@ void ARMPassConfig::addIRPasses() {
// ldrex/strex loops to simplify this, but it needs tidying up.
if (TM->getOptLevel() != CodeGenOptLevel::None && EnableAtomicTidy)
addPass(createCFGSimplificationPass(
- SimplifyCFGOptions().hoistCommonInsts(true).sinkCommonInsts(true),
+ SimplifyCFGOptions()
+ .forwardSwitchCondToPhi(true)
+ .convertSwitchRangeToICmp(true)
+ .convertSwitchToLookupTable(true)
+ .hoistCommonInsts(true)
+ .sinkCommonInsts(true),
[this](const Function &F) {
const auto &ST = this->TM->getSubtarget<ARMSubtarget>(F);
return ST.hasAnyDataBarrier() && !ST.isThumb1Only();
@@ -385,8 +390,10 @@ void ARMPassConfig::addIRPasses() {
addPass(createComplexDeinterleavingPass(TM));
// Match interleaved memory accesses to ldN/stN intrinsics.
- if (TM->getOptLevel() != CodeGenOptLevel::None)
+ if (TM->getOptLevel() != CodeGenOptLevel::None) {
+ addPass(createInterleavedLoadCombinePass());
addPass(createInterleavedAccessPass());
+ }
// Add Control Flow Guard checks.
if (TM->getTargetTriple().isOSWindows())
diff --git a/llvm/test/CodeGen/ARM/O3-pipeline.ll b/llvm/test/CodeGen/ARM/O3-pipeline.ll
index 9f4d70531a3f7..aceb32c890889 100644
--- a/llvm/test/CodeGen/ARM/O3-pipeline.ll
+++ b/llvm/test/CodeGen/ARM/O3-pipeline.ll
@@ -47,7 +47,12 @@
; CHECK-NEXT: Function Alias Analysis Results
; CHECK-NEXT: Transform functions to use DSP intrinsics
; CHECK-NEXT: Complex Deinterleaving Pass
+; CHECK-NEXT: Function Alias Analysis Results
+; CHECK-NEXT: Memory SSA
+; CHECK-NEXT: Interleaved Load Combine Pass
+; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Interleaved Access Pass
+; CHECK-NEXT: Natural Loop Information
; CHECK-NEXT: Type Promotion
; CHECK-NEXT: Post-Dominator Tree Construction
; CHECK-NEXT: Branch Probability Analysis
diff --git a/llvm/test/CodeGen/ARM/arm-interleaved-ld-combine.ll b/llvm/test/CodeGen/ARM/arm-interleaved-ld-combine.ll
new file mode 100644
index 0000000000000..584708093e133
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/arm-interleaved-ld-combine.ll
@@ -0,0 +1,357 @@
+; RUN: llc -mtriple=armv7-eabi -mattr=+neon -float-abi=hard < %s | FileCheck --check-prefix=AS %s
+; RUN: opt -S -mtriple=armv7-eabi -mattr=+neon -interleaved-load-combine < %s | FileCheck %s
+; RUN: opt -S -mtriple=armv7-eabi -mattr=+neon -passes=interleaved-load-combine < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+target triple = "armv7---eabi"
+
+; This should be lowered into VLD4.32
+define void @arm_ilc_const(ptr %ptr) {
+entry:
+
+;;; Check LLVM transformation
+; CHECK-LABEL: @arm_ilc_const(
+; CHECK-DAG: [[GEP:%.+]] = getelementptr inbounds <4 x float>, ptr %ptr, i32 2
+; CHECK-DAG: [[LOAD:%.+]] = load <16 x float>, ptr [[GEP]], align 16
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 0, i32 4, i32 8, i32 12>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 1, i32 5, i32 9, i32 13>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 2, i32 6, i32 10, i32 14>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 3, i32 7, i32 11, i32 15>
+; CHECK: ret void
+
+;;; Check if it gets lowered
+; AS-LABEL: arm_ilc_const
+; AS: vld4.32
+; AS: bx lr
+
+ %gep1 = getelementptr inbounds <4 x float>, ptr %ptr, i32 2
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 3
+ %gep3 = getelementptr inbounds <4 x float>, ptr %ptr, i32 4
+ %gep4 = getelementptr inbounds <4 x float>, ptr %ptr, i32 5
+ %ld1 = load <4 x float>, ptr %gep1, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %ld3 = load <4 x float>, ptr %gep3, align 16
+ %ld4 = load <4 x float>, ptr %gep4, align 16
+ %sv1 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ %sv2 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ %sv3 = shufflevector <4 x float> %ld3, <4 x float> %ld4, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ %sv4 = shufflevector <4 x float> %ld3, <4 x float> %ld4, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ %m0_3 = shufflevector <4 x float> %sv1, <4 x float> %sv3, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %sv1, <4 x float> %sv3, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+ %m8_11 = shufflevector <4 x float> %sv2, <4 x float> %sv4, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m12_15 = shufflevector <4 x float> %sv2, <4 x float> %sv4, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+
+ store <4 x float> %m0_3, ptr %gep1, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ store <4 x float> %m8_11, ptr %gep3, align 16
+ store <4 x float> %m12_15, ptr %gep4, align 16
+ ret void
+}
+
+; This should be lowered into VLD4.32
+define void @arm_ilc_idx(ptr %ptr, i32 %idx) {
+entry:
+
+;;; Check LLVM transformation
+; CHECK-LABEL: @arm_ilc_idx(
+; CHECK-DAG: [[ADD:%.+]] = add i32 %idx, 16
+; CHECK-DAG: [[LSHR:%.+]] = lshr i32 [[ADD]], 2
+; CHECK-DAG: [[GEP:%.+]] = getelementptr inbounds <4 x float>, ptr %ptr, i32 [[LSHR]]
+; CHECK-DAG: [[LOAD:%.+]] = load <16 x float>, ptr [[GEP]], align 16
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 0, i32 4, i32 8, i32 12>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 1, i32 5, i32 9, i32 13>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 2, i32 6, i32 10, i32 14>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 3, i32 7, i32 11, i32 15>
+; CHECK: ret void
+
+; AS-LABEL: arm_ilc_idx
+; AS: vld4.32
+; AS: bx lr
+
+ %a2 = add i32 %idx, 20
+ %idx2 = lshr i32 %a2, 2
+ %a3 = add i32 %idx, 24
+ %a1 = add i32 %idx, 16
+ %idx1 = lshr i32 %a1, 2
+ %idx3 = lshr i32 %a3, 2
+ %a4 = add i32 %idx, 28
+ %idx4 = lshr i32 %a4, 2
+
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx2
+ %gep4 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx4
+ %gep1 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx1
+ %gep3 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx3
+ %ld1 = load <4 x float>, ptr %gep1, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %ld3 = load <4 x float>, ptr %gep3, align 16
+ %ld4 = load <4 x float>, ptr %gep4, align 16
+ %sv1 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ %sv2 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ %sv3 = shufflevector <4 x float> %ld3, <4 x float> %ld4, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ %sv4 = shufflevector <4 x float> %ld3, <4 x float> %ld4, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ %m0_3 = shufflevector <4 x float> %sv1, <4 x float> %sv3, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %sv1, <4 x float> %sv3, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+ %m8_11 = shufflevector <4 x float> %sv2, <4 x float> %sv4, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m12_15 = shufflevector <4 x float> %sv2, <4 x float> %sv4, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+
+ store <4 x float> %m0_3, ptr %gep1, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ store <4 x float> %m8_11, ptr %gep3, align 16
+ store <4 x float> %m12_15, ptr %gep4, align 16
+ ret void
+}
+
+; This should be lowered into VLD4.32, an offset has to be taken into account
+%struct.ilc = type <{ float, [0 x <4 x float>] }>
+define void @arm_ilc_struct(ptr %ptr, i32 %idx) {
+entry:
+
+;;; Check LLVM transformation
+; CHECK-LABEL: @arm_ilc_struct(
+; CHECK-DAG: [[LSHR:%.+]] = lshr i32 %idx, 2
+; CHECK-DAG: [[GEP:%.+]] = getelementptr %struct.ilc, ptr %ptr, i32 0, i32 1, i32 [[LSHR]]
+; CHECK-DAG: [[LOAD:%.+]] = load <16 x float>, ptr [[GEP]], align 4
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 0, i32 4, i32 8, i32 12>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 1, i32 5, i32 9, i32 13>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 2, i32 6, i32 10, i32 14>
+; CHECK-DAG: %{{.* }}= shufflevector <16 x float> [[LOAD]], <16 x float> poison, <4 x i32> <i32 3, i32 7, i32 11, i32 15>
+; CHECK: ret void
+
+; AS-LABEL: arm_ilc_struct
+; AS: vld4.32
+; AS: bx lr
+
+ %a1 = add i32 %idx, 4
+ %idx2 = lshr i32 %a1, 2
+ %a2 = add i32 %idx, 8
+ %idx3 = lshr i32 %a2, 2
+ %a3 = add i32 %idx, 12
+ %idx4 = lshr i32 %a3, 2
+
+ %gep2 = getelementptr %struct.ilc, ptr %ptr, i32 0, i32 1, i32 %idx2
+ %gep3 = getelementptr %struct.ilc, ptr %ptr, i32 0, i32 1, i32 %idx3
+ %gep4 = getelementptr %struct.ilc, ptr %ptr, i32 0, i32 1, i32 %idx4
+ %idx1 = lshr i32 %idx, 2
+ %gep1 = getelementptr %struct.ilc, ptr %ptr, i32 0, i32 1, i32 %idx1
+ %ld1 = load <4 x float>, ptr %gep1, align 4
+ %ld2 = load <4 x float>, ptr %gep2, align 4
+ %ld3 = load <4 x float>, ptr %gep3, align 4
+ %ld4 = load <4 x float>, ptr %gep4, align 4
+ %sv1 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ %sv2 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ %sv3 = shufflevector <4 x float> %ld3, <4 x float> %ld4, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ %sv4 = shufflevector <4 x float> %ld3, <4 x float> %ld4, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ %m0_3 = shufflevector <4 x float> %sv1, <4 x float> %sv3, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %sv1, <4 x float> %sv3, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+ %m8_11 = shufflevector <4 x float> %sv2, <4 x float> %sv4, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m12_15 = shufflevector <4 x float> %sv2, <4 x float> %sv4, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+
+ store <4 x float> %m0_3, ptr %gep1, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ store <4 x float> %m8_11, ptr %gep3, align 16
+ store <4 x float> %m12_15, ptr %gep4, align 16
+ ret void
+}
+
+; This should be lowered into VLD2.32
+define void @arm_ilc_idx_ld2(ptr %ptr, i32 %idx) {
+entry:
+; CHECK-LABEL: @arm_ilc_idx_ld2(
+; CHECK-DAG: [[LSHR:%.+]] = lshr i32 %idx, 2
+; CHECK-DAG: [[GEP:%.+]] = getelementptr inbounds <4 x float>, ptr %ptr, i32 [[LSHR]]
+; CHECK-DAG: [[LOAD:%.+]] = load <8 x float>, ptr [[GEP]], align 16
+; CHECK: %{{.* }}= shufflevector <8 x float> [[LOAD]], <8 x float> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK: %{{.* }}= shufflevector <8 x float> [[LOAD]], <8 x float> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+; CHECK-DAG: ret void
+
+; AS-LABEL: arm_ilc_idx_ld2
+; AS: vld2.32
+; AS: bx lr
+
+ %idx1 = lshr i32 %idx, 2
+ %a1 = add i32 %idx, 4
+ %idx2 = lshr i32 %a1, 2
+
+ %gep1 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx1
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx2
+ %ld1 = load <4 x float>, ptr %gep1, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %m0_3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+
+ store <4 x float> %m0_3, ptr %gep1
+ store <4 x float> %m4_7, ptr %gep2
+ ret void
+}
+
+; This should be lowered into VLD3.32
+define void @arm_ilc_idx_ld3(ptr %ptr, i32 %idx) {
+entry:
+; CHECK-LABEL: @arm_ilc_idx_ld3(
+; CHECK-DAG: [[LSHR:%.+]] = lshr i32 %idx, 2
+; CHECK-DAG: [[GEP:%.+]] = getelementptr inbounds <4 x float>, ptr %ptr, i32 [[LSHR]]
+; CHECK-DAG: [[LOAD:%.+]] = load <12 x float>, ptr [[GEP]], align 16
+; CHECK: %{{.* }}= shufflevector <12 x float> [[LOAD]], <12 x float> poison, <4 x i32> <i32 0, i32 3, i32 6, i32 9>
+; CHECK: %{{.* }}= shufflevector <12 x float> [[LOAD]], <12 x float> poison, <4 x i32> <i32 1, i32 4, i32 7, i32 10>
+; CHECK: %{{.* }}= shufflevector <12 x float> [[LOAD]], <12 x float> poison, <4 x i32> <i32 2, i32 5, i32 8, i32 11>
+; CHECK-DAG: ret void
+
+; AS-LABEL: arm_ilc_idx_ld3
+; AS: vld3.32
+; AS: bx lr
+
+ %idx1 = lshr i32 %idx, 2
+ %a1 = add i32 %idx, 4
+ %idx2 = lshr i32 %a1, 2
+ %a2 = add i32 %idx, 8
+ %idx3 = lshr i32 %a2, 2
+
+ %gep1 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx1
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx2
+ %gep3 = getelementptr inbounds <4 x float>, ptr %ptr, i32 %idx3
+ %ld1 = load <4 x float>, ptr %gep1, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %ld3 = load <4 x float>, ptr %gep3, align 16
+
+ %sv1 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 3, i32 6, i32 undef>
+ %sv2 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 4, i32 7, i32 undef>
+ %sv3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 2, i32 5, i32 undef, i32 undef>
+ %m0_3 = shufflevector <4 x float> %sv1, <4 x float> %ld3, <4 x i32> <i32 0, i32 1, i32 2, i32 5>
+ %m4_7 = shufflevector <4 x float> %sv2, <4 x float> %ld3, <4 x i32> <i32 0, i32 1, i32 2, i32 6>
+ %m8_11 = shufflevector <4 x float> %sv3, <4 x float> %ld3, <4 x i32> <i32 0, i32 1, i32 4, i32 7>
+
+ store <4 x float> %m0_3, ptr %gep1, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ store <4 x float> %m8_11, ptr %gep3, align 16
+ ret void
+}
+
+; A wider (i64) induction variable on a 32-bit target is also handled: the
+; pass tracks the low 32 bits of the index arithmetic and lowers to VLD2.32.
+define void @arm_ilc_i64_idx_ld2(ptr %ptr, i64 %idx) {
+entry:
+; CHECK-LABEL: @arm_ilc_i64_idx_ld2(
+; CHECK-DAG: [[LSHR:%.+]] = lshr i64 %idx, 2
+; CHECK-DAG: [[GEP:%.+]] = getelementptr inbounds <4 x float>, ptr %ptr, i64 [[LSHR]]
+; CHECK-DAG: [[LOAD:%.+]] = load <8 x float>, ptr [[GEP]], align 16
+; CHECK-DAG: %{{.* }}= shufflevector <8 x float> [[LOAD]], <8 x float> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-DAG: %{{.* }}= shufflevector <8 x float> [[LOAD]], <8 x float> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+; CHECK: ret void
+
+; AS-LABEL: arm_ilc_i64_idx_ld2
+; AS: vld2.32
+; AS: bx lr
+
+ %idx1 = lshr i64 %idx, 2
+ %a1 = add i64 %idx, 4
+ %idx2 = lshr i64 %a1, 2
+
+ %gep1 = getelementptr inbounds <4 x float>, ptr %ptr, i64 %idx1
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i64 %idx2
+ %ld1 = load <4 x float>, ptr %gep1, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %m0_3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+
+ store <4 x float> %m0_3, ptr %gep1, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ ret void
+}
+
+; Volatile loads must not be lowered
+define void @arm_ilc_volatile(ptr %ptr) {
+; CHECK-LABEL: @arm_ilc_volatile(
+; CHECK: %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 1
+; CHECK-NEXT: %ld1 = load volatile <4 x float>, ptr %ptr, align 16
+; CHECK-NEXT: %ld2 = load <4 x float>, ptr %gep2, align 16
+; CHECK-NEXT: %m0_3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT: %m4_7 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+; CHECK-NEXT: store <4 x float> %m0_3, ptr %ptr, align 16
+; CHECK-NEXT: store <4 x float> %m4_7, ptr %gep2, align 16
+; CHECK-NEXT: ret void
+
+; AS-LABEL: arm_ilc_volatile
+; AS-NOT: vld2.
+; AS-NOT: vld3.
+; AS-NOT: vld4.
+; AS: bx lr
+
+entry:
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 1
+ %ld1 = load volatile <4 x float>, ptr %ptr, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %m0_3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+ store <4 x float> %m0_3, ptr %ptr, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ ret void
+}
+
+; This must not be lowered because there is an aliasing store between the loads
+define void @arm_ilc_depmem(ptr %ptr, i32 %idx) {
+entry:
+; CHECK-LABEL: @arm_ilc_depmem(
+; CHECK: %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 1
+; CHECK-NEXT: %ld1 = load <4 x float>, ptr %ptr, align 16
+; CHECK-NEXT: store <4 x float> %ld1, ptr %gep2, align 16
+; CHECK-NEXT: %ld2 = load <4 x float>, ptr %gep2, align 16
+; CHECK-NEXT: %m0_3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT: %m4_7 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+; CHECK-NEXT: store <4 x float> %m0_3, ptr %ptr, align 16
+; CHECK-NEXT: store <4 x float> %m4_7, ptr %gep2, align 16
+; CHECK-NEXT: ret void
+
+; AS-LABEL: arm_ilc_depmem
+; AS-NOT: vld2.
+; AS-NOT: vld3.
+; AS-NOT: vld4.
+; AS: bx lr
+
+ %gep2 = getelementptr inbounds <4 x float>, ptr %ptr, i32 1
+ %ld1 = load <4 x float>, ptr %ptr, align 16
+ store <4 x float> %ld1, ptr %gep2, align 16
+ %ld2 = load <4 x float>, ptr %gep2, align 16
+ %m0_3 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %m4_7 = shufflevector <4 x float> %ld1, <4 x float> %ld2, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+
+ store <4 x float> %m0_3, ptr %ptr, align 16
+ store <4 x float> %m4_7, ptr %gep2, align 16
+ ret void
+}
+
+; This cannot be converted - insertion position cannot be determined
+define void @arm_no_insertion_pos(ptr %ptr) {
+entry:
+; CHECK-LABEL: @arm_no_insertion_pos(
+; CHECK: %p1 = getelementptr inbounds float, ptr %ptr, i32 4
+; CHECK-NEXT: %l0 = load <5 x float>, ptr %ptr
+; CHECK-NEXT: %l1 = load <5 x float>, ptr %p1
+; CHECK-NEXT: %s0 = shufflevector <5 x float> %l0, <5 x float> %l1, <4 x i32> <i32 1, i32 3, i32 6, i32 8>
+; CHECK-NEXT: %s1 = shufflevector <5 x float> %l0, <5 x float> %l1, <4 x i32> <i32 2, i32 4, i32 7, i32 9>
+; CHECK-NEXT: ret void
+
+ %p1 = getelementptr inbounds float, ptr %ptr, i32 4
+ %l0 = load <5 x float>, ptr %ptr
+ %l1 = load <5 x float>, ptr %p1
+ %s0 = shufflevector <5 x float> %l0, <5 x float> %l1, <4 x i32> <i32 1, i32 3, i32 6, i32 8>
+ %s1 = shufflevector <5 x float> %l0, <5 x float> %l1, <4 x i32> <i32 2, i32 4, i32 7, i32 9>
+ ret void
+}
+
+; This cannot be converted - the insertion position does not dominate all uses
+define void @arm_insertpos_does_not_dominate(ptr %ptr) {
+entry:
+; CHECK-LABEL: @arm_insertpos_does_not_dominate(
+; CHECK: %p1 = getelementptr inbounds float, ptr %ptr, i32 1
+; CHECK-NEXT: %l1 = load <7 x float>, ptr %p1
+; CHECK-NEXT: %s1 = shufflevector <7 x float> %l1, <7 x float> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT: %l0 = load <7 x float>, ptr %ptr
+; CHECK-NEXT: %s0 = shufflevector <7 x float> %l0, <7 x float> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT: ret void
+ %p1 = getelementptr inbounds float, ptr %ptr, i32 1
+ %l1 = load <7 x float>, ptr %p1
+ %s1 = shufflevector <7 x float> %l1, <7 x float> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %l0 = load <7 x float>, ptr %ptr
+ %s0 = shufflevector <7 x float> %l0, <7 x float> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ ret void
+}
More information about the llvm-commits
mailing list