[llvm] [VectorCombine][TTI] Disable Load Widening for SPIR-V (PR #227623)
Gregory Roth via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 04:16:37 PDT 2026
https://github.com/pow2clk updated https://github.com/llvm/llvm-project/pull/227623
>From ba4342580f5e6ac6239a29592db594b94047c634 Mon Sep 17 00:00:00 2001
From: Gregory Roth <groth at nvidia.com>
Date: Tue, 29 Sep 2026 04:16:37 -0700
Subject: [PATCH 1/2] [VectorCombine][TTI] Disable Load Widening for SPIR-V
When a float is loaded and its only use is to insert it into a vector, VectorCombine converts the load to just load that vector. This fails SPIR-V validation as it's the wrong type.
These wide loads aren't compatible with SPIR-V, so a check is added to TargetTransformInfo to query support.
This is along similar lines as #150216
---
.../llvm/Analysis/TargetTransformInfo.h | 3 ++
.../llvm/Analysis/TargetTransformInfoImpl.h | 2 +
llvm/lib/Analysis/TargetTransformInfo.cpp | 4 ++
.../Target/SPIRV/SPIRVTargetTransformInfo.h | 2 +
.../Transforms/Vectorize/VectorCombine.cpp | 5 ++-
.../VectorCombine/SPIRV/load-widening.ll | 37 +++++++++++++++++++
6 files changed, 51 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index a33e6f62e941e..cf6898ffec52b 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -2145,6 +2145,9 @@ class TargetTransformInfo {
/// target.
LLVM_ABI bool allowVectorElementIndexingUsingGEP() const;
+ /// Return true if we should enable load widening for this target.
+ LLVM_ABI bool allowLoadWidening() const;
+
/// Determine if an instruction with Custom uniformity can be proven uniform
/// based on which operands are uniform.
///
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index a19c122c16f20..10e37a8381ae5 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -1253,6 +1253,8 @@ class LLVM_ABI TargetTransformInfoImplBase {
virtual bool allowVectorElementIndexingUsingGEP() const { return true; }
+ virtual bool allowLoadWidening() const { return true; }
+
virtual bool isUniform(const Instruction *I,
const SmallBitVector &UniformArgs) const {
llvm_unreachable("target must implement isUniform for Custom uniformity");
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index af73a615f25fa..50b4ed720ef2b 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -1596,6 +1596,10 @@ bool TargetTransformInfo::allowVectorElementIndexingUsingGEP() const {
return TTIImpl->allowVectorElementIndexingUsingGEP();
}
+bool TargetTransformInfo::allowLoadWidening() const {
+ return TTIImpl->allowLoadWidening();
+}
+
bool TargetTransformInfo::isUniform(const Instruction *I,
const SmallBitVector &UniformArgs) const {
return TTIImpl->isUniform(I, UniformArgs);
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h b/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h
index 5d9db79e6f8de..ffd46627cb81f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h
@@ -62,6 +62,8 @@ class SPIRVTTIImpl final : public BasicTTIImplBase<SPIRVTTIImpl> {
bool allowVectorElementIndexingUsingGEP() const override { return false; }
+ bool allowLoadWidening() const override { return false; }
+
bool isLegalMaskedGather(Type *DataType, Align Alignment) const override;
bool isLegalMaskedScatter(Type *DataType, Align Alignment) const override;
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 7a08eff6cc64d..4ec3386ceb9d3 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -228,12 +228,13 @@ static bool isEquivBitcast(Value *X, Value *Y) {
}
static bool canWidenLoad(LoadInst *Load, const TargetTransformInfo &TTI) {
- // Do not widen load if atomic/volatile or under asan/hwasan/memtag/tsan.
+ // Do not widen load if atomic/volatile or under asan/hwasan/memtag/tsan
+ // or if not supported by the target.
// The widened load may load data from dirty regions or create data races
// non-existent in the source.
if (!Load || !Load->isSimple() || !Load->hasOneUse() ||
Load->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag) ||
- mustSuppressSpeculation(*Load))
+ mustSuppressSpeculation(*Load) || !TTI.allowLoadWidening())
return false;
// We are potentially transforming byte-sized (8-bit) memory accesses, so make
diff --git a/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll b/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll
new file mode 100644
index 0000000000000..d6d93ef0a6852
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll
@@ -0,0 +1,37 @@
+; RUN: opt -S -passes=vector-combine -data-layout=E -mtriple=spirv-unknown-vulkan1.3-library %s | FileCheck %s
+
+; Ensure the loading of a splatted single scalar doesn't get widened.
+
+define <4 x float> @load_sf32_v4f32(ptr dereferenceable(16) %p) {
+; CHECK-LABEL: @load_sf32_v4f32(
+; CHECK-NEXT: [[L:%.*]] = load float, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[SP:%.*]] = insertelement <4 x float> poison, float [[L]], i64 0
+; CHECK-NEXT: [[SH:%.*]] = shufflevector <4 x float> [[SP]], <4 x float> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT: ret <4 x float> [[SH]]
+ %l = load float, ptr %p, align 4
+ %sp = insertelement <4 x float> poison, float %l, i64 0
+ %sh = shufflevector <4 x float> %sp, <4 x float> poison, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+ ret <4 x float> %sh
+}
+
+; Ensure the loading of a small vector doesn't get widened.
+
+define <4 x float> @load_v1f32_v4f32(ptr dereferenceable(16) %p) {
+; CHECK-LABEL: @load_v1f32_v4f32(
+; CHECK-NEXT: [[L:%.*]] = load <1 x float>, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[SH:%.*]] = shufflevector <1 x float> %l, <1 x float> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT: ret <4 x float> [[SH]]
+ %l = load <1 x float>, ptr %p, align 4
+ %s = shufflevector <1 x float> %l, <1 x float> poison, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+ ret <4 x float> %s
+}
+
+define <4 x float> @load_v2f32_v4f32(ptr align 16 dereferenceable(16) %p) {
+; CHECK-LABEL: @load_v2f32_v4f32(
+; CHECK-NEXT: [[L:%.*]] = load <2 x float>, ptr [[P:%.*]], align 16
+; CHECK-NEXT: [[SH:%.*]] = shufflevector <2 x float> [[L]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: ret <4 x float> [[SH]]
+ %l = load <2 x float>, ptr %p, align 16
+ %s = shufflevector <2 x float> %l, <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+ ret <4 x float> %s
+}
>From 2d446303335443692ee7a2419c6ea78ace9bf816 Mon Sep 17 00:00:00 2001
From: Gregory Roth <groth at nvidia.com>
Date: Wed, 30 Sep 2026 04:14:07 -0700
Subject: [PATCH 2/2] fix load-widening test usage of undefs
Replaced with poison
---
llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll b/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll
index d6d93ef0a6852..c3058a7db81f7 100644
--- a/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll
+++ b/llvm/test/Transforms/VectorCombine/SPIRV/load-widening.ll
@@ -10,7 +10,7 @@ define <4 x float> @load_sf32_v4f32(ptr dereferenceable(16) %p) {
; CHECK-NEXT: ret <4 x float> [[SH]]
%l = load float, ptr %p, align 4
%sp = insertelement <4 x float> poison, float %l, i64 0
- %sh = shufflevector <4 x float> %sp, <4 x float> poison, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+ %sh = shufflevector <4 x float> %sp, <4 x float> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
ret <4 x float> %sh
}
@@ -22,7 +22,7 @@ define <4 x float> @load_v1f32_v4f32(ptr dereferenceable(16) %p) {
; CHECK-NEXT: [[SH:%.*]] = shufflevector <1 x float> %l, <1 x float> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: ret <4 x float> [[SH]]
%l = load <1 x float>, ptr %p, align 4
- %s = shufflevector <1 x float> %l, <1 x float> poison, <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
+ %s = shufflevector <1 x float> %l, <1 x float> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
ret <4 x float> %s
}
@@ -32,6 +32,6 @@ define <4 x float> @load_v2f32_v4f32(ptr align 16 dereferenceable(16) %p) {
; CHECK-NEXT: [[SH:%.*]] = shufflevector <2 x float> [[L]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
; CHECK-NEXT: ret <4 x float> [[SH]]
%l = load <2 x float>, ptr %p, align 16
- %s = shufflevector <2 x float> %l, <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
+ %s = shufflevector <2 x float> %l, <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
ret <4 x float> %s
}
More information about the llvm-commits
mailing list