diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc index cd8966619d..f48a0e442d 100644 --- a/include/LLVMSPIRVExtensions.inc +++ b/include/LLVMSPIRVExtensions.inc @@ -94,3 +94,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 3fe4f54e93..c70f24597e 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -426,6 +426,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() || isa(VecTy->getElementType())) { // SPV_INTEL_masked_gather_scatter extension changes 2.16.1. Universal @@ -6244,12 +6258,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)); + if (!lowerBuiltinCallsToVariables(M)) return false; diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h index a5be437d8a..c9ae4ef3ee 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -922,6 +922,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/SPIRVModule.h b/lib/SPIRV/libSPIRV/SPIRVModule.h index 12fe72a3f6..ba27140b0f 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -141,6 +141,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; @@ -666,6 +668,7 @@ class SPIRVModule { private: bool IsValid; + bool IsVectorCompute = false; }; #ifdef _SPIRV_SUPPORT_TEXT_FMT diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index 5f3d8c1eb3..52b74bc0ce 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -630,6 +630,7 @@ template <> inline void SPIRVMap::init() { add(CapabilityLongCompositesINTEL, "LongCompositesINTEL"); add(CapabilityOptNoneEXT, "OptNoneEXT"); add(CapabilityAtomicFloat16AddEXT, "AtomicFloat16AddEXT"); + add(CapabilityLongVectorEXT, "LongVectorEXT"); add(internal::CapabilityAtomicBFloat16AddINTEL, "AtomicBFloat16AddINTEL"); add(internal::CapabilityAtomicBFloat16MinMaxINTEL, "AtomicBFloat16MinMaxINTEL"); diff --git a/lib/SPIRV/libSPIRV/SPIRVType.h b/lib/SPIRV/libSPIRV/SPIRVType.h index dcd6834b15..e770c9c9ec 100644 --- a/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/lib/SPIRV/libSPIRV/SPIRVType.h @@ -430,10 +430,17 @@ 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) { + // 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)) V.push_back(CapabilityVectorAnyINTEL); + } return V; } @@ -447,7 +454,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 +} diff --git a/test/extensions/INTEL/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_func.ll b/test/extensions/INTEL/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_func.ll new file mode 100644 index 0000000000..639dfe5988 --- /dev/null +++ b/test/extensions/INTEL/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/extensions/INTEL/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_global.ll b/test/extensions/INTEL/SPV_INTEL_vector_compute/prioritize_over_LongVecEXT_global.ll new file mode 100644 index 0000000000..e4eceb5cb0 --- /dev/null +++ b/test/extensions/INTEL/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" }