[llvm] 21517de - [AArch64] Use SVE for load-extend-broadcast (#221689)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 17 06:17:58 PDT 2026
Author: Jack Styles
Date: 2026-09-17T14:17:53+01:00
New Revision: 21517de3188cc2779115e86c69a3c4e1fe94a864
URL: https://github.com/llvm/llvm-project/commit/21517de3188cc2779115e86c69a3c4e1fe94a864
DIFF: https://github.com/llvm/llvm-project/commit/21517de3188cc2779115e86c69a3c4e1fe94a864.diff
LOG: [AArch64] Use SVE for load-extend-broadcast (#221689)
On certain cores, it is faster to use SVE ld1r instructions to load,
extend and broadcast an integer value to a vector in all cases other
than 64bit vectors where no type promotion occurs.
To acheive this, introduce a tuning option, `PreferSVEVectors` for use
when combining DUP instructions to create a Splat Vector to the scalable
alternative, and then use the already implemented scheduling model
patterns for splat vectors to end up generate the ld1r instruction.
If used in a loop, the predicate will be hoisted outside of the loop.
Added:
Modified:
llvm/lib/Target/AArch64/AArch64Features.td
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
llvm/lib/Target/AArch64/AArch64Processors.td
llvm/test/CodeGen/AArch64/dup-ext-load-combine.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index ad1561c281703..440151ae6f4e1 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -665,6 +665,10 @@ def FeatureNoSVEFPLD1R : SubtargetFeature<"no-sve-fp-ld1r",
"NoSVEFPLD1R", "true", "Avoid using LD1RX instructions for FP",
[], InlineIgnore>;
+def FeatureDontPreferPredicatedLD1R : SubtargetFeature <
+ "dont-prefer-predicated-ld1r", "NoPredicatedLD1R", "true",
+ "Don't prefer predicated SVE LD1R over sign-extended-load + NEON dup", [], InlineIgnore>;
+
def FeatureZCRegMoveGPR64 : SubtargetFeature<"zcm-gpr64", "HasZeroCycleRegMoveGPR64", "true",
"Has zero-cycle register moves for GPR64 registers",
[], InlineIgnore>;
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index c4942e12e17ac..31c86fdad4778 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -30293,7 +30293,8 @@ static SDValue performSelectCombine(SDNode *N,
}
static SDValue performDUPCombine(SDNode *N,
- TargetLowering::DAGCombinerInfo &DCI) {
+ TargetLowering::DAGCombinerInfo &DCI,
+ const AArch64Subtarget *Subtarget) {
EVT VT = N->getValueType(0);
SDLoc DL(N);
// If "v2i32 DUP(x)" and "v4i32 DUP(x)" both exist, use an extract from the
@@ -30317,6 +30318,15 @@ static SDValue performDUPCombine(SDNode *N,
// v4i32 = SCALAR_TO_VECTOR (i32 (zextloadi8 addr)) ; Matches to ldr b0
// v4i32 = DUPLANE32 (v4i32), 0
if (auto *LD = dyn_cast<LoadSDNode>(Op)) {
+ if (!Subtarget->noPredicatedLD1R() &&
+ Subtarget->isSVEorStreamingSVEAvailable() && Op->hasOneUse() &&
+ VT.getScalarType().isInteger() &&
+ VT.getScalarType() != LD->getMemoryVT().getScalarType()) {
+ EVT ScalableVT = getContainerForFixedLengthVector(DCI.DAG, VT);
+ SDValue SplatNode =
+ DCI.DAG.getNode(ISD::SPLAT_VECTOR, DL, ScalableVT, Op);
+ return convertFromScalableVector(DCI.DAG, VT, SplatNode);
+ }
ISD::LoadExtType ExtType = LD->getExtensionType();
EVT MemVT = LD->getMemoryVT();
EVT ElemVT = VT.getVectorElementType();
@@ -31815,7 +31825,7 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
case AArch64ISD::DUPLANE16:
case AArch64ISD::DUPLANE32:
case AArch64ISD::DUPLANE64:
- return performDUPCombine(N, DCI);
+ return performDUPCombine(N, DCI, Subtarget);
case AArch64ISD::DUPLANE128:
return performDupLane128Combine(N, DAG);
case AArch64ISD::NVCAST:
diff --git a/llvm/lib/Target/AArch64/AArch64Processors.td b/llvm/lib/Target/AArch64/AArch64Processors.td
index 1ed06ee68db49..c0bbcc8cd4537 100644
--- a/llvm/lib/Target/AArch64/AArch64Processors.td
+++ b/llvm/lib/Target/AArch64/AArch64Processors.td
@@ -575,7 +575,8 @@ def TuneNeoverseV1 : SubtargetFeature<"neoversev1", "ARMProcFamily", "NeoverseV1
FeatureEnableSelectOptimize,
FeaturePredictableSelectIsExpensive,
FeatureDisableMaximizeScalableBandwidth,
- FeatureNoSVEFPLD1R]>;
+ FeatureNoSVEFPLD1R,
+ FeatureDontPreferPredicatedLD1R]>;
def TuneNeoverseV2 : SubtargetFeature<"neoversev2", "ARMProcFamily", "NeoverseV2",
"Neoverse V2 ARM processors", [
@@ -591,7 +592,8 @@ def TuneNeoverseV2 : SubtargetFeature<"neoversev2", "ARMProcFamily", "NeoverseV2
FeatureAvoidLDAPUR,
FeaturePredictableSelectIsExpensive,
FeatureDisableLatencySchedHeuristic,
- FeatureMaxInterleaveFactor4]>;
+ FeatureMaxInterleaveFactor4,
+ FeatureDontPreferPredicatedLD1R]>;
def TuneNeoverseV3 : SubtargetFeature<"neoversev3", "ARMProcFamily", "NeoverseV3",
"Neoverse V3 ARM processors", [
diff --git a/llvm/test/CodeGen/AArch64/dup-ext-load-combine.ll b/llvm/test/CodeGen/AArch64/dup-ext-load-combine.ll
index cf529343c6728..d97bfe1cbc726 100644
--- a/llvm/test/CodeGen/AArch64/dup-ext-load-combine.ll
+++ b/llvm/test/CodeGen/AArch64/dup-ext-load-combine.ll
@@ -1,15 +1,24 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,CHECK-BASE
+; RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+sve -mattr=+dont-prefer-predicated-ld1r < %s | FileCheck %s --check-prefixes=CHECK,CHECK-BASE
+; RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+sve < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SVE
; Test optimization of DUP with extended narrow loads
; This should avoid GPR->SIMD transfers by loading directly into vector registers
define <4 x i16> @test_dup_zextload_i8_v4i16(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i8_v4i16:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0]
-; CHECK-NEXT: dup v0.4h, v0.h[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v4i16:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0]
+; CHECK-BASE-NEXT: dup v0.4h, v0.h[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v4i16:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.h
+; CHECK-SVE-NEXT: ld1rb { z0.h }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i8, ptr %p, align 1
%ext = zext i8 %load to i16
%vec = insertelement <4 x i16> poison, i16 %ext, i32 0
@@ -18,11 +27,18 @@ define <4 x i16> @test_dup_zextload_i8_v4i16(ptr %p) {
}
define <8 x i16> @test_dup_zextload_i8_v8i16(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i8_v8i16:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0]
-; CHECK-NEXT: dup v0.8h, v0.h[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v8i16:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0]
+; CHECK-BASE-NEXT: dup v0.8h, v0.h[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v8i16:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.h
+; CHECK-SVE-NEXT: ld1rb { z0.h }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i8, ptr %p, align 1
%ext = zext i8 %load to i16
%vec = insertelement <8 x i16> poison, i16 %ext, i32 0
@@ -31,11 +47,18 @@ define <8 x i16> @test_dup_zextload_i8_v8i16(ptr %p) {
}
define <2 x i32> @test_dup_zextload_i8_v2i32(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i8_v2i32:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0]
-; CHECK-NEXT: dup v0.2s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v2i32:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0]
+; CHECK-BASE-NEXT: dup v0.2s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v2i32:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: ld1rb { z0.s }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i8, ptr %p, align 1
%ext = zext i8 %load to i32
%vec = insertelement <2 x i32> poison, i32 %ext, i32 0
@@ -44,11 +67,18 @@ define <2 x i32> @test_dup_zextload_i8_v2i32(ptr %p) {
}
define <4 x i32> @test_dup_zextload_i8_v4i32(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i8_v4i32:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0]
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v4i32:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0]
+; CHECK-BASE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v4i32:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: ld1rb { z0.s }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i8, ptr %p, align 1
%ext = zext i8 %load to i32
%vec = insertelement <4 x i32> poison, i32 %ext, i32 0
@@ -57,11 +87,18 @@ define <4 x i32> @test_dup_zextload_i8_v4i32(ptr %p) {
}
define <4 x i32> @test_dup_zextload_i8_v4i32_offset(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i8_v4i32_offset:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0, #4]
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v4i32_offset:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0, #4]
+; CHECK-BASE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v4i32_offset:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: ld1rb { z0.s }, p0/z, [x0, #4]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%addr = getelementptr inbounds i8, ptr %p, i64 4
%load = load i8, ptr %addr, align 1
%ext = zext i8 %load to i32
@@ -71,11 +108,19 @@ define <4 x i32> @test_dup_zextload_i8_v4i32_offset(ptr %p) {
}
define <4 x i32> @test_dup_zextload_i8_v4i32_reg_offset(ptr %p, i64 %offset) {
-; CHECK-LABEL: test_dup_zextload_i8_v4i32_reg_offset:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0, x1]
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v4i32_reg_offset:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0, x1]
+; CHECK-BASE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v4i32_reg_offset:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: add x8, x0, x1
+; CHECK-SVE-NEXT: ld1rb { z0.s }, p0/z, [x8]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%addr = getelementptr inbounds i8, ptr %p, i64 %offset
%load = load i8, ptr %addr, align 1
%ext = zext i8 %load to i32
@@ -85,11 +130,18 @@ define <4 x i32> @test_dup_zextload_i8_v4i32_reg_offset(ptr %p, i64 %offset) {
}
define <2 x i64> @test_dup_zextload_i8_v2i64(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i8_v2i64:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr b0, [x0]
-; CHECK-NEXT: dup v0.2d, v0.d[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i8_v2i64:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr b0, [x0]
+; CHECK-BASE-NEXT: dup v0.2d, v0.d[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i8_v2i64:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.d
+; CHECK-SVE-NEXT: ld1rb { z0.d }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i8, ptr %p, align 1
%ext = zext i8 %load to i64
%vec = insertelement <2 x i64> poison, i64 %ext, i32 0
@@ -98,11 +150,18 @@ define <2 x i64> @test_dup_zextload_i8_v2i64(ptr %p) {
}
define <2 x i32> @test_dup_zextload_i16_v2i32(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i16_v2i32:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr h0, [x0]
-; CHECK-NEXT: dup v0.2s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i16_v2i32:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr h0, [x0]
+; CHECK-BASE-NEXT: dup v0.2s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i16_v2i32:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: ld1rh { z0.s }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i16, ptr %p, align 1
%ext = zext i16 %load to i32
%vec = insertelement <2 x i32> poison, i32 %ext, i32 0
@@ -111,11 +170,18 @@ define <2 x i32> @test_dup_zextload_i16_v2i32(ptr %p) {
}
define <4 x i32> @test_dup_zextload_i16_v4i32(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i16_v4i32:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr h0, [x0]
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i16_v4i32:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr h0, [x0]
+; CHECK-BASE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i16_v4i32:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: ld1rh { z0.s }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i16, ptr %p, align 1
%ext = zext i16 %load to i32
%vec = insertelement <4 x i32> poison, i32 %ext, i32 0
@@ -124,11 +190,18 @@ define <4 x i32> @test_dup_zextload_i16_v4i32(ptr %p) {
}
define <4 x i32> @test_dup_zextload_i16_v4i32_offset(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i16_v4i32_offset:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr h0, [x0, #8]
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i16_v4i32_offset:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr h0, [x0, #8]
+; CHECK-BASE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i16_v4i32_offset:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: ld1rh { z0.s }, p0/z, [x0, #8]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%addr = getelementptr inbounds i16, ptr %p, i64 4
%load = load i16, ptr %addr, align 1
%ext = zext i16 %load to i32
@@ -138,11 +211,19 @@ define <4 x i32> @test_dup_zextload_i16_v4i32_offset(ptr %p) {
}
define <4 x i32> @test_dup_zextload_i16_v4i32_reg_offset(ptr %p, i64 %offset) {
-; CHECK-LABEL: test_dup_zextload_i16_v4i32_reg_offset:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr h0, [x0, x1, lsl #1]
-; CHECK-NEXT: dup v0.4s, v0.s[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i16_v4i32_reg_offset:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr h0, [x0, x1, lsl #1]
+; CHECK-BASE-NEXT: dup v0.4s, v0.s[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i16_v4i32_reg_offset:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.s
+; CHECK-SVE-NEXT: add x8, x0, x1, lsl #1
+; CHECK-SVE-NEXT: ld1rh { z0.s }, p0/z, [x8]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%addr = getelementptr inbounds i16, ptr %p, i64 %offset
%load = load i16, ptr %addr, align 1
%ext = zext i16 %load to i32
@@ -152,11 +233,18 @@ define <4 x i32> @test_dup_zextload_i16_v4i32_reg_offset(ptr %p, i64 %offset) {
}
define <2 x i64> @test_dup_zextload_i16_v2i64(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i16_v2i64:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr h0, [x0]
-; CHECK-NEXT: dup v0.2d, v0.d[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i16_v2i64:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr h0, [x0]
+; CHECK-BASE-NEXT: dup v0.2d, v0.d[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i16_v2i64:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.d
+; CHECK-SVE-NEXT: ld1rh { z0.d }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i16, ptr %p, align 1
%ext = zext i16 %load to i64
%vec = insertelement <2 x i64> poison, i64 %ext, i32 0
@@ -165,14 +253,98 @@ define <2 x i64> @test_dup_zextload_i16_v2i64(ptr %p) {
}
define <2 x i64> @test_dup_zextload_i32_v2i64(ptr %p) {
-; CHECK-LABEL: test_dup_zextload_i32_v2i64:
-; CHECK: // %bb.0:
-; CHECK-NEXT: ldr s0, [x0]
-; CHECK-NEXT: dup v0.2d, v0.d[0]
-; CHECK-NEXT: ret
+; CHECK-BASE-LABEL: test_dup_zextload_i32_v2i64:
+; CHECK-BASE: // %bb.0:
+; CHECK-BASE-NEXT: ldr s0, [x0]
+; CHECK-BASE-NEXT: dup v0.2d, v0.d[0]
+; CHECK-BASE-NEXT: ret
+;
+; CHECK-SVE-LABEL: test_dup_zextload_i32_v2i64:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: ptrue p0.d
+; CHECK-SVE-NEXT: ld1rw { z0.d }, p0/z, [x0]
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
+; CHECK-SVE-NEXT: ret
%load = load i32, ptr %p, align 1
%ext = zext i32 %load to i64
%vec = insertelement <2 x i64> poison, i64 %ext, i32 0
%dup = shufflevector <2 x i64> %vec, <2 x i64> poison, <2 x i32> zeroinitializer
ret <2 x i64> %dup
}
+
+define <16 x i8> @test_dup_load_i8_v16i8(ptr %p) {
+; CHECK-LABEL: test_dup_load_i8_v16i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.16b }, [x0]
+; CHECK-NEXT: ret
+ %load = load i8, ptr %p, align 1
+ %vec = insertelement <16 x i8> poison, i8 %load, i64 0
+ %dup = shufflevector <16 x i8> %vec, <16 x i8> poison, <16 x i32> zeroinitializer
+ ret <16 x i8> %dup
+}
+
+define <8 x i8> @test_dup_load_i8_v8i8(ptr %p) {
+; CHECK-LABEL: test_dup_load_i8_v8i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.8b }, [x0]
+; CHECK-NEXT: ret
+ %load = load i8, ptr %p, align 1
+ %vec = insertelement <8 x i8> poison, i8 %load, i64 0
+ %dup = shufflevector <8 x i8> %vec, <8 x i8> poison, <8 x i32> zeroinitializer
+ ret <8 x i8> %dup
+}
+
+define <8 x i16> @test_dup_load_i16_v8i16(ptr %p) {
+; CHECK-LABEL: test_dup_load_i16_v8i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.8h }, [x0]
+; CHECK-NEXT: ret
+ %load = load i16, ptr %p, align 1
+ %vec = insertelement <8 x i16> poison, i16 %load, i64 0
+ %dup = shufflevector <8 x i16> %vec, <8 x i16> poison, <8 x i32> zeroinitializer
+ ret <8 x i16> %dup
+}
+
+define <4 x i16> @test_dup_load_i16_v4i16(ptr %p) {
+; CHECK-LABEL: test_dup_load_i16_v4i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.4h }, [x0]
+; CHECK-NEXT: ret
+ %load = load i16, ptr %p, align 1
+ %vec = insertelement <4 x i16> poison, i16 %load, i64 0
+ %dup = shufflevector <4 x i16> %vec, <4 x i16> poison, <4 x i32> zeroinitializer
+ ret <4 x i16> %dup
+}
+
+define <4 x i32> @test_dup_load_i32_v4i32(ptr %p) {
+; CHECK-LABEL: test_dup_load_i32_v4i32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.4s }, [x0]
+; CHECK-NEXT: ret
+ %load = load i32, ptr %p, align 1
+ %vec = insertelement <4 x i32> poison, i32 %load, i64 0
+ %dup = shufflevector <4 x i32> %vec, <4 x i32> poison, <4 x i32> zeroinitializer
+ ret <4 x i32> %dup
+}
+
+define <2 x i32> @test_dup_load_i32_v2i32(ptr %p) {
+; CHECK-LABEL: test_dup_load_i32_v2i32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.2s }, [x0]
+; CHECK-NEXT: ret
+ %load = load i32, ptr %p, align 1
+ %vec = insertelement <2 x i32> poison, i32 %load, i64 0
+ %dup = shufflevector <2 x i32> %vec, <2 x i32> poison, <2 x i32> zeroinitializer
+ ret <2 x i32> %dup
+}
+
+define <2 x i64> @test_dup_load_i64_v2i64(ptr %p) {
+; CHECK-LABEL: test_dup_load_i64_v2i64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ld1r { v0.2d }, [x0]
+; CHECK-NEXT: ret
+ %load = load i64, ptr %p, align 1
+ %vec = insertelement <2 x i64> poison, i64 %load, i64 0
+ %dup = shufflevector <2 x i64> %vec, <2 x i64> poison, <2 x i32> zeroinitializer
+ ret <2 x i64> %dup
+}
More information about the llvm-commits
mailing list