Skip to content

Commit e899d0b

Browse files
michalpaszkowskiigcbot
authored andcommitted
Fix inlining of non-kernel funcs with SPIR-V image args
Before the migration to opaque pointers, the inlining logic in ProcessFuncAttributes decided to inline functions based on the actual type of an argument. With typed pointers, SPIR-V/OpenCL images were represented using pointers to opaque structs (allowing to recognize the image type by parsing the struct name). With opauqe pointers, such types are represented using TargetExtTy. However, TargetExtTy are missing at this point during compilation due to earlier retyping (to opaque pointers) in PreprocessSPVIR. Hence, this change allows recognition of such types based on metadata hints. Analogous metadata are already emitted for kernel functions by SPIR-V Reader.
1 parent 35cbc48 commit e899d0b

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

IGC/AdaptorCommon/ProcessFuncAttributes.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,30 @@ ModulePass *createProcessFuncAttributesPass() { return new ProcessFuncAttributes
267267

268268
extern bool isSupportedAggregateArgument(Argument *arg);
269269

270+
static bool hasImageTypesInMetadataTypeHints(Function *F, ModuleMetaData *ModMD) {
271+
auto It = ModMD->FuncMD.find(F);
272+
if (It != ModMD->FuncMD.end()) {
273+
const FunctionMetaData &FuncMD = It->second;
274+
IGC_ASSERT_MESSAGE(FuncMD.m_OpenCLArgBaseTypes.size() == F->arg_size(),
275+
"m_OpenCLArgBaseTypes and function argument size mismatch!");
276+
277+
for (const auto &BaseTy : FuncMD.m_OpenCLArgBaseTypes) {
278+
if (BaseTy.find("image") != std::string::npos)
279+
return true;
280+
}
281+
}
282+
283+
MDNode *Hints = F->getMetadata("non_kernel_arg_type_hints");
284+
if (Hints) {
285+
for (auto &Operand : Hints->operands())
286+
if (MDString *MDStr = dyn_cast<MDString>(Operand))
287+
if (MDStr->getString().contains_insensitive("image"))
288+
return true;
289+
}
290+
291+
return false;
292+
}
293+
270294
// Only pointer, struct and array types are considered. E.g. vector type
271295
// cannot contain opaque subtypes, function type may contain but ignored.
272296
static void getBuiltinType(Type *T, SmallPtrSetImpl<Type *> &BuiltinTypes) {
@@ -688,12 +712,18 @@ bool ProcessFuncAttributes::runOnModule(Module &M) {
688712
// Curently, ExtensionArgAnalysis assumes that all functions with image arguments
689713
// to be inlined. We add always inline for such cases.
690714
for (auto &arg : F->args()) {
715+
// TODO: Remove following the migration to opaque pointers. The following method won't be able to recognize
716+
// builtin types. TargetExtTy information is lost at this point (following the retyping in PreprocessSPVIR) and
717+
// type hints in the metadata should be used instead, see hasImageTypesInMetadataTypeHints below.
691718
if (containsImageType(arg.getType())) {
692719
mustAlwaysInline = true;
693720
break;
694721
}
695722
}
696723

724+
if (hasImageTypesInMetadataTypeHints(F, modMD))
725+
mustAlwaysInline = true;
726+
697727
if (pCtx->m_hasDPEmu && !mustAlwaysInline && !isKernel) {
698728
// Prefer stackcall if a func has double operations
699729
bool isSet = false;

IGC/AdaptorOCL/preprocess_spvir/PreprocessSPVIR.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,30 @@ void PreprocessSPVIR::visitCallInst(CallInst &CI) {
159159
}
160160
}
161161

162+
#if LLVM_VERSION_MAJOR >= 16
163+
static void addNonKernelFuncsArgTypeHints(Module &M) {
164+
for (Function &F : M) {
165+
if (F.isDeclaration() || F.getCallingConv() != CallingConv::SPIR_FUNC)
166+
continue;
167+
168+
SmallVector<Metadata *, 8> Hints;
169+
for (Argument &Arg : F.args()) {
170+
Type *ArgTy = Arg.getType();
171+
172+
// Hints are needed only for SPIR-V builtin types.
173+
std::string HintValue = "";
174+
if (TargetExtType *TET = dyn_cast<TargetExtType>(ArgTy))
175+
HintValue = TET->getTargetExtName();
176+
177+
Hints.push_back(MDString::get(M.getContext(), HintValue));
178+
}
179+
180+
MDNode *Node = MDNode::get(M.getContext(), Hints);
181+
F.setMetadata("non_kernel_arg_type_hints", Node);
182+
}
183+
}
184+
#endif
185+
162186
static void fixKernelArgBaseTypes(Module &M) {
163187
LLVMContext &Ctx = M.getContext();
164188

@@ -232,6 +256,14 @@ bool PreprocessSPVIR::runOnModule(Module &M) {
232256
// incorrect and inconsistent with the prior behavior.
233257
fixKernelArgBaseTypes(M);
234258

259+
#if LLVM_VERSION_MAJOR >= 16
260+
// Add SPIR-V builtin type hints as metadata to non-kernel functions. Kernel functions already have metadata type
261+
// hints added by the SPIR-V Reader. Type hints for non-kernel functions are not strictly required, but allow us to
262+
// apply certain optimizations (e.g. inlining) without doing costly type deduction. Adding type hints is easier before
263+
// retyping since we can rely on TargetExtTy information.
264+
addNonKernelFuncsArgTypeHints(M);
265+
#endif
266+
235267
// Retype function arguments of OpenCL types represented as TargetExtTy to
236268
// use opaque pointers instead. This is necessary to match function
237269
// signatures generated by Clang, given that it only has partial TargetExtTy
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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-16-plus
10+
; RUN: igc_opt --opaque-pointers -igc-preprocess-spvir -S < %s | FileCheck %s --check-prefixes=CHECK-A
11+
; RUN: igc_opt --opaque-pointers -igc-preprocess-spvir -igc-process-func-attributes -S < %s | FileCheck %s --check-prefixes=CHECK-B
12+
13+
; CHECK-A: !non_kernel_arg_type_hints ![[#NODE:]]
14+
; CHECK-A: ![[#NODE:]] = !{!"spirv.Image", !"spirv.SampledImage"}
15+
; CHECK-B: alwaysinline
16+
17+
define spir_func void @testNonKernel(target("spirv.Image", void, 0, 0, 0, 0, 0, 0, 2) %img, target("spirv.SampledImage", void, 1, 1, 0, 0, 0, 0, 0) %sampledImg) {
18+
ret void
19+
}

0 commit comments

Comments
 (0)