[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