@@ -88,6 +88,10 @@ static cl::opt<bool> OutputAssembly{"S",
88
88
cl::desc (" Write output as LLVM assembly" ),
89
89
cl::Hidden, cl::cat (PostLinkCat)};
90
90
91
+ static cl::opt<bool > SplitEsimd{" split-esimd" ,
92
+ cl::desc (" Split SYCL and ESIMD kernels" ),
93
+ cl::cat (PostLinkCat)};
94
+
91
95
enum IRSplitMode {
92
96
SPLIT_PER_TU, // one module per translation unit
93
97
SPLIT_PER_KERNEL, // one module per kernel
@@ -446,18 +450,16 @@ splitModule(Module &M,
446
450
}
447
451
}
448
452
449
- static std::string makeResultFileName (Twine Ext, int I, bool IsEsimd ) {
453
+ static std::string makeResultFileName (Twine Ext, int I, StringRef Suffix ) {
450
454
const StringRef Dir0 = OutputDir.getNumOccurrences () > 0
451
455
? OutputDir
452
456
: sys::path::parent_path (OutputFilename);
453
457
const StringRef Sep = sys::path::get_separator ();
454
458
std::string Dir = Dir0.str ();
455
459
if (!Dir0.empty () && !Dir0.endswith (Sep))
456
460
Dir += Sep.str ();
457
- std::string RetStr = Dir + sys::path::stem (OutputFilename).str () + " _" ;
458
- if (IsEsimd)
459
- RetStr += " esimd_" ;
460
- return RetStr + std::to_string (I) + Ext.str ();
461
+ return Dir + sys::path::stem (OutputFilename).str () + " _" + Suffix.str () +
462
+ std::to_string (I) + Ext.str ();
461
463
}
462
464
463
465
static void saveModule (Module &M, StringRef OutFilename) {
@@ -479,13 +481,13 @@ static void saveModule(Module &M, StringRef OutFilename) {
479
481
// Saves file list if user specified corresponding filename.
480
482
static string_vector
481
483
saveResultModules (std::vector<std::unique_ptr<Module>> &ResModules,
482
- bool IsEsimd ) {
484
+ StringRef Suffix ) {
483
485
string_vector Res;
484
486
485
487
for (size_t I = 0 ; I < ResModules.size (); ++I) {
486
488
std::error_code EC;
487
489
StringRef FileExt = (OutputAssembly) ? " .ll" : " .bc" ;
488
- std::string CurOutFileName = makeResultFileName (FileExt, I, IsEsimd );
490
+ std::string CurOutFileName = makeResultFileName (FileExt, I, Suffix );
489
491
saveModule (*ResModules[I].get (), CurOutFileName);
490
492
Res.emplace_back (std::move (CurOutFileName));
491
493
}
@@ -586,7 +588,7 @@ static string_vector saveDeviceImageProperty(
586
588
}
587
589
std::error_code EC;
588
590
std::string SCFile =
589
- makeResultFileName (" .prop" , I, ImgPSInfo.IsEsimdKernel );
591
+ makeResultFileName (" .prop" , I, ImgPSInfo.IsEsimdKernel ? " esimd_ " : " " );
590
592
raw_fd_ostream SCOut (SCFile, EC);
591
593
PropSet.write (SCOut);
592
594
Res.emplace_back (std::move (SCFile));
@@ -598,12 +600,12 @@ static string_vector saveDeviceImageProperty(
598
600
// Saves specified collection of symbols lists to files.
599
601
// Saves file list if user specified corresponding filename.
600
602
static string_vector saveResultSymbolsLists (string_vector &ResSymbolsLists,
601
- bool IsEsimd ) {
603
+ StringRef Suffix ) {
602
604
string_vector Res;
603
605
604
606
std::string TxtFilesList;
605
607
for (size_t I = 0 ; I < ResSymbolsLists.size (); ++I) {
606
- std::string CurOutFileName = makeResultFileName (" .sym" , I, IsEsimd );
608
+ std::string CurOutFileName = makeResultFileName (" .sym" , I, Suffix );
607
609
writeToFile (CurOutFileName, ResSymbolsLists[I]);
608
610
Res.emplace_back (std::move (CurOutFileName));
609
611
}
@@ -682,7 +684,7 @@ static TableFiles processOneModule(std::unique_ptr<Module> M, bool IsEsimd,
682
684
// reuse input module if there were no spec constants and no splitting
683
685
string_vector Files =
684
686
SpecConstsMet || (ResultModules.size () > 1 ) || SyclAndEsimdKernels
685
- ? saveResultModules (ResultModules, IsEsimd)
687
+ ? saveResultModules (ResultModules, IsEsimd ? " esimd_ " : " " )
686
688
: string_vector{InputFilename};
687
689
// "Code" column is always output
688
690
std::copy (Files.begin (), Files.end (),
@@ -696,7 +698,6 @@ static TableFiles processOneModule(std::unique_ptr<Module> M, bool IsEsimd,
696
698
string_vector Files = saveDeviceImageProperty (ResultModules, ImgPSInfo);
697
699
std::copy (Files.begin (), Files.end (),
698
700
std::back_inserter (TblFiles[COL_PROPS]));
699
-
700
701
}
701
702
if (DoSymGen) {
702
703
// extract symbols per each module
@@ -706,7 +707,8 @@ static TableFiles processOneModule(std::unique_ptr<Module> M, bool IsEsimd,
706
707
assert (ResultModules.size () == 1 );
707
708
ResultSymbolsLists.push_back (" " );
708
709
}
709
- string_vector Files = saveResultSymbolsLists (ResultSymbolsLists, IsEsimd);
710
+ string_vector Files =
711
+ saveResultSymbolsLists (ResultSymbolsLists, IsEsimd ? " esimd_" : " " );
710
712
std::copy (Files.begin (), Files.end (),
711
713
std::back_inserter (TblFiles[COL_SYM]));
712
714
}
@@ -750,6 +752,36 @@ static ModulePair splitSyclEsimd(std::unique_ptr<Module> M) {
750
752
std::move (ResultModules[1 ]));
751
753
}
752
754
755
+ static TableFiles processInputModule (std::unique_ptr<Module> M) {
756
+ if (!SplitEsimd)
757
+ return processOneModule (std::move (M), false , false );
758
+
759
+ std::unique_ptr<Module> SyclModule;
760
+ std::unique_ptr<Module> EsimdModule;
761
+ std::tie (SyclModule, EsimdModule) = splitSyclEsimd (std::move (M));
762
+
763
+ // Do we have both Sycl and Esimd kernels?
764
+ bool SyclAndEsimdKernels = SyclModule && EsimdModule;
765
+
766
+ TableFiles SyclTblFiles =
767
+ processOneModule (std::move (SyclModule), false , SyclAndEsimdKernels);
768
+ TableFiles EsimdTblFiles =
769
+ processOneModule (std::move (EsimdModule), true , SyclAndEsimdKernels);
770
+
771
+ // Merge the two resulting file maps
772
+ TableFiles MergedTblFiles;
773
+ for (auto &ColumnStr : {COL_CODE, COL_PROPS, COL_SYM}) {
774
+ auto &SyclFiles = SyclTblFiles[ColumnStr];
775
+ auto &EsimdFiles = EsimdTblFiles[ColumnStr];
776
+ auto &MergedFiles = MergedTblFiles[ColumnStr];
777
+ std::copy (SyclFiles.begin (), SyclFiles.end (),
778
+ std::back_inserter (MergedFiles));
779
+ std::copy (EsimdFiles.begin (), EsimdFiles.end (),
780
+ std::back_inserter (MergedFiles));
781
+ }
782
+ return MergedTblFiles;
783
+ }
784
+
753
785
int main (int argc, char **argv) {
754
786
InitLLVM X{argc, argv};
755
787
@@ -761,13 +793,19 @@ int main(int argc, char **argv) {
761
793
" This is a collection of utilities run on device code's LLVM IR before\n "
762
794
" handing off to back-end for further compilation or emitting SPIRV.\n "
763
795
" The utilities are:\n "
796
+ " - SYCL and ESIMD kernels can be split into separate modules with\n "
797
+ " '-split-esimd' option. The option has no effect when there is only\n "
798
+ " one type of kernels in the input module.\n "
764
799
" - Module splitter to split a big input module into smaller ones.\n "
765
800
" Groups kernels using function attribute 'sycl-module-id', i.e.\n "
766
801
" kernels with the same values of the 'sycl-module-id' attribute will\n "
767
802
" be put into the same module. If -split=kernel option is specified,\n "
768
803
" one module per kernel will be emitted.\n "
769
804
" '-split=auto' mode automatically selects the best way of splitting\n "
770
805
" kernels into modules based on some heuristic.\n "
806
+ " The '-split' option is compatible with '-split-esimd'. In this case,\n "
807
+ " first input module will be split into SYCL and ESIMD modules. Then\n "
808
+ " both modules will be further split according to the '-split' option.\n "
771
809
" - If -symbols options is also specified, then for each produced module\n "
772
810
" a text file containing names of all spir kernels in it is generated.\n "
773
811
" - Specialization constant intrinsic transformer. Replaces symbolic\n "
@@ -792,10 +830,11 @@ int main(int argc, char **argv) {
792
830
" than 'auto'.\n " );
793
831
794
832
bool DoSplit = SplitMode.getNumOccurrences () > 0 ;
833
+ bool DoSplitEsimd = SplitEsimd.getNumOccurrences () > 0 ;
795
834
bool DoSpecConst = SpecConstLower.getNumOccurrences () > 0 ;
796
835
bool DoParamInfo = EmitKernelParamInfo.getNumOccurrences () > 0 ;
797
836
798
- if (!DoSplit && !DoSpecConst && !DoSymGen && !DoParamInfo) {
837
+ if (!DoSplit && !DoSpecConst && !DoSymGen && !DoParamInfo && !DoSplitEsimd ) {
799
838
errs () << " no actions specified; try --help for usage info\n " ;
800
839
return 1 ;
801
840
}
@@ -804,6 +843,11 @@ int main(int argc, char **argv) {
804
843
<< " can't be used with -" << IROutputOnly.ArgStr << " \n " ;
805
844
return 1 ;
806
845
}
846
+ if (IROutputOnly && DoSplitEsimd) {
847
+ errs () << " error: -" << SplitEsimd.ArgStr << " can't be used with -"
848
+ << IROutputOnly.ArgStr << " \n " ;
849
+ return 1 ;
850
+ }
807
851
if (IROutputOnly && DoSymGen) {
808
852
errs () << " error: -" << DoSymGen.ArgStr << " can't be used with -"
809
853
<< IROutputOnly.ArgStr << " \n " ;
@@ -840,58 +884,22 @@ int main(int argc, char **argv) {
840
884
if (OutputFilename.getNumOccurrences () == 0 )
841
885
OutputFilename = (Twine (sys::path::stem (InputFilename)) + " .files" ).str ();
842
886
843
- std::unique_ptr<Module> SyclModule;
844
- std::unique_ptr<Module> EsimdModule;
845
- std::tie (SyclModule, EsimdModule) = splitSyclEsimd (std::move (M));
846
-
847
- // Do we have both Sycl and Esimd kernels?
848
- bool SyclAndEsimdKernels = SyclModule && EsimdModule;
849
-
850
- TableFiles SyclTblFiles =
851
- processOneModule (std::move (SyclModule), false , SyclAndEsimdKernels);
887
+ TableFiles TblFiles = processInputModule (std::move (M));
852
888
853
- // TODO: Currently -ir-output-only option doesn't work when there is a mix
854
- // of SYCL and ESIMD kernels. The option requires a single LLVM IR output
855
- // file, which we cannot provide since SYCL and ESIMD kernels should always
856
- // be split.
857
- // Today, -ir-output-only is an FPGA use case, while ESIMD kernels only appear
858
- // in programs that run on a GPU, so they are orthogonal. But once there
859
- // would be a use case for -ir-output-only on a module that has SYCL and ESIMD
860
- // code, we need to address it.
889
+ // Input module was processed and a single output file was requested.
861
890
if (IROutputOnly)
862
891
return 0 ;
863
892
864
- TableFiles EsimdTblFiles =
865
- processOneModule (std::move (EsimdModule), true , SyclAndEsimdKernels);
866
-
893
+ // Populate and emit the resulting table
867
894
util::SimpleTable Table;
895
+ for (auto &ColumnStr : {COL_CODE, COL_PROPS, COL_SYM})
896
+ if (!TblFiles[ColumnStr].empty ())
897
+ CHECK_AND_EXIT (Table.addColumn (ColumnStr, TblFiles[ColumnStr]));
868
898
869
- auto addTableColumn = [&Table, &SyclTblFiles,
870
- &EsimdTblFiles](std::string Str) {
871
- auto &SyclFiles = SyclTblFiles[Str];
872
- auto &EsimdFiles = EsimdTblFiles[Str];
873
- string_vector Files (SyclFiles);
874
- std::copy (EsimdFiles.begin (), EsimdFiles.end (), std::back_inserter (Files));
875
- if (Files.empty ())
876
- return 0 ;
877
- Error Err = Table.addColumn (Str, Files);
878
- CHECK_AND_EXIT (Err);
879
- return 0 ;
880
- };
881
-
882
- int Res;
883
- if ((Res = addTableColumn (COL_CODE)) != 0 )
884
- return Res;
885
- if ((Res = addTableColumn (COL_PROPS)) != 0 )
886
- return Res;
887
- if ((Res = addTableColumn (COL_SYM)) != 0 )
888
- return Res;
899
+ std::error_code EC;
900
+ raw_fd_ostream Out{OutputFilename, EC, sys::fs::OF_None};
901
+ checkError (EC, " error opening file '" + OutputFilename + " '" );
902
+ Table.write (Out);
889
903
890
- {
891
- std::error_code EC;
892
- raw_fd_ostream Out{OutputFilename, EC, sys::fs::OF_None};
893
- checkError (EC, " error opening file '" + OutputFilename + " '" );
894
- Table.write (Out);
895
- }
896
904
return 0 ;
897
905
}
0 commit comments