@@ -138,31 +138,31 @@ static void getContainedStructType(Type *T, SmallPtrSetImpl<StructType *> &Tys)
138
138
}
139
139
}
140
140
141
+ static bool isImageType (llvm::Type *Ty)
142
+ {
143
+ if (auto *STy = dyn_cast<StructType>(Ty); STy && STy->isOpaque ())
144
+ {
145
+ auto typeName = STy->getName ();
146
+ llvm::SmallVector<llvm::StringRef, 3 > buf;
147
+ typeName.split (buf, " ." );
148
+ if (buf.size () < 2 ) return false ;
149
+ bool isOpenCLImage = buf[0 ].equals (" opencl" ) && buf[1 ].startswith (" image" ) && buf[1 ].endswith (" _t" );
150
+ bool isSPIRVImage = buf[0 ].equals (" spirv" ) && (buf[1 ].startswith (" Image" ) || buf[1 ].startswith (" SampledImage" ));
151
+
152
+ if (isOpenCLImage || isSPIRVImage)
153
+ return true ;
154
+ }
155
+ return false ;
156
+ }
157
+
141
158
// Check the existence of an image type.
142
159
static bool containsImageType (llvm::Type *T)
143
160
{
144
161
// All (nested) struct types in T.
145
162
SmallPtrSet<StructType *, 8 > StructTys;
146
163
getContainedStructType (T, StructTys);
147
164
148
- for (auto I = StructTys.begin (), E = StructTys.end (); I != E; ++I)
149
- {
150
- StructType *ST = *I;
151
- if (ST->isOpaque ())
152
- {
153
- auto typeName = ST->getName ();
154
- llvm::SmallVector<llvm::StringRef, 3 > buf;
155
- typeName.split (buf, " ." );
156
- if (buf.size () < 2 ) return false ;
157
- bool isOpenCLImage = buf[0 ].equals (" opencl" ) && buf[1 ].startswith (" image" ) && buf[1 ].endswith (" _t" );
158
- bool isSPIRVImage = buf[0 ].equals (" spirv" ) && buf[1 ].startswith (" Image" );
159
-
160
- if (isOpenCLImage || isSPIRVImage)
161
- return true ;
162
- }
163
- }
164
-
165
- return false ;
165
+ return llvm::any_of (StructTys, [](StructType *STy) { return isImageType (STy); });
166
166
}
167
167
168
168
static bool isOptNoneBuiltin (StringRef name)
@@ -235,7 +235,7 @@ static DenseSet<Function*> collectMemPoolUsage(const Module &M)
235
235
return FuncsToInline;
236
236
}
237
237
238
- void addFnAttrRecursive (Function* F, StringRef Attr, StringRef Val)
238
+ static void addFnAttrRecursive (Function* F, StringRef Attr, StringRef Val)
239
239
{
240
240
F->addFnAttr (Attr, Val);
241
241
for (inst_iterator i = inst_begin (F), e = inst_end (F); i != e; ++i) {
@@ -248,6 +248,96 @@ void addFnAttrRecursive(Function* F, StringRef Attr, StringRef Val)
248
248
}
249
249
}
250
250
251
+ static void setAlwaysInline (Function* F)
252
+ {
253
+ F->addFnAttr (llvm::Attribute::AlwaysInline);
254
+ F->removeFnAttr (llvm::Attribute::NoInline);
255
+ // optnone requires noinline and is incompatible with alwaysinline
256
+ F->removeFnAttr (llvm::Attribute::OptimizeNone);
257
+ };
258
+
259
+ static void setAlwaysInlineRecursive (Function* F)
260
+ {
261
+ if (F->hasFnAttribute (llvm::Attribute::AlwaysInline))
262
+ return ;
263
+ setAlwaysInline (F);
264
+ for (auto &I : instructions (F))
265
+ {
266
+ if (CallInst* CI = dyn_cast<CallInst>(&I))
267
+ {
268
+ if (Function* Callee = CI->getCalledFunction ())
269
+ {
270
+ setAlwaysInlineRecursive (Callee);
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ static void addAlwaysInlineForImageBuiltinUserFunctions (Module &M)
277
+ {
278
+ StringRef ImageBuiltinPrefixes[] = {
279
+ " __builtin_IB_get_image" , " __builtin_IB_get_sampler" ,
280
+ " __builtin_IB_get_snap_wa_reqd" , " __builtin_IB_OCL_1d_" ,
281
+ " __builtin_IB_OCL_2d_" , " __builtin_IB_OCL_3d_" };
282
+ SmallVector<Function *, 16 > ImageBuiltins;
283
+ SmallVector<Function *, 16 > SampledImageFunctions;
284
+ for (auto &F : M)
285
+ {
286
+ if (F.isDeclaration ())
287
+ {
288
+ for (StringRef Prefix : ImageBuiltinPrefixes)
289
+ {
290
+ if (F.getName ().startswith (Prefix))
291
+ {
292
+ ImageBuiltins.push_back (&F);
293
+ break ;
294
+ }
295
+ }
296
+ continue ;
297
+ }
298
+ // Check if return type is image.
299
+ if (auto *PTy = dyn_cast<PointerType>(F.getReturnType ()))
300
+ {
301
+ if (isImageType (IGCLLVM::getNonOpaquePtrEltTy (PTy)))
302
+ {
303
+ SampledImageFunctions.push_back (&F);
304
+ }
305
+ }
306
+ }
307
+
308
+ // Add always inline recursively for user functions of each image builtin.
309
+ DenseSet<Function *> Visited;
310
+ for (auto *Builtin : ImageBuiltins)
311
+ {
312
+ SmallVector<Function *, 16 > WorkList{Builtin};
313
+ Visited.insert (Builtin);
314
+ while (!WorkList.empty ())
315
+ {
316
+ Function *F = WorkList.pop_back_val ();
317
+ for (User *U : F->users ())
318
+ {
319
+ if (auto *CI = dyn_cast<CallInst>(U))
320
+ {
321
+ auto *Caller = CI->getFunction ();
322
+ if (Visited.insert (Caller).second )
323
+ {
324
+ setAlwaysInline (Caller);
325
+ WorkList.push_back (Caller);
326
+ }
327
+ }
328
+ }
329
+ }
330
+ }
331
+
332
+ // Operand of __builtin_IB_get_image/__builtin_IB_get_sampler could be
333
+ // result of a call instruction. The call should be inlined as well,
334
+ // otherwise ResolveSampledImageBuiltins isn't able to resolve the two builtins.
335
+ for (auto *F : SampledImageFunctions)
336
+ {
337
+ setAlwaysInlineRecursive (F);
338
+ }
339
+ }
340
+
251
341
bool ProcessFuncAttributes::runOnModule (Module& M)
252
342
{
253
343
MetaDataUtilsWrapper &mduw = getAnalysis<MetaDataUtilsWrapper>();
@@ -282,13 +372,6 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
282
372
F->addFnAttr (llvm::Attribute::NoInline);
283
373
F->removeFnAttr (llvm::Attribute::AlwaysInline);
284
374
};
285
- auto SetAlwaysInline = [](Function* F)->void
286
- {
287
- F->addFnAttr (llvm::Attribute::AlwaysInline);
288
- F->removeFnAttr (llvm::Attribute::NoInline);
289
- // optnone requires noinline and is incompatible with alwaysinline
290
- F->removeFnAttr (llvm::Attribute::OptimizeNone);
291
- };
292
375
293
376
// Returns true if a function is either import or export and requires external linking
294
377
auto NeedsLinking = [](Function* F)->bool
@@ -378,7 +461,7 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
378
461
pCtx->type != ShaderType::RAYTRACING_SHADER &&
379
462
pCtx->type != ShaderType::COMPUTE_SHADER)
380
463
{
381
- SetAlwaysInline (F);
464
+ setAlwaysInline (F);
382
465
continue ;
383
466
}
384
467
// Set noinline on optnone user functions.
@@ -461,7 +544,7 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
461
544
if (!isKernel && (F->getCallingConv () == CallingConv::SPIR_KERNEL))
462
545
{
463
546
// WA for callable kernels, always inline these.
464
- SetAlwaysInline (F);
547
+ setAlwaysInline (F);
465
548
continue ;
466
549
}
467
550
@@ -616,7 +699,7 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
616
699
617
700
if (mustAlwaysInline)
618
701
{
619
- SetAlwaysInline (F);
702
+ setAlwaysInline (F);
620
703
continue ;
621
704
}
622
705
@@ -678,15 +761,15 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
678
761
}
679
762
else
680
763
{
681
- SetAlwaysInline (F);
764
+ setAlwaysInline (F);
682
765
}
683
766
}
684
767
}
685
768
}
686
769
else if (FCtrl == FLAG_FCALL_FORCE_INLINE)
687
770
{
688
771
// Forced inlining all functions
689
- SetAlwaysInline (F);
772
+ setAlwaysInline (F);
690
773
}
691
774
else
692
775
{
@@ -782,7 +865,7 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
782
865
{
783
866
F->removeFnAttr (" referenced-indirectly" );
784
867
F->removeFnAttr (" visaStackCall" );
785
- SetAlwaysInline (F);
868
+ setAlwaysInline (F);
786
869
}
787
870
else if (FunctionControlMode == FLAG_FCALL_FORCE_SUBROUTINE)
788
871
{
@@ -864,6 +947,14 @@ bool ProcessFuncAttributes::runOnModule(Module& M)
864
947
}
865
948
}
866
949
950
+ // Curently, ExtensionArgAnalysis assumes that for all functions that use
951
+ // image builtins directly or indirectly, we add alwaysinline attribute.
952
+ // For SYCL bindless image, checking function argument isn't enough because
953
+ // * image handle could be an integer.
954
+ // * image handle could be from a call instead of function argument.
955
+ // Therefore, we explore all users functions of image builtin recursively.
956
+ addAlwaysInlineForImageBuiltinUserFunctions (M);
957
+
867
958
return true ;
868
959
}
869
960
0 commit comments