51
51
using namespace llvm ;
52
52
53
53
using string_vector = std::vector<std::string>;
54
+ using PropSetRegTy = llvm::util::PropertySetRegistry;
54
55
55
56
namespace {
56
57
@@ -183,8 +184,6 @@ cl::opt<bool> EmitOnlyKernelsAsEntryPoints{
183
184
cl::cat (PostLinkCat), cl::init (false )};
184
185
185
186
struct ImagePropSaveInfo {
186
- bool NeedDeviceLibReqMask;
187
- bool DoSpecConst;
188
187
bool SetSpecConstAtRT;
189
188
bool SpecConstsMet;
190
189
bool EmitKernelParamInfo;
@@ -219,20 +218,13 @@ enum KernelMapEntryScope {
219
218
Scope_Global // single entry in the map for all kernels
220
219
};
221
220
222
- KernelMapEntryScope selectDeviceCodeSplitScopeAutomatically (const Module &M) {
223
- if (IROutputOnly) {
224
- // We allow enabling auto split mode even in presence of -ir-output-only
225
- // flag, but in this case we are limited by it so we can't do any split at
226
- // all.
227
- return Scope_Global;
228
- }
229
-
221
+ bool hasIndirectFunctionCalls (const Module &M) {
230
222
for (const auto &F : M.functions ()) {
231
223
// There are functions marked with [[intel::device_indirectly_callable]]
232
224
// attribute, because it instructs us to make this function available to the
233
225
// whole program as it was compiled as a single module.
234
226
if (F.hasFnAttribute (" referenced-indirectly" ))
235
- return Scope_Global ;
227
+ return true ;
236
228
if (F.isDeclaration ())
237
229
continue ;
238
230
// There are indirect calls in the module, which means that we don't know
@@ -241,18 +233,47 @@ KernelMapEntryScope selectDeviceCodeSplitScopeAutomatically(const Module &M) {
241
233
for (const auto &I : instructions (F)) {
242
234
if (auto *CI = dyn_cast<CallInst>(&I))
243
235
if (!CI->getCalledFunction ())
244
- return Scope_Global ;
236
+ return true ;
245
237
}
246
238
247
239
// Function pointer is used somewhere. Follow the same rule as above.
248
240
for (const auto *U : F.users ())
249
241
if (!isa<CallInst>(U))
250
- return Scope_Global ;
242
+ return true ;
251
243
}
252
244
253
- // At the moment, we assume that per-source split is the best way of splitting
254
- // device code and can always be used execpt for cases handled above.
255
- return Scope_PerModule;
245
+ return false ;
246
+ }
247
+
248
+ KernelMapEntryScope selectDeviceCodeSplitScope (const Module &M) {
249
+ bool DoSplit = SplitMode.getNumOccurrences () > 0 ;
250
+ if (DoSplit) {
251
+ switch (SplitMode) {
252
+ case SPLIT_PER_TU:
253
+ return Scope_PerModule;
254
+
255
+ case SPLIT_PER_KERNEL:
256
+ return Scope_PerKernel;
257
+
258
+ case SPLIT_AUTO: {
259
+ if (IROutputOnly) {
260
+ // We allow enabling auto split mode even in presence of -ir-output-only
261
+ // flag, but in this case we are limited by it so we can't do any split
262
+ // at all.
263
+ return Scope_Global;
264
+ }
265
+
266
+ if (hasIndirectFunctionCalls (M))
267
+ return Scope_Global;
268
+
269
+ // At the moment, we assume that per-source split is the best way of
270
+ // splitting device code and can always be used except for cases handled
271
+ // above.
272
+ return Scope_PerModule;
273
+ }
274
+ }
275
+ }
276
+ return Scope_Global;
256
277
}
257
278
258
279
// Return true if the function is a SPIRV or SYCL builtin, e.g.
@@ -411,6 +432,41 @@ HasAssertStatus hasAssertInFunctionCallGraph(const Function *Func) {
411
432
return No_Assert;
412
433
}
413
434
435
+ std::vector<StringRef> getKernelNamesUsingAssert (const Module &M) {
436
+ std::vector<StringRef> Result;
437
+
438
+ bool HasIndirectlyCalledAssert = false ;
439
+ std::vector<const Function *> Kernels;
440
+ for (const auto &F : M.functions ()) {
441
+ // TODO: handle SYCL_EXTERNAL functions for dynamic linkage.
442
+ // TODO: handle function pointers.
443
+ if (F.getCallingConv () != CallingConv::SPIR_KERNEL)
444
+ continue ;
445
+
446
+ Kernels.push_back (&F);
447
+ if (HasIndirectlyCalledAssert)
448
+ continue ;
449
+
450
+ HasAssertStatus HasAssert = hasAssertInFunctionCallGraph (&F);
451
+ switch (HasAssert) {
452
+ case Assert:
453
+ Result.push_back (F.getName ());
454
+ break ;
455
+ case Assert_Indirect:
456
+ HasIndirectlyCalledAssert = true ;
457
+ break ;
458
+ case No_Assert:
459
+ break ;
460
+ }
461
+ }
462
+
463
+ if (HasIndirectlyCalledAssert)
464
+ for (const auto *F : Kernels)
465
+ Result.push_back (F->getName ());
466
+
467
+ return Result;
468
+ }
469
+
414
470
// Gets reqd_work_group_size information for function Func.
415
471
std::vector<uint32_t > getKernelReqdWorkGroupSizeMetadata (const Function &Func) {
416
472
auto ReqdWorkGroupSizeMD = Func.getMetadata (" reqd_work_group_size" );
@@ -545,7 +601,6 @@ string_vector saveResultModules(const std::vector<ResultModule> &ResModules,
545
601
string_vector Res;
546
602
547
603
for (size_t I = 0 ; I < ResModules.size (); ++I) {
548
- std::error_code EC;
549
604
StringRef FileExt = (OutputAssembly) ? " .ll" : " .bc" ;
550
605
std::string CurOutFileName = makeResultFileName (FileExt, I, Suffix);
551
606
saveModule (*ResModules[I].ModulePtr , CurOutFileName);
@@ -560,40 +615,36 @@ string_vector saveDeviceImageProperty(
560
615
const ImagePropSaveInfo &ImgPSInfo) {
561
616
string_vector Res;
562
617
legacy::PassManager GetSYCLDeviceLibReqMask;
563
- SYCLDeviceLibReqMaskPass *SDLReqMaskLegacyPass =
564
- new SYCLDeviceLibReqMaskPass ();
618
+ auto *SDLReqMaskLegacyPass = new SYCLDeviceLibReqMaskPass ();
565
619
GetSYCLDeviceLibReqMask.add (SDLReqMaskLegacyPass);
566
620
for (size_t I = 0 ; I < ResultModules.size (); ++I) {
567
- llvm::util::PropertySetRegistry PropSet;
568
- if (ImgPSInfo.NeedDeviceLibReqMask ) {
569
- GetSYCLDeviceLibReqMask.run (*ResultModules[I].ModulePtr );
621
+ Module &M = *ResultModules[I].ModulePtr ;
622
+ PropSetRegTy PropSet;
623
+
624
+ {
625
+ GetSYCLDeviceLibReqMask.run (M);
570
626
uint32_t MRMask = SDLReqMaskLegacyPass->getSYCLDeviceLibReqMask ();
571
627
std::map<StringRef, uint32_t > RMEntry = {{" DeviceLibReqMask" , MRMask}};
572
- PropSet.add (llvm::util::PropertySetRegistry::SYCL_DEVICELIB_REQ_MASK,
573
- RMEntry);
628
+ PropSet.add (PropSetRegTy::SYCL_DEVICELIB_REQ_MASK, RMEntry);
574
629
}
575
- if (ImgPSInfo.DoSpecConst ) {
576
- if (ImgPSInfo.SpecConstsMet ) {
577
- // extract spec constant maps per each module
578
- SpecIDMapTy TmpSpecIDMap;
579
- SpecConstantsPass::collectSpecConstantMetadata (
580
- *ResultModules[I].ModulePtr , TmpSpecIDMap);
581
- PropSet.add (
582
- llvm::util::PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS,
583
- TmpSpecIDMap);
584
-
585
- // Add property with the default values of spec constants only in native
586
- // (default) mode.
587
- if (!ImgPSInfo.SetSpecConstAtRT ) {
588
- std::vector<char > DefaultValues;
589
- SpecConstantsPass::collectSpecConstantDefaultValuesMetadata (
590
- *ResultModules[I].ModulePtr , DefaultValues);
591
- PropSet.add (llvm::util::PropertySetRegistry::
592
- SYCL_SPEC_CONSTANTS_DEFAULT_VALUES,
593
- " all" , DefaultValues);
594
- }
630
+
631
+ if (ImgPSInfo.SpecConstsMet ) {
632
+ // extract spec constant maps per each module
633
+ SpecIDMapTy TmpSpecIDMap;
634
+ SpecConstantsPass::collectSpecConstantMetadata (M, TmpSpecIDMap);
635
+ PropSet.add (PropSetRegTy::SYCL_SPECIALIZATION_CONSTANTS, TmpSpecIDMap);
636
+
637
+ // Add property with the default values of spec constants only in native
638
+ // (default) mode.
639
+ if (!ImgPSInfo.SetSpecConstAtRT ) {
640
+ std::vector<char > DefaultValues;
641
+ SpecConstantsPass::collectSpecConstantDefaultValuesMetadata (
642
+ M, DefaultValues);
643
+ PropSet.add (PropSetRegTy::SYCL_SPEC_CONSTANTS_DEFAULT_VALUES, " all" ,
644
+ DefaultValues);
595
645
}
596
646
}
647
+
597
648
if (ImgPSInfo.EmitKernelParamInfo ) {
598
649
// extract kernel parameter optimization info per module
599
650
ModuleAnalysisManager MAM;
@@ -603,12 +654,11 @@ string_vector saveDeviceImageProperty(
603
654
604
655
MAM.registerPass ([&] { return SYCLKernelParamOptInfoAnalysis (); });
605
656
SYCLKernelParamOptInfo PInfo =
606
- MAM.getResult <SYCLKernelParamOptInfoAnalysis>(
607
- *ResultModules[I].ModulePtr );
657
+ MAM.getResult <SYCLKernelParamOptInfoAnalysis>(M);
608
658
609
659
// convert analysis results into properties and record them
610
660
llvm::util::PropertySet &Props =
611
- PropSet[llvm::util::PropertySetRegistry ::SYCL_KERNEL_PARAM_OPT_INFO];
661
+ PropSet[PropSetRegTy ::SYCL_KERNEL_PARAM_OPT_INFO];
612
662
613
663
for (const auto &NameInfoPair : PInfo) {
614
664
const llvm::BitVector &Bits = NameInfoPair.second ;
@@ -623,15 +673,16 @@ string_vector saveDeviceImageProperty(
623
673
NameInfoPair.first , llvm::util::PropertyValue (Data, DataBitSize)));
624
674
}
625
675
}
676
+
626
677
if (ImgPSInfo.EmitExportedSymbols ) {
627
678
// For each result module, extract the exported functions
628
679
auto ModuleFunctionsIt =
629
680
KernelModuleMap.find (ResultModules[I].KernelModuleName );
630
681
if (ModuleFunctionsIt != KernelModuleMap.end ()) {
631
682
for (const auto &F : ModuleFunctionsIt->second ) {
632
683
if (F->getCallingConv () == CallingConv::SPIR_FUNC) {
633
- PropSet[llvm::util::PropertySetRegistry:: SYCL_EXPORTED_SYMBOLS]
634
- . insert ( {F->getName (), true });
684
+ PropSet[PropSetRegTy:: SYCL_EXPORTED_SYMBOLS]. insert (
685
+ {F->getName (), true });
635
686
}
636
687
}
637
688
}
@@ -641,11 +692,10 @@ string_vector saveDeviceImageProperty(
641
692
// properties have been written.
642
693
SmallVector<std::string, 4 > MetadataNames;
643
694
if (ImgPSInfo.EmitProgramMetadata ) {
644
- auto &ProgramMetadata =
645
- PropSet[llvm::util::PropertySetRegistry::SYCL_PROGRAM_METADATA];
695
+ auto &ProgramMetadata = PropSet[PropSetRegTy::SYCL_PROGRAM_METADATA];
646
696
647
697
// Add reqd_work_group_size information to program metadata
648
- for (const Function &Func : ResultModules[I]. ModulePtr -> functions ()) {
698
+ for (const Function &Func : M. functions ()) {
649
699
std::vector<uint32_t > KernelReqdWorkGroupSize =
650
700
getKernelReqdWorkGroupSizeMetadata (Func);
651
701
if (KernelReqdWorkGroupSize.empty ())
@@ -655,44 +705,13 @@ string_vector saveDeviceImageProperty(
655
705
}
656
706
}
657
707
658
- if (ImgPSInfo.IsEsimdKernel ) {
659
- PropSet[llvm::util::PropertySetRegistry::SYCL_MISC_PROP].insert (
660
- {" isEsimdImage" , true });
661
- }
708
+ if (ImgPSInfo.IsEsimdKernel )
709
+ PropSet[PropSetRegTy::SYCL_MISC_PROP].insert ({" isEsimdImage" , true });
662
710
663
711
{
664
- Module *M = ResultModules[I].ModulePtr .get ();
665
- bool HasIndirectlyCalledAssert = false ;
666
- std::vector<const Function *> Kernels;
667
- for (const auto &F : M->functions ()) {
668
- // TODO: handle SYCL_EXTERNAL functions for dynamic linkage.
669
- // TODO: handle function pointers.
670
- if (F.getCallingConv () != CallingConv::SPIR_KERNEL)
671
- continue ;
672
-
673
- Kernels.push_back (&F);
674
- if (HasIndirectlyCalledAssert)
675
- continue ;
676
-
677
- HasAssertStatus HasAssert = hasAssertInFunctionCallGraph (&F);
678
- switch (HasAssert) {
679
- case Assert:
680
- PropSet[llvm::util::PropertySetRegistry::SYCL_ASSERT_USED].insert (
681
- {F.getName (), true });
682
- break ;
683
- case Assert_Indirect:
684
- HasIndirectlyCalledAssert = true ;
685
- break ;
686
- case No_Assert:
687
- break ;
688
- }
689
- }
690
-
691
- if (HasIndirectlyCalledAssert) {
692
- for (const auto *F : Kernels)
693
- PropSet[llvm::util::PropertySetRegistry::SYCL_ASSERT_USED].insert (
694
- {F->getName (), true });
695
- }
712
+ std::vector<StringRef> FuncNames = getKernelNamesUsingAssert (M);
713
+ for (const StringRef &FName : FuncNames)
714
+ PropSet[PropSetRegTy::SYCL_ASSERT_USED].insert ({FName, true });
696
715
}
697
716
698
717
std::error_code EC;
@@ -786,23 +805,15 @@ TableFiles processOneModule(std::unique_ptr<Module> M, bool IsEsimd,
786
805
std::map<StringRef, std::vector<const Function *>> GlobalsSet;
787
806
788
807
bool DoSplit = SplitMode.getNumOccurrences () > 0 ;
789
- bool DoSpecConst = SpecConstLower.getNumOccurrences () > 0 ;
790
808
791
809
if (DoSplit || DoSymGen) {
792
- KernelMapEntryScope Scope = Scope_Global;
793
- if (DoSplit) {
794
- if (SplitMode == SPLIT_AUTO)
795
- Scope = selectDeviceCodeSplitScopeAutomatically (*M);
796
- else
797
- Scope =
798
- SplitMode == SPLIT_PER_KERNEL ? Scope_PerKernel : Scope_PerModule;
799
- }
810
+ KernelMapEntryScope Scope = selectDeviceCodeSplitScope (*M);
800
811
collectEntryPointToModuleMap (*M, GlobalsSet, Scope);
801
812
}
802
813
803
814
std::vector<ResultModule> ResultModules;
804
- string_vector ResultSymbolsLists;
805
815
816
+ bool DoSpecConst = SpecConstLower.getNumOccurrences () > 0 ;
806
817
bool SpecConstsMet = false ;
807
818
bool SetSpecConstAtRT = DoSpecConst && (SpecConstLower == SC_USE_RT_VAL);
808
819
@@ -852,21 +863,18 @@ TableFiles processOneModule(std::unique_ptr<Module> M, bool IsEsimd,
852
863
}
853
864
854
865
{
855
- ImagePropSaveInfo ImgPSInfo = {true ,
856
- DoSpecConst,
857
- SetSpecConstAtRT,
858
- SpecConstsMet,
859
- EmitKernelParamInfo,
860
- EmitProgramMetadata,
861
- EmitExportedSymbols,
862
- IsEsimd};
866
+ ImagePropSaveInfo ImgPSInfo = {SetSpecConstAtRT, SpecConstsMet,
867
+ EmitKernelParamInfo, EmitProgramMetadata,
868
+ EmitExportedSymbols, IsEsimd};
863
869
string_vector Files =
864
870
saveDeviceImageProperty (ResultModules, GlobalsSet, ImgPSInfo);
865
871
std::copy (Files.begin (), Files.end (),
866
872
std::back_inserter (TblFiles[COL_PROPS]));
867
873
}
874
+
868
875
if (DoSymGen) {
869
876
// extract symbols per each module
877
+ string_vector ResultSymbolsLists;
870
878
collectSymbolsLists (GlobalsSet, ResultSymbolsLists);
871
879
if (ResultSymbolsLists.empty ()) {
872
880
// push empty symbols list for consistency
@@ -878,6 +886,7 @@ TableFiles processOneModule(std::unique_ptr<Module> M, bool IsEsimd,
878
886
std::copy (Files.begin (), Files.end (),
879
887
std::back_inserter (TblFiles[COL_SYM]));
880
888
}
889
+
881
890
return TblFiles;
882
891
}
883
892
0 commit comments