@@ -50,14 +50,14 @@ static cl::opt<std::string> BaseOutputFilename{
5050// with prodced IR modules files names.
5151static cl::opt<std::string> OutputIRFilesList{
5252 " ir-files-list" , cl::desc (" Specify output filename for IR files list" ),
53- cl::value_desc (" filename" ), cl::init (" - " ), cl::cat (ExtractCat)};
53+ cl::value_desc (" filename" ), cl::init (" " ), cl::cat (ExtractCat)};
5454
5555// Module splitter produces multiple TXT files. These files contain kernel names
5656// list presented in a produced module. TXT files list is a file list
5757// with produced TXT files names.
5858static cl::opt<std::string> OutputTxtFilesList{
5959 " txt-files-list" , cl::desc (" Specify output filename for txt files list" ),
60- cl::value_desc (" filename" ), cl::init (" - " ), cl::cat (ExtractCat)};
60+ cl::value_desc (" filename" ), cl::init (" " ), cl::cat (ExtractCat)};
6161
6262static cl::opt<bool > Force{" f" , cl::desc (" Enable binary output on terminals" ),
6363 cl::cat (ExtractCat)};
@@ -88,45 +88,62 @@ static void writeToFile(std::string Filename, std::string Content) {
8888 OS.close ();
8989}
9090
91- static void collectKernelsSet (
92- Module &M, std::map<std::string, std::vector<Function *>> &ResKernelsSet) {
91+ // Output parameter ResKernelModuleMap is a map containing groups of kernels
92+ // with same values of the sycl-module-id attribute.
93+ // The function fills ResKernelModuleMap using input module M.
94+ static void collectKernelModuleMap (
95+ Module &M,
96+ std::map<std::string, std::vector<Function *>> &ResKernelModuleMap) {
9397 for (auto &F : M.functions ()) {
9498 if (F.getCallingConv () == CallingConv::SPIR_KERNEL) {
9599 if (OneKernelPerModule) {
96- ResKernelsSet [F.getName ()].push_back (&F);
100+ ResKernelModuleMap [F.getName ()].push_back (&F);
97101 } else if (F.hasFnAttribute (" sycl-module-id" )) {
98102 auto Id = F.getFnAttribute (" sycl-module-id" );
99103 auto Val = Id.getValueAsString ();
100- ResKernelsSet [Val].push_back (&F);
104+ ResKernelModuleMap [Val].push_back (&F);
101105 }
102106 }
103107 }
104108}
105109
106- // Splits input LLVM IR module M into smaller ones.
107- // Input parameter KernelsSet is a map containing groups of kernels with same
108- // values in the sycl-module-id attribute. For each group of kernels a separate
109- // IR module will be produced.
110- // ResModules and ResSymbolsLists are output parameters.
111- // Result modules are stored into
112- // ResModules vector. For each result module set of kernel names is collected.
113- // Sets of kernel names are stored into ResSymbolsLists.
110+ // Input parameter KernelModuleMap is a map containing groups of kernels with
111+ // same values of the sycl-module-id attribute. ResSymbolsLists is a vector of
112+ // kernel name lists. Each vector element is a string with kernel names from the
113+ // same module separated by \n.
114+ // The function saves names of kernels from one group to a single std::string
115+ // and stores this string to the ResSymbolsLists vector.
116+ static void collectSymbolsLists (
117+ std::map<std::string, std::vector<Function *>> &KernelModuleMap,
118+ std::vector<std::string> &ResSymbolsLists) {
119+ for (auto &It : KernelModuleMap) {
120+ std::string SymbolsList;
121+ for (auto &F : It.second ) {
122+ SymbolsList =
123+ (Twine (SymbolsList) + Twine (F->getName ()) + Twine (" \n " )).str ();
124+ }
125+ ResSymbolsLists.push_back (std::move (SymbolsList));
126+ }
127+ }
128+
129+ // Input parameter KernelModuleMap is a map containing groups of kernels with
130+ // same values of the sycl-module-id attribute. For each group of kernels a
131+ // separate IR module will be produced.
132+ // ResModules is a vector of produced modules.
133+ // The function splits input LLVM IR module M into smaller ones and stores them
134+ // to the ResModules vector.
114135static void
115136splitModule (Module &M,
116- std::map<std::string, std::vector<Function *>> &KernelsSet,
117- std::vector<std::unique_ptr<Module>> &ResModules,
118- std::vector<std::string> &ResSymbolsLists) {
119- for (auto &It : KernelsSet) {
137+ std::map<std::string, std::vector<Function *>> &KernelModuleMap,
138+ std::vector<std::unique_ptr<Module>> &ResModules) {
139+ for (auto &It : KernelModuleMap) {
120140 // For each group of kernels collect all dependencies.
121141 SetVector<GlobalValue *> GVs;
122142 std::vector<llvm::Function *> Workqueue;
123- std::string SymbolsList;
124143
125144 for (auto &F : It.second ) {
126145 GVs.insert (F);
127146 Workqueue.push_back (F);
128- SymbolsList =
129- (Twine (SymbolsList) + Twine (F->getName ()) + Twine (" \n " )).str ();
130147 }
131148
132149 while (!Workqueue.empty ()) {
@@ -184,22 +201,17 @@ splitModule(Module &M,
184201
185202 // Save results.
186203 ResModules.push_back (std::move (MClone));
187- ResSymbolsLists.push_back (std::move (SymbolsList));
188204 }
189205}
190206
191- // Saves specified collections of llvm IR modules and corresponding lists of
192- // kernel names to files. Saves IR files list and TXT files list if user
193- // specified corresponding filenames.
194- static void saveResults (std::vector<std::unique_ptr<Module>> &ResModules,
195- std::vector<std::string> &ResSymbolsLists) {
196- int NumOfFile = 0 ;
207+ // Saves specified collection of llvm IR modules to files.
208+ // Saves file list if user specified corresponding filename.
209+ static void
210+ saveResultModules (std::vector<std::unique_ptr<Module>> &ResModules) {
197211 std::string IRFilesList;
198- std::string TxtFilesList;
199212 for (size_t I = 0 ; I < ResModules.size (); ++I) {
200213 std::error_code EC;
201- std::string CurOutFileName = BaseOutputFilename + " _" +
202- std::to_string (NumOfFile) +
214+ std::string CurOutFileName = BaseOutputFilename + " _" + std::to_string (I) +
203215 ((OutputAssembly) ? " .ll" : " .bc" );
204216
205217 raw_fd_ostream Out{CurOutFileName, EC, sys::fs::OF_None};
@@ -214,33 +226,36 @@ static void saveResults(std::vector<std::unique_ptr<Module>> &ResModules,
214226 PrintModule.add (createBitcodeWriterPass (Out));
215227 PrintModule.run (*ResModules[I].get ());
216228
217- IRFilesList =
218- (Twine (IRFilesList) + Twine (CurOutFileName) + Twine (" \n " )).str ();
219-
220- CurOutFileName =
221- BaseOutputFilename + " _" + std::to_string (NumOfFile) + " .txt" ;
222- writeToFile (CurOutFileName, ResSymbolsLists[I]);
223-
224- TxtFilesList =
225- (Twine (TxtFilesList) + Twine (CurOutFileName) + Twine (" \n " )).str ();
226-
227- ++NumOfFile;
229+ if (!OutputIRFilesList.empty ())
230+ IRFilesList =
231+ (Twine (IRFilesList) + Twine (CurOutFileName) + Twine (" \n " )).str ();
228232 }
229233
230- if (OutputIRFilesList != " -" ) {
231- // TODO: Figure out what can be added to the output list if there are no
232- // kernels in the input module.
234+ if (!OutputIRFilesList.empty ()) {
233235 // Just pass input module to next tools if there was nothing to split.
234236 if (IRFilesList.empty ())
235- IRFilesList =
236- (Twine (InputFilename) + Twine (" \n " )).str ();
237+ IRFilesList = (Twine (InputFilename) + Twine (" \n " )).str ();
237238 writeToFile (OutputIRFilesList, IRFilesList);
238239 }
239- if (OutputTxtFilesList != " -" ) {
240- // TODO: Figure out what can be added to output list if there are no kernels
241- // in the input module.
240+ }
241+
242+ // Saves specified collection of symbols lists to files.
243+ // Saves file list if user specified corresponding filename.
244+ static void saveResultSymbolsLists (std::vector<std::string> &ResSymbolsLists) {
245+ std::string TxtFilesList;
246+ for (size_t I = 0 ; I < ResSymbolsLists.size (); ++I) {
247+ std::string CurOutFileName =
248+ BaseOutputFilename + " _" + std::to_string (I) + " .txt" ;
249+ writeToFile (CurOutFileName, ResSymbolsLists[I]);
250+
251+ if (!OutputTxtFilesList.empty ())
252+ TxtFilesList =
253+ (Twine (TxtFilesList) + Twine (CurOutFileName) + Twine (" \n " )).str ();
254+ }
255+
256+ if (!OutputTxtFilesList.empty ()) {
242257 if (TxtFilesList.empty ()) {
243- // Just create an empty temporary file if there was nothing to split
258+ // Just create an empty temporary file if there was nothing to split.
244259 std::string TempFileNameBase = sys::path::stem (BaseOutputFilename);
245260 SmallString<128 > Path;
246261 std::error_code EC =
@@ -290,17 +305,32 @@ int main(int argc, char **argv) {
290305
291306 std::map<std::string, std::vector<Function *>> GlobalsSet;
292307
293- collectKernelsSet (*M.get (), GlobalsSet);
308+ collectKernelModuleMap (*M.get (), GlobalsSet);
294309
295310 std::vector<std::unique_ptr<Module>> ResultModules;
296311 std::vector<std::string> ResultSymbolsLists;
297312
298- splitModule (*M.get (), GlobalsSet, ResultModules, ResultSymbolsLists);
313+ // Default usage model of that the tool is
314+ // calling it twice with the same input due clang driver limitations.
315+ // It should not bring much extra overhead because
316+ // parseIRFile and collectKernelModuleMap functions are small (would be good
317+ // to estimate) compared to splitModule and saveResultModules.
318+ bool NoLists = OutputIRFilesList.empty () && OutputTxtFilesList.empty ();
319+ bool PerformSplit = !OutputIRFilesList.empty () || NoLists;
320+ bool CollectSymbols = !OutputTxtFilesList.empty () || NoLists;
299321
300322 if (BaseOutputFilename == " -" )
301323 BaseOutputFilename = " a.out" ;
302324
303- saveResults (ResultModules, ResultSymbolsLists);
325+ if (PerformSplit) {
326+ splitModule (*M.get (), GlobalsSet, ResultModules);
327+ saveResultModules (ResultModules);
328+ }
329+
330+ if (CollectSymbols) {
331+ collectSymbolsLists (GlobalsSet, ResultSymbolsLists);
332+ saveResultSymbolsLists (ResultSymbolsLists);
333+ }
304334
305335 return 0 ;
306336}
0 commit comments