Skip to content

Commit c5c2623

Browse files
aratajewigcbot
authored andcommitted
Fix crashes encountered during the compilation of Blender kernels utilizing the SPV_INTEL_bindless_images extension
The latest version of Blender utilizes the SPV_INTEL_bindless_images extension in a moreadvanced manner, storing image and sampler handles in a global variable. This approach has posed a challenging stress test for the IGC's implementation of the SPV_INTEL_bindless_images extension, leading to compilation crashes. These crashes occur due to the use of ValueTracker, which is inappropriate for the SPV_INTEL_bindless_images extension since images are runtime values in this context. Consequently, this change disables value tracking for the purposes of: - handling SAMPLER_SNAP_WA - Image3dToImage2darray pass As a result, both the `SAMPLER_SNAP_WA` and `Image3dToImage2darray` pass are disabled for kernels utilizing the `SPV_INTEL_bindless_images` extension.
1 parent b13a1f8 commit c5c2623

File tree

10 files changed

+219
-5
lines changed

10 files changed

+219
-5
lines changed

IGC/AdaptorOCL/dllInterfaceCompute.cpp

+27-3
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,27 @@ bool CheckForImageUsage(const std::string & SPIRVBinary) {
458458
return it != textReport.Capabilities.end();
459459
}
460460

461+
void GenerateSPIRVExtensionsMD(llvm::LLVMContext& C, llvm::Module& M, const std::string& SPIRVBinary)
462+
{
463+
std::istringstream repIS(SPIRVBinary);
464+
std::optional<SPIRV::SPIRVModuleReport> report = IGCLLVM::makeOptional(SPIRV::getSpirvReport(repIS));
465+
466+
if (!report.has_value())
467+
return;
468+
469+
if (report->Extensions.empty())
470+
return;
471+
472+
std::vector<llvm::Metadata*> ExtensionsVec;
473+
for (const auto& E : report->Extensions)
474+
{
475+
ExtensionsVec.push_back(llvm::MDString::get(C, E));
476+
}
477+
478+
llvm::NamedMDNode* SPIRVExtensionsMD = M.getOrInsertNamedMetadata("igc.spirv.extensions");
479+
SPIRVExtensionsMD->addOperand(llvm::MDNode::get(C, ExtensionsVec));
480+
}
481+
461482
// Translate SPIR-V binary to LLVM Module
462483
bool TranslateSPIRVToLLVM(
463484
const STB_TranslateInputArgs& InputArgs,
@@ -505,18 +526,21 @@ bool TranslateSPIRVToLLVM(
505526
// Actual translation from SPIR-V to LLVM
506527
success = llvm::readSpirv(Context, Opts, IS, LLVMModule, stringErrMsg);
507528

508-
// Handle OpenCL Compiler Options
509529
if (success)
510530
{
511531
AssignNamesToUnnamedGlobalVariables(*LLVMModule);
512532

533+
// Handle OpenCL Compiler Options
513534
GenerateCompilerOptionsMD(
514535
Context,
515536
*LLVMModule,
516537
llvm::StringRef(InputArgs.pOptions, InputArgs.OptionsSize));
517538

518-
if (IGC_IS_FLAG_ENABLED(ShaderDumpTranslationOnly))
519-
LLVMModule->dump();
539+
// Parse SPIRV extensions and encode them as 'igc.spirv.extensions' metadata
540+
GenerateSPIRVExtensionsMD(Context, *LLVMModule, SPIRVBinary.str());
541+
542+
if (IGC_IS_FLAG_ENABLED(ShaderDumpTranslationOnly))
543+
LLVMModule->dump();
520544
}
521545

522546
return success;

IGC/Compiler/MetaDataApi/SpirMetaDataApi.h

+38
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ namespace IGC::SPIRMD
4444
using InnerCompilerExternalOptionsMetaDataList = MetaDataList<std::string>;
4545
using InnerCompilerExternalOptionsMetaDataListHandle = MetaObjectHandle<InnerCompilerExternalOptionsMetaDataList>;
4646

47+
using SPIRVExtensionsMetaDataList = MetaDataList<std::string>;
48+
using SPIRVExtensionsMetaDataListHandle = MetaObjectHandle<SPIRVExtensionsMetaDataList>;
49+
4750
class VersionMetaData : public IMetaDataObject
4851
{
4952
public:
@@ -555,6 +558,7 @@ namespace IGC::SPIRMD
555558
using UsedKhrExtensionsList = NamedMDNodeList<InnerUsedKhrExtensionsMetaDataListHandle>;
556559
using SpirVersionsList = NamedMDNodeList<VersionMetaDataHandle>;
557560
using OpenCLVersionsList = NamedMDNodeList<VersionMetaDataHandle>;
561+
using SPIRVExtensionsList = NamedMDNodeList<SPIRVExtensionsMetaDataListHandle>;
558562

559563
// If using this constructor, setting the llvm module by the setModule
560564
// function is needed for correct operation.
@@ -569,6 +573,7 @@ namespace IGC::SPIRMD
569573
m_UsedKhrExtensions(pModule->getNamedMetadata("opencl.used.extensions")),
570574
m_SpirVersions(pModule->getNamedMetadata("opencl.spir.version")),
571575
m_OpenCLVersions(pModule->getNamedMetadata("opencl.ocl.version")),
576+
m_SPIRVExtensions(pModule->getNamedMetadata("igc.spirv.extensions")),
572577
m_pModule(pModule)
573578
{}
574579

@@ -581,6 +586,7 @@ namespace IGC::SPIRMD
581586
m_UsedKhrExtensions = pModule->getNamedMetadata("opencl.used.extensions");
582587
m_SpirVersions = pModule->getNamedMetadata("opencl.spir.version");
583588
m_OpenCLVersions = pModule->getNamedMetadata("opencl.ocl.version");
589+
m_SPIRVExtensions = pModule->getNamedMetadata("igc.spirv.extensions");
584590
m_pModule = pModule;
585591
}
586592

@@ -834,6 +840,37 @@ namespace IGC::SPIRMD
834840
return m_OpenCLVersions.getItem(index);
835841
}
836842

843+
// SPIRV Extensions
844+
SPIRVExtensionsList::const_iterator begin_SPIRVExtensions() const
845+
{
846+
return m_SPIRVExtensions.begin();
847+
}
848+
849+
SPIRVExtensionsList::const_iterator end_SPIRVExtensions() const
850+
{
851+
return m_SPIRVExtensions.end();
852+
}
853+
854+
size_t size_SPIRVExtensions() const
855+
{
856+
return m_SPIRVExtensions.size();
857+
}
858+
859+
bool empty_SPIRVExtensions() const
860+
{
861+
return m_SPIRVExtensions.empty();
862+
}
863+
864+
bool isSPIRVExtensionsHasValue() const
865+
{
866+
return m_SPIRVExtensions.hasValue();
867+
}
868+
869+
const SPIRVExtensionsList::item_type getSPIRVExtensionsItem(size_t index) const
870+
{
871+
return m_SPIRVExtensions.getItem(index);
872+
}
873+
837874
void deleteMetadata()
838875
{
839876
llvm::NamedMDNode* KernelsNode = m_pModule->getNamedMetadata("opencl.kernels");
@@ -897,5 +934,6 @@ namespace IGC::SPIRMD
897934
UsedKhrExtensionsList m_UsedKhrExtensions;
898935
SpirVersionsList m_SpirVersions;
899936
OpenCLVersionsList m_OpenCLVersions;
937+
SPIRVExtensionsList m_SPIRVExtensions;
900938
};
901939
}

IGC/Compiler/Optimizer/OpenCLPasses/Image3dToImage2darray/Image3dToImage2darray.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,15 @@ bool Image3dToImage2darray::runOnFunction(Function& F)
152152
m_MetadataUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
153153
m_modMD = getAnalysis<MetaDataUtilsWrapper>().getModuleMetaData();
154154

155+
// This pass is not compatible with the SPV_INTEL_bindless_images extension.
156+
// The incompatibility arises because this pass requires images to be trackable
157+
// at compile time, a condition that bindless images from the SPV_INTEL_bindless_images
158+
// extension do not satisfy.
159+
if (m_modMD->extensions.spvINTELBindlessImages)
160+
{
161+
return false;
162+
}
163+
155164
if (m_MetadataUtils->findFunctionsInfoItem(&F) == m_MetadataUtils->end_FunctionsInfo())
156165
{
157166
return false;

IGC/Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncResolution.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,27 @@ Value* ImageFuncResolution::getSamplerProperty(CallInst& CI)
210210
{
211211
MetaDataUtils* pMdUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
212212
ModuleMetaData* modMD = getAnalysis<MetaDataUtilsWrapper>().getModuleMetaData();
213+
214+
if (ArgTy == ImplicitArg::SAMPLER_SNAP_WA && modMD->extensions.spvINTELBindlessImages)
215+
{
216+
// The snap_wa workaround is disabled for bindless images from the SPV_INTEL_bindless_images extension.
217+
// This is because the current implementation of the workaround requires the sampler to be known at compile-time,
218+
// either as an inline sampler or a kernel argument. This allows the UMD to program the
219+
// SAMPLER_SNAP_WA implicit argument, which indicates whether the workaround should be enabled.
220+
//
221+
// For bindless images from SPV_INTEL_bindless_images, image is represented as an i64 handle (bindlessOffset)
222+
// provided by the user. The handle is a runtime value and cannot be tracked to a kernel argument at compile-time.
223+
// Therefore, implementing snap_wa would require a completely new approach.
224+
//
225+
// The absence of reported sampling issues with images from SPV_INTEL_bindless_images suggests that snap_wa
226+
// might not be necessary. However, further investigation is required.
227+
//
228+
// If snap_wa is found to be unnecessary, the workaround for OpenCL images can be removed.
229+
// Conversely, if hardware constraints necessitate it, the workaround must be enabled for
230+
// images from from SPV_INTEL_bindless_images extension.
231+
return ConstantInt::get(CI.getType(), 0);
232+
}
233+
213234
if (Value* sampler = ValueTracker::track(&CI, 0, pMdUtils, modMD))
214235
{
215236
auto *arg = dyn_cast<Argument>(sampler);

IGC/Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncsAnalysis.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ bool ImageFuncsAnalysis::runOnModule(Module& M) {
5959
m_useAdvancedBindlessMode = ctx->getModuleMetaData()->compOpt.UseBindlessMode &&
6060
!ctx->getModuleMetaData()->compOpt.UseLegacyBindlessMode;
6161

62+
m_useSPVINTELBindlessImages = ctx->getModuleMetaData()->extensions.spvINTELBindlessImages;
63+
6264
// Run on all functions defined in this module
6365
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
6466
Function* pFunc = &(*I);
@@ -144,7 +146,9 @@ void ImageFuncsAnalysis::visitCallInst(CallInst& CI)
144146
{
145147
imageFunc = &m_argMap[ImplicitArg::SAMPLER_NORMALIZED];
146148
}
147-
else if (funcName == GET_SAMPLER_SNAP_WA_REQUIRED)
149+
// The SNAP_WA is disabled for SPV_INTEL_bindless_images extension.
150+
// For further information, refer to the ImageFuncResolution.cpp file.
151+
else if (funcName == GET_SAMPLER_SNAP_WA_REQUIRED && !m_useSPVINTELBindlessImages)
148152
{
149153
imageFunc = &m_argMap[ImplicitArg::SAMPLER_SNAP_WA];
150154
}

IGC/Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncsAnalysis.hpp

+12
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,18 @@ namespace IGC
107107
/// If false, implicit image args for information like width, height, etc.
108108
/// will be added to m_argMap
109109
bool m_useAdvancedBindlessMode{};
110+
111+
// @brief Handling of image/sampler properties query functions varies based on image type.
112+
//
113+
// This distinction arises between standard OpenCL images and bindless images
114+
// from the SPV_INTEL_bindless_images extension.
115+
//
116+
// For example: the __builtin_IB_get_snap_wa_reqd function is lowered to an
117+
// implicit argument, SAMPLER_SNAP_WA, for standard OpenCL images.
118+
// However, for bindless images from the SPV_INTEL_bindless_images extension,
119+
// the snap_wa is unsupported. Consequently, it is effectively disabled
120+
// by being lowered to a ConstantInt value of 0.
121+
bool m_useSPVINTELBindlessImages{};
110122
};
111123

112124
} // namespace IGC

IGC/Compiler/SPIRMetaDataTranslation.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,20 @@ bool SPIRMetaDataTranslation::runOnModule(Module& M)
389389
modMD->compOpt.MadEnable = true;
390390
}
391391

392+
// Ensure that the extensions listed in the 'igc.spirv.extensions' metadata are
393+
// reflected within the ModuleMetaData->extensions
394+
if (!spirMDUtils.empty_SPIRVExtensions())
395+
{
396+
auto extensions = spirMDUtils.getSPIRVExtensionsItem(0);
397+
for (const auto& spirvExtension : *extensions)
398+
{
399+
if (spirvExtension == "SPV_INTEL_bindless_images")
400+
{
401+
modMD->extensions.spvINTELBindlessImages = true;
402+
}
403+
}
404+
}
405+
392406
spirMDUtils.deleteMetadata();
393407

394408
pIgcMDUtils->save(M.getContext());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
; This test verifies if snap_wa is effectively disabled for SPV_INTEL_bindless_images extension.
10+
11+
; The snap_wa workaround is disabled for bindless images from the SPV_INTEL_bindless_images extension.
12+
; This is because the current implementation of the workaround requires the sampler to be known at compile-time,
13+
; either as an inline sampler or a kernel argument. This allows the UMD to program the
14+
; SAMPLER_SNAP_WA implicit argument, which indicates whether the workaround should be enabled.
15+
;
16+
; For bindless images from SPV_INTEL_bindless_images, image is represented as an i64 handle (bindlessOffset)
17+
; provided by the user. The handle is a runtime value and cannot be tracked to a kernel argument at compile-time.
18+
; Therefore, implementing snap_wa would require a completely new approach.
19+
20+
; REQUIRES: llvm-14-plus
21+
; RUN: igc_opt --opaque-pointers -igc-image-func-resolution -S %s -o %t.ll
22+
; RUN: FileCheck %s --input-file=%t.ll
23+
24+
%spirv.Sampler = type opaque
25+
26+
declare i32 @__builtin_IB_get_snap_wa_reqd(i32)
27+
28+
define i32 @foo(i32 %sampler_handle) nounwind {
29+
; CHECK-NOT: call i32 @__builtin_IB_get_snap_wa_reqd(i32 %sampler_handle)
30+
%id = call i32 @__builtin_IB_get_snap_wa_reqd(i32 %sampler_handle)
31+
; CHECK: ret i32 0
32+
ret i32 %id
33+
}
34+
35+
!IGCMetadata = !{!0}
36+
!igc.functions = !{!3}
37+
38+
!0 = !{!"ModuleMD", !1}
39+
!1 = !{!"extensions", !2}
40+
!2 = !{!"spvINTELBindlessImages", i1 true}
41+
!3 = !{i32 (i32)* @foo, !1}
42+
!4 = !{ptr @foo, !5}
43+
!5 = !{!5, !6}
44+
!6 = !{!"function_type", i32 0}

IGC/common/MDFrameWork.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -709,10 +709,22 @@ enum class ShaderTypeMD
709709

710710
struct SPIRVCapabilities
711711
{
712-
713712
bool globalVariableDecorationsINTEL = false;
714713
};
715714

715+
struct SPIRVExtensions
716+
{
717+
// IGC must distinguish between SPIRV compilations that utilize standard
718+
// OpenCL images and those using Bindless images from the
719+
// SPV_INTEL_bindless_images extension. Currently, OpenCL images require the
720+
// valueTracker to be addressed using the bindless addressing model. This is
721+
// because IGC needs to insert a bindlessOffset as an implicit argument for
722+
// tracked images. Conversely, for bindless images originating from
723+
// SPV_INTEL_bindless_images, the bindlessOffset is supplied by the user as a
724+
// kernel argument, eliminating the need for IGC to perform tracking.
725+
bool spvINTELBindlessImages = false;
726+
};
727+
716728
//metadata for the entire module
717729
struct ModuleMetaData
718730
{
@@ -783,6 +795,7 @@ enum class ShaderTypeMD
783795
std::set<std::string> m_OptsToDisable;
784796

785797
SPIRVCapabilities capabilities;
798+
SPIRVExtensions extensions;
786799

787800
std::array<uint64_t, NUM_SHADER_RESOURCE_VIEW_SIZE> m_ShaderResourceViewMcsMask{};
788801
unsigned int computedDepthMode = 0; //Defaults to 0 meaning depth mode is off
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
; REQUIRES: llvm-spirv, regkeys, dg2-supported
10+
11+
; RUN: llvm-as %s -o %t.bc
12+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_bindless_images -o %t.spv
13+
; RUN: ocloc compile -spirv_input -file %t.spv -device dg2 -options " -igc_opts 'PrintToConsole=1 PrintAfter=igc-spir-metadata-translation'" 2>&1 | FileCheck %s
14+
15+
; CHECK: !{!"spvINTELBindlessImages", i1 true}
16+
17+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
18+
target triple = "spir64-unknown-unknown"
19+
20+
%spirv.SampledImage._void_1_0_0_0_0_0_0 = type opaque
21+
22+
define spir_func void @foo(i64 %in) {
23+
%img = call spir_func %spirv.SampledImage._void_1_0_0_0_0_0_0 addrspace(1)* @_Z90__spirv_ConvertHandleToSampledImageINTEL_RPU3AS140__spirv_SampledImage__void_1_0_0_0_0_0_0m(i64 %in)
24+
ret void
25+
}
26+
27+
declare spir_func %spirv.SampledImage._void_1_0_0_0_0_0_0 addrspace(1)* @_Z90__spirv_ConvertHandleToSampledImageINTEL_RPU3AS140__spirv_SampledImage__void_1_0_0_0_0_0_0m(i64)
28+
29+
!opencl.spir.version = !{!0}
30+
!spirv.Source = !{!1}
31+
!llvm.ident = !{!2}
32+
33+
!0 = !{i32 1, i32 2}
34+
!1 = !{i32 4, i32 100000}
35+
!2 = !{!"clang version 14.0.0"}

0 commit comments

Comments
 (0)