From 0c2855062ac84dbe9a2b770a3cf7aad6a51df624 Mon Sep 17 00:00:00 2001 From: "Ye, Qi" Date: Mon, 13 Jul 2026 12:23:19 -0700 Subject: [PATCH 1/2] [Backport to 15] Use SPV_EXT_long_vector extension for non-standard vector size (#3777) For a vector type, add `SPV_EXT_long_vector` extension and prioritize it over `SPV_INTEL_vector_compute` whenever the vector type doesn't have a standard component size (2, 3, 4, 8, or 16). --- include/LLVMSPIRVExtensions.inc | 1 + lib/SPIRV/SPIRVWriter.cpp | 14 ++++++++++ lib/SPIRV/libSPIRV/SPIRVEntry.h | 2 ++ lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h | 1 + lib/SPIRV/libSPIRV/SPIRVType.h | 13 ++++++--- .../priority_over_vector_compute.ll | 16 +++++++++++ .../priority_over_vector_compute_size_5.ll | 16 +++++++++++ .../EXT/SPV_EXT_long_vector/vector_size_1.ll | 28 +++++++++++++++++++ .../EXT/SPV_EXT_long_vector/vector_size_5.ll | 28 +++++++++++++++++++ 9 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute.ll create mode 100644 test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute_size_5.ll create mode 100644 test/extensions/EXT/SPV_EXT_long_vector/vector_size_1.ll create mode 100644 test/extensions/EXT/SPV_EXT_long_vector/vector_size_5.ll diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc index 19fb7fde09..cf801e4c92 100644 --- a/include/LLVMSPIRVExtensions.inc +++ b/include/LLVMSPIRVExtensions.inc @@ -92,3 +92,4 @@ EXT(SPV_INTEL_sigmoid) EXT(SPV_INTEL_float4) EXT(SPV_INTEL_fp_conversions) EXT(SPV_INTEL_rounded_divide_sqrt) +EXT(SPV_EXT_long_vector) diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 2fc6e9c4aa..be7f4c0495 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -359,6 +359,20 @@ SPIRVType *LLVMToSPIRVBase::transType(Type *T) { } if (auto *VecTy = dyn_cast(T)) { + unsigned NumElements = VecTy->getNumElements(); + bool IsNonStandardCount = + !(NumElements == 2 || NumElements == 3 || NumElements == 4 || + NumElements == 8 || NumElements == 16); + if (IsNonStandardCount && + !BM->isAllowedToUseExtension(ExtensionID::SPV_EXT_long_vector) && + !BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_vector_compute)) { + BM->getErrorLog().checkError( + false, SPIRVEC_RequiresExtension, + "SPV_EXT_long_vector or SPV_INTEL_vector_compute\n" + "NOTE: LLVM module contains a vector with an unsupported number of " + "components, translation of which requires one of these extensions"); + return nullptr; + } if (VecTy->getElementType()->isPointerTy()) { // SPV_INTEL_masked_gather_scatter extension changes 2.16.1. Universal // Validation Rules: diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h index 0ece8175db..db25df964f 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -913,6 +913,8 @@ class SPIRVCapability : public SPIRVEntryNoId { return ExtensionID::SPV_INTEL_rounded_divide_sqrt; case internal::CapabilityDeviceBarrierINTEL: return ExtensionID::SPV_INTEL_device_barrier; + case CapabilityLongVectorEXT: + return ExtensionID::SPV_EXT_long_vector; default: return {}; } diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index 1c7c488439..a6ac440743 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -608,6 +608,7 @@ template <> inline void SPIRVMap::init() { add(CapabilityLongCompositesINTEL, "LongCompositesINTEL"); add(CapabilityOptNoneEXT, "OptNoneEXT"); add(CapabilityAtomicFloat16AddEXT, "AtomicFloat16AddEXT"); + add(CapabilityLongVectorEXT, "LongVectorEXT"); add(CapabilityDebugInfoModuleINTEL, "DebugInfoModuleINTEL"); add(CapabilitySplitBarrierINTEL, "SplitBarrierINTEL"); add(CapabilityGlobalVariableFPGADecorationsINTEL, diff --git a/lib/SPIRV/libSPIRV/SPIRVType.h b/lib/SPIRV/libSPIRV/SPIRVType.h index e8c508d03a..5ac1776865 100644 --- a/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/lib/SPIRV/libSPIRV/SPIRVType.h @@ -383,10 +383,14 @@ class SPIRVTypeVector : public SPIRVType { if (CompCount == 8 || CompCount == 16) V.push_back(CapabilityVector16); - if (Module->isAllowedToUseExtension(ExtensionID::SPV_INTEL_vector_compute)) - if (CompCount == 1 || (CompCount > 4 && CompCount < 8) || - (CompCount > 8 && CompCount < 16) || CompCount > 16) + if (CompCount == 1 || (CompCount > 4 && CompCount < 8) || + (CompCount > 8 && CompCount < 16) || CompCount > 16) { + if (Module->isAllowedToUseExtension(ExtensionID::SPV_EXT_long_vector)) + V.push_back(CapabilityLongVectorEXT); + else if (Module->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_vector_compute)) V.push_back(CapabilityVectorAnyINTEL); + } return V; } @@ -400,7 +404,8 @@ class SPIRVTypeVector : public SPIRVType { SPIRVEntry::validate(); CompType->validate(); #ifndef NDEBUG - if (!(Module->isAllowedToUseExtension( + if (!Module->isAllowedToUseExtension(ExtensionID::SPV_EXT_long_vector) && + !(Module->isAllowedToUseExtension( ExtensionID::SPV_INTEL_vector_compute))) { assert(CompCount == 2 || CompCount == 3 || CompCount == 4 || CompCount == 8 || CompCount == 16); diff --git a/test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute.ll b/test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute.ll new file mode 100644 index 0000000000..4c463c98e3 --- /dev/null +++ b/test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_long_vector,+SPV_INTEL_vector_compute -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --implicit-check-not="Capability VectorAnyINTEL" +; TODO: re-enable spirv-val once it can recognize LongVectorEXT capability (5425). +; RUNx: spirv-val %t.spv + +; CHECK-DAG: Capability LongVectorEXT +; CHECK-DAG: Extension "SPV_EXT_long_vector" + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +define spir_func void @test_vec1(<1 x float> %v) { +entry: + ret void +} diff --git a/test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute_size_5.ll b/test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute_size_5.ll new file mode 100644 index 0000000000..3896044ccc --- /dev/null +++ b/test/extensions/EXT/SPV_EXT_long_vector/priority_over_vector_compute_size_5.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_long_vector,+SPV_INTEL_vector_compute -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --implicit-check-not="Capability VectorAnyINTEL" +; TODO: re-enable spirv-val once it can recognize LongVectorEXT capability (5425). +; RUNx: spirv-val %t.spv + +; CHECK-DAG: Capability LongVectorEXT +; CHECK-DAG: Extension "SPV_EXT_long_vector" + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +define spir_func void @test_vec5(<5 x float> %v) { +entry: + ret void +} diff --git a/test/extensions/EXT/SPV_EXT_long_vector/vector_size_1.ll b/test/extensions/EXT/SPV_EXT_long_vector/vector_size_1.ll new file mode 100644 index 0000000000..3b1c8ff01e --- /dev/null +++ b/test/extensions/EXT/SPV_EXT_long_vector/vector_size_1.ll @@ -0,0 +1,28 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_long_vector -o %t.spv +; TODO: re-enable spirv-val once it can recognize LongVectorEXT capability (5425). +; RUNx: spirv-val %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s + +; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s --check-prefix=ERROR + +; CHECK-DAG: Capability LongVectorEXT +; CHECK-DAG: Extension "SPV_EXT_long_vector" +; CHECK-DAG: TypeFloat [[#F32:]] 32 +; CHECK-DAG: TypeVector [[#]] [[#F32]] 1 + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +define spir_func void @test_vec1(<1 x float> %v1) { +entry: + ret void +} + +; ERROR: RequiresExtension: Feature requires the following SPIR-V extension: +; ERROR-NEXT: SPV_EXT_long_vector or SPV_INTEL_vector_compute + +define spir_func void @test_no_ext(<1 x float> %v) { +entry: + ret void +} diff --git a/test/extensions/EXT/SPV_EXT_long_vector/vector_size_5.ll b/test/extensions/EXT/SPV_EXT_long_vector/vector_size_5.ll new file mode 100644 index 0000000000..8fbd757343 --- /dev/null +++ b/test/extensions/EXT/SPV_EXT_long_vector/vector_size_5.ll @@ -0,0 +1,28 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_long_vector -o %t.spv +; TODO: re-enable spirv-val once it can recognize LongVectorEXT capability (5425). +; RUNx: spirv-val %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s + +; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s --check-prefix=ERROR + +; CHECK-DAG: Capability LongVectorEXT +; CHECK-DAG: Extension "SPV_EXT_long_vector" +; CHECK-DAG: TypeFloat [[#F32:]] 32 +; CHECK-DAG: TypeVector [[#]] [[#F32]] 5 + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +define spir_func void @test_vec5(<5 x float> %v) { +entry: + ret void +} + +; ERROR: RequiresExtension: Feature requires the following SPIR-V extension: +; ERROR-NEXT: SPV_EXT_long_vector or SPV_INTEL_vector_compute + +define spir_func void @test_no_ext(<5 x float> %v) { +entry: + ret void +} From d1158d91a540d3abd7d4b6b9d84fe6b0cc047743 Mon Sep 17 00:00:00 2001 From: "Ye, Qi" Date: Mon, 13 Jul 2026 12:25:43 -0700 Subject: [PATCH 2/2] [Backport to 15] Keep VectorAnyINTEL for VectorCompute modules with SPV_EXT_long_vector (#3829) `SPV_INTEL_vector_compute`: when both extensions are enabled and a vector has a non-standard component count, the translator now emits `CapabilityLongVectorEXT` instead of `CapabilityVectorAnyINTEL`. This regresses `VectorCompute` modules. The offloading flow (producing both `VectorCompute` and non-`VectorCompute` modules) applies a single, fixed extension list uniformly to every device image, so a `VectorCompute` module is translated with both `SPV_INTEL_vector_compute` and `SPV_EXT_long_vector` enabled. Before vectors; after #3777 it emits `LongVectorEXT`. `VectorCompute` consumers require `VectorAnyINTEL`, so this is a functional regression. Hence, the enabled extension list does not identify a module as `VectorCompute` - the `VectorCompute` metadata (`VCFunction` /`VCGlobalVariable`) does. `IsVectorComputeModule` records the presence of that metadata before type translation. `VectorCompute` modules keep using `VectorAnyINTEL`, restoring the pre-#3777 behavior; all other modules still prefer the multi-vendor `LongVectorEXT` when its extension is enabled. --------- Co-authored-by: Ye, Qi --- lib/SPIRV/SPIRVWriter.cpp | 17 ++++++++++++++ lib/SPIRV/libSPIRV/SPIRVModule.h | 3 +++ lib/SPIRV/libSPIRV/SPIRVType.h | 5 ++++- .../prioritize_over_LongVecEXT_func.ll | 22 +++++++++++++++++++ .../prioritize_over_LongVecEXT_global.ll | 19 ++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_func.ll create mode 100644 test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_global.ll diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index be7f4c0495..b2f8dbc51f 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -5105,12 +5105,29 @@ bool isEmptyLLVMModule(Module *M) { M->global_empty(); // No global variables } +// A module is VectorCompute when any function or global variable carries +// VectorCompute metadata. +static bool hasVectorComputeMetadata(Module *M) { + return any_of(*M, + [](const Function &F) { + return F.hasFnAttribute(kVCMetadata::VCFunction); + }) || + any_of(M->globals(), [](const GlobalVariable &GV) { + return GV.hasAttribute(kVCMetadata::VCGlobalVariable); + }); +} + bool LLVMToSPIRVBase::translate() { BM->setGeneratorVer(KTranslatorVer); if (isEmptyLLVMModule(M)) BM->addCapability(CapabilityLinkage); + // Check before type translation so that SPIRVTypeVector can choose the + // matching capability. + if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_vector_compute)) + BM->setVectorCompute(hasVectorComputeMetadata(M)); + // Use the type scavenger to recover pointer element types. Scavenger = std::make_unique(*M); diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.h b/lib/SPIRV/libSPIRV/SPIRVModule.h index 269470b6d3..d634986c1e 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -139,6 +139,8 @@ class SPIRVModule { const std::string &) = 0; void setInvalid() { IsValid = false; } bool isModuleValid() { return IsValid; } + void setVectorCompute(bool E) { IsVectorCompute = E; } + bool isVectorCompute() const { return IsVectorCompute; } // Module query functions virtual SPIRVAddressingModelKind getAddressingModel() = 0; @@ -648,6 +650,7 @@ class SPIRVModule { private: bool IsValid; + bool IsVectorCompute = false; }; #ifdef _SPIRV_SUPPORT_TEXT_FMT diff --git a/lib/SPIRV/libSPIRV/SPIRVType.h b/lib/SPIRV/libSPIRV/SPIRVType.h index 5ac1776865..909a7ba4d4 100644 --- a/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/lib/SPIRV/libSPIRV/SPIRVType.h @@ -385,7 +385,10 @@ class SPIRVTypeVector : public SPIRVType { if (CompCount == 1 || (CompCount > 4 && CompCount < 8) || (CompCount > 8 && CompCount < 16) || CompCount > 16) { - if (Module->isAllowedToUseExtension(ExtensionID::SPV_EXT_long_vector)) + // A VectorCompute module keeps using CapabilityVectorAnyINTEL; + // otherwise use multi-vendor LongVectorEXT + if (!Module->isVectorCompute() && + Module->isAllowedToUseExtension(ExtensionID::SPV_EXT_long_vector)) V.push_back(CapabilityLongVectorEXT); else if (Module->isAllowedToUseExtension( ExtensionID::SPV_INTEL_vector_compute)) diff --git a/test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_func.ll b/test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_func.ll new file mode 100644 index 0000000000..639dfe5988 --- /dev/null +++ b/test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_func.ll @@ -0,0 +1,22 @@ +; A VectorCompute module (detected via VCFunction metadata) keeps using +; VectorAnyINTEL and SPV_INTEL_vector_compute for a non-standard vector size, +; even when SPV_EXT_long_vector is also enabled. + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_long_vector,+SPV_INTEL_vector_compute -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --implicit-check-not="Capability LongVectorEXT" --implicit-check-not='Extension "SPV_EXT_long_vector"' + +; CHECK-DAG: Capability VectorAnyINTEL +; CHECK-DAG: Extension "SPV_INTEL_vector_compute" +; CHECK-DAG: TypeFloat [[#F32:]] 32 +; CHECK-DAG: TypeVector [[#]] [[#F32]] 5 + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +define spir_func void @test_vc(<5 x float> %v) #0 { +entry: + ret void +} + +attributes #0 = { "VCFunction" } diff --git a/test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_global.ll b/test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_global.ll new file mode 100644 index 0000000000..e4eceb5cb0 --- /dev/null +++ b/test/transcoding/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_global.ll @@ -0,0 +1,19 @@ +; A VectorCompute module (detected via VCGlobalVariable metadata) keeps using +; VectorAnyINTEL and SPV_INTEL_vector_compute for a non-standard vector size, +; even when SPV_EXT_long_vector is also enabled. + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_long_vector,+SPV_INTEL_vector_compute -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --implicit-check-not="Capability LongVectorEXT" --implicit-check-not='Extension "SPV_EXT_long_vector"' + +; CHECK-DAG: Capability VectorAnyINTEL +; CHECK-DAG: Extension "SPV_INTEL_vector_compute" +; CHECK-DAG: TypeFloat [[#F32:]] 32 +; CHECK-DAG: TypeVector [[#]] [[#F32]] 5 + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +@gv = internal addrspace(1) global <5 x float> zeroinitializer #0 + +attributes #0 = { "VCGlobalVariable" }