diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc index c46c642064..c8493c6f99 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 6fbfae5a28..eb17621c52 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -351,6 +351,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 @@ -5672,12 +5686,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 93423aa218..8d893ad64f 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -916,6 +916,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 6ce12d5c51..516225b30d 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; @@ -646,6 +648,7 @@ class SPIRVModule { private: bool IsValid; + bool IsVectorCompute = false; }; diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index f96758495a..96c27eef6d 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -624,6 +624,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 70faf957ef..35e3b07b36 100644 --- a/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/lib/SPIRV/libSPIRV/SPIRVType.h @@ -383,10 +383,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; } @@ -400,7 +407,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" }