diff --git a/llvm/test/tools/sycl-post-link/spec-constants/DeprecatedFeautres/spec_const_and_split.ll b/llvm/test/tools/sycl-post-link/spec-constants/DeprecatedFeautres/spec_const_and_split.ll index 3a5f1ce85f76d..d51d051843bf4 100644 --- a/llvm/test/tools/sycl-post-link/spec-constants/DeprecatedFeautres/spec_const_and_split.ll +++ b/llvm/test/tools/sycl-post-link/spec-constants/DeprecatedFeautres/spec_const_and_split.ll @@ -55,5 +55,4 @@ define dso_local spir_kernel void @KERNEL_CCC() { ; CHECK-PROP1: SpecConst=2| ; CHECK-PROP1-NOT: SpecConst2 ; -; CHECK-PROP2: [SYCL/specialization constants] -; CHECK-PROP2: [SYCL/specialization constants default values] +; CHECK-PROP2-NOT: [SYCL/specialization constants diff --git a/llvm/tools/sycl-post-link/sycl-post-link.cpp b/llvm/tools/sycl-post-link/sycl-post-link.cpp index bd313a4555aca..e1f29cd1e683a 100644 --- a/llvm/tools/sycl-post-link/sycl-post-link.cpp +++ b/llvm/tools/sycl-post-link/sycl-post-link.cpp @@ -247,8 +247,7 @@ bool hasIndirectFunctionCalls(const Module &M) { } EntryPointsGroupScope selectDeviceCodeGroupScope(const Module &M) { - bool DoSplit = SplitMode.getNumOccurrences() > 0; - if (DoSplit) { + if (SplitMode.getNumOccurrences() > 0) { switch (SplitMode) { case SPLIT_PER_TU: return Scope_PerModule; @@ -318,7 +317,6 @@ bool isEntryPoint(const Function &F) { // ...) will constitute a separate module. void groupEntryPoints(const Module &M, EntryPointGroupMap &EntryPointsGroups, EntryPointsGroupScope EntryScope) { - // Only process module entry points: for (const auto &F : M.functions()) { if (!isEntryPoint(F)) @@ -348,6 +346,10 @@ void groupEntryPoints(const Module &M, EntryPointGroupMap &EntryPointsGroups, break; } } + + // No entry points met, record this. + if (EntryPointsGroups.empty()) + EntryPointsGroups[GLOBAL_SCOPE_NAME] = {}; } enum HasAssertStatus { No_Assert, Assert, Assert_Indirect }; @@ -488,90 +490,63 @@ std::vector getKernelReqdWorkGroupSizeMetadata(const Function &Func) { return {X, Y, Z}; } -// Input parameter EntryPointsGroups contains a map of entry points or groups -// of entry points with same values of the sycl-module-id attribute. -// Return value is a vector of entry points names lists. Each vector element is -// a string with entry point names from the same module separated by \n. -// The function saves names of entry points from one group to a single -// std::string and stores this string to the ResSymbolsLists vector. -string_vector collectSymbolsLists(const EntryPointGroupMap &EntryPointsGroups) { - string_vector ResSymbolsLists{}; - for (const auto &It : EntryPointsGroups) { - std::string SymbolsList; - for (const auto &F : It.second) { - SymbolsList = - (Twine(SymbolsList) + Twine(F->getName()) + Twine("\n")).str(); - } - ResSymbolsLists.push_back(std::move(SymbolsList)); - } - return ResSymbolsLists; +// The function joins names of entry points from one split module to a single +// std::string with '\n' as delimiter. +std::string collectSymbolsList(const EntryPointGroup &ModuleEntryPoints) { + std::string SymbolsStr; + for (const auto *F : ModuleEntryPoints) + SymbolsStr = (Twine(SymbolsStr) + Twine(F->getName()) + Twine('\n')).str(); + return SymbolsStr; } -struct ResultModule { - StringRef KernelModuleName; - std::unique_ptr ModulePtr; -}; - -// Input parameter EntryPointsGroups contains a map of entry points or groups -// of entry points with same values of the sycl-module-id attribute. -// For each group of entry points a separate IR module will be produced. -// ResModules is a vector of pairs of split module identifiers and produced -// modules. The function splits input LLVM IR module M into smaller ones and -// stores them to the ResModules vector. -std::vector -splitModule(const Module &M, const EntryPointGroupMap &EntryPointsGroups) { - std::vector ResModules{}; - - for (const auto &It : EntryPointsGroups) { - // For each group of entry points collect all dependencies. - SetVector GVs; - std::vector Workqueue; - - for (const auto &F : It.second) { - GVs.insert(F); - Workqueue.push_back(F); - } - - while (!Workqueue.empty()) { - const Function *F = &*Workqueue.back(); - Workqueue.pop_back(); - for (const auto &I : instructions(F)) { - if (const CallBase *CB = dyn_cast(&I)) - if (const Function *CF = CB->getCalledFunction()) - if (!CF->isDeclaration() && !GVs.count(CF)) { - GVs.insert(CF); - Workqueue.push_back(CF); - } - } - } +// The function produces a copy of input LLVM IR module M with only those entry +// points that are specified in ModuleEntryPoints vector. +std::unique_ptr +extractCallGraph(const Module &M, const EntryPointGroup &ModuleEntryPoints) { + // For each group of entry points collect all dependencies. + SetVector GVs; + std::vector Workqueue; + + for (const auto &F : ModuleEntryPoints) { + GVs.insert(F); + Workqueue.push_back(F); + } - // It's not easy to trace global variable's uses inside needed functions - // because global variable can be used inside a combination of operators, so - // mark all global variables as needed and remove dead ones after - // cloning. - for (const auto &G : M.globals()) { - GVs.insert(&G); + while (!Workqueue.empty()) { + const Function *F = &*Workqueue.back(); + Workqueue.pop_back(); + for (const auto &I : instructions(F)) { + if (const CallBase *CB = dyn_cast(&I)) + if (const Function *CF = CB->getCalledFunction()) + if (!CF->isDeclaration() && !GVs.count(CF)) { + GVs.insert(CF); + Workqueue.push_back(CF); + } } + } - ValueToValueMapTy VMap; - // Clone definitions only for needed globals. Others will be added as - // declarations and removed later. - std::unique_ptr MClone = CloneModule( - M, VMap, [&](const GlobalValue *GV) { return GVs.count(GV); }); - - // TODO: Use the new PassManager instead? - legacy::PassManager Passes; - // Do cleanup. - Passes.add(createGlobalDCEPass()); // Delete unreachable globals. - Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info. - Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls. - Passes.run(*MClone.get()); - - // Save results. - ResModules.push_back({It.first, std::move(MClone)}); + // It's not easy to trace global variable's uses inside needed functions + // because global variable can be used inside a combination of operators, so + // mark all global variables as needed and remove dead ones after cloning. + for (const auto &G : M.globals()) { + GVs.insert(&G); } - return ResModules; + ValueToValueMapTy VMap; + // Clone definitions only for needed globals. Others will be added as + // declarations and removed later. + std::unique_ptr MClone = CloneModule( + M, VMap, [&](const GlobalValue *GV) { return GVs.count(GV); }); + + // TODO: Use the new PassManager instead? + legacy::PassManager Passes; + // Do cleanup. + Passes.add(createGlobalDCEPass()); // Delete unreachable globals. + Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info. + Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls. + Passes.run(*MClone.get()); + + return MClone; } std::string makeResultFileName(Twine Ext, int I, StringRef Suffix) { @@ -601,149 +576,102 @@ void saveModuleIR(Module &M, StringRef OutFilename) { PrintModule.run(M); } -// Saves specified collection of llvm IR modules to files. -// Saves file list if user specified corresponding filename. -string_vector saveResultModules(const std::vector &ResModules, - StringRef Suffix) { - string_vector Res; - - for (size_t I = 0; I < ResModules.size(); ++I) { - StringRef FileExt = (OutputAssembly) ? ".ll" : ".bc"; - std::string CurOutFileName = makeResultFileName(FileExt, I, Suffix); - saveModuleIR(*ResModules[I].ModulePtr, CurOutFileName); - Res.emplace_back(std::move(CurOutFileName)); - } - return Res; -} - -string_vector -saveModuleProperties(const std::vector &ResultModules, - const EntryPointGroupMap &EntryPointsGroups, - const GlobalBinImageProps &ImgPSInfo) { +void saveModuleProperties(Module &M, const EntryPointGroup &ModuleEntryPoints, + const GlobalBinImageProps &ImgPSInfo, + const std::string &PropSetFile) { using PropSetRegTy = llvm::util::PropertySetRegistry; + PropSetRegTy PropSet; - string_vector Res; - legacy::PassManager GetSYCLDeviceLibReqMask; - auto *SDLReqMaskLegacyPass = new SYCLDeviceLibReqMaskPass(); - GetSYCLDeviceLibReqMask.add(SDLReqMaskLegacyPass); - for (size_t I = 0; I < ResultModules.size(); ++I) { - Module &M = *ResultModules[I].ModulePtr; - PropSetRegTy PropSet; - - { - GetSYCLDeviceLibReqMask.run(M); - uint32_t MRMask = SDLReqMaskLegacyPass->getSYCLDeviceLibReqMask(); - std::map RMEntry = {{"DeviceLibReqMask", MRMask}}; - PropSet.add(PropSetRegTy::SYCL_DEVICELIB_REQ_MASK, RMEntry); - } - - if (ImgPSInfo.SpecConstsMet) { - // extract spec constant maps per each module - SpecIDMapTy TmpSpecIDMap; - SpecConstantsPass::collectSpecConstantMetadata(M, TmpSpecIDMap); - PropSet.add(PropSetRegTy::SYCL_SPECIALIZATION_CONSTANTS, TmpSpecIDMap); - - // Add property with the default values of spec constants - std::vector DefaultValues; - SpecConstantsPass::collectSpecConstantDefaultValuesMetadata( - M, DefaultValues); - PropSet.add(PropSetRegTy::SYCL_SPEC_CONSTANTS_DEFAULT_VALUES, "all", - DefaultValues); - } - - if (ImgPSInfo.EmitKernelParamInfo) { - // extract kernel parameter optimization info per module - ModuleAnalysisManager MAM; - // Register required analysis - MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); - // Register the payload analysis - - MAM.registerPass([&] { return SYCLKernelParamOptInfoAnalysis(); }); - SYCLKernelParamOptInfo PInfo = - MAM.getResult(M); - - // convert analysis results into properties and record them - llvm::util::PropertySet &Props = - PropSet[PropSetRegTy::SYCL_KERNEL_PARAM_OPT_INFO]; - - for (const auto &NameInfoPair : PInfo) { - const llvm::BitVector &Bits = NameInfoPair.second; - if (Bits.empty()) - continue; // Nothing to add - - const llvm::ArrayRef Arr = Bits.getData(); - const unsigned char *Data = - reinterpret_cast(Arr.begin()); - llvm::util::PropertyValue::SizeTy DataBitSize = Bits.size(); - Props.insert(std::make_pair( - NameInfoPair.first, llvm::util::PropertyValue(Data, DataBitSize))); - } - } + { + legacy::PassManager GetSYCLDeviceLibReqMask; + auto *SDLReqMaskLegacyPass = new SYCLDeviceLibReqMaskPass(); + GetSYCLDeviceLibReqMask.add(SDLReqMaskLegacyPass); + GetSYCLDeviceLibReqMask.run(M); + uint32_t MRMask = SDLReqMaskLegacyPass->getSYCLDeviceLibReqMask(); + std::map RMEntry = {{"DeviceLibReqMask", MRMask}}; + PropSet.add(PropSetRegTy::SYCL_DEVICELIB_REQ_MASK, RMEntry); + } - if (ImgPSInfo.EmitExportedSymbols) { - // For each result module, extract the exported functions - auto ModuleFunctionsIt = - EntryPointsGroups.find(ResultModules[I].KernelModuleName); - if (ModuleFunctionsIt != EntryPointsGroups.end()) { - for (const auto &F : ModuleFunctionsIt->second) { - if (F->getCallingConv() == CallingConv::SPIR_FUNC) { - PropSet[PropSetRegTy::SYCL_EXPORTED_SYMBOLS].insert( - {F->getName(), true}); - } - } - } - } + if (ImgPSInfo.SpecConstsMet) { + // extract spec constant maps per each module + SpecIDMapTy TmpSpecIDMap; + SpecConstantsPass::collectSpecConstantMetadata(M, TmpSpecIDMap); + PropSet.add(PropSetRegTy::SYCL_SPECIALIZATION_CONSTANTS, TmpSpecIDMap); + + // Add property with the default values of spec constants + std::vector DefaultValues; + SpecConstantsPass::collectSpecConstantDefaultValuesMetadata(M, + DefaultValues); + PropSet.add(PropSetRegTy::SYCL_SPEC_CONSTANTS_DEFAULT_VALUES, "all", + DefaultValues); + } - // Metadata names may be composite so we keep them alive until the - // properties have been written. - SmallVector MetadataNames; - if (ImgPSInfo.EmitProgramMetadata) { - auto &ProgramMetadata = PropSet[PropSetRegTy::SYCL_PROGRAM_METADATA]; - - // Add reqd_work_group_size information to program metadata - for (const Function &Func : M.functions()) { - std::vector KernelReqdWorkGroupSize = - getKernelReqdWorkGroupSizeMetadata(Func); - if (KernelReqdWorkGroupSize.empty()) - continue; - MetadataNames.push_back(Func.getName().str() + "@reqd_work_group_size"); - ProgramMetadata.insert({MetadataNames.back(), KernelReqdWorkGroupSize}); - } + if (ImgPSInfo.EmitKernelParamInfo) { + // extract kernel parameter optimization info per module + ModuleAnalysisManager MAM; + // Register required analysis + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + // Register the payload analysis + MAM.registerPass([&] { return SYCLKernelParamOptInfoAnalysis(); }); + SYCLKernelParamOptInfo PInfo = + MAM.getResult(M); + + // convert analysis results into properties and record them + llvm::util::PropertySet &Props = + PropSet[PropSetRegTy::SYCL_KERNEL_PARAM_OPT_INFO]; + + for (const auto &NameInfoPair : PInfo) { + const llvm::BitVector &Bits = NameInfoPair.second; + if (Bits.empty()) + continue; // Nothing to add + + const llvm::ArrayRef Arr = Bits.getData(); + const unsigned char *Data = + reinterpret_cast(Arr.begin()); + llvm::util::PropertyValue::SizeTy DataBitSize = Bits.size(); + Props.insert(std::make_pair( + NameInfoPair.first, llvm::util::PropertyValue(Data, DataBitSize))); } + } - if (ImgPSInfo.IsEsimdKernel) - PropSet[PropSetRegTy::SYCL_MISC_PROP].insert({"isEsimdImage", true}); + if (ImgPSInfo.EmitExportedSymbols) { + // Extract the exported functions for a result module + for (const auto *F : ModuleEntryPoints) + if (F->getCallingConv() == CallingConv::SPIR_FUNC) + PropSet[PropSetRegTy::SYCL_EXPORTED_SYMBOLS].insert( + {F->getName(), true}); + } - { - std::vector FuncNames = getKernelNamesUsingAssert(M); - for (const StringRef &FName : FuncNames) - PropSet[PropSetRegTy::SYCL_ASSERT_USED].insert({FName, true}); + // Metadata names may be composite so we keep them alive until the + // properties have been written. + SmallVector MetadataNames; + if (ImgPSInfo.EmitProgramMetadata) { + auto &ProgramMetadata = PropSet[PropSetRegTy::SYCL_PROGRAM_METADATA]; + + // Add reqd_work_group_size information to program metadata + for (const Function &Func : M.functions()) { + std::vector KernelReqdWorkGroupSize = + getKernelReqdWorkGroupSizeMetadata(Func); + if (KernelReqdWorkGroupSize.empty()) + continue; + MetadataNames.push_back(Func.getName().str() + "@reqd_work_group_size"); + ProgramMetadata.insert({MetadataNames.back(), KernelReqdWorkGroupSize}); } - - std::error_code EC; - std::string SCFile = - makeResultFileName(".prop", I, ImgPSInfo.IsEsimdKernel ? "esimd_" : ""); - raw_fd_ostream SCOut(SCFile, EC); - PropSet.write(SCOut); - Res.emplace_back(std::move(SCFile)); } - return Res; -} + if (ImgPSInfo.IsEsimdKernel) + PropSet[PropSetRegTy::SYCL_MISC_PROP].insert({"isEsimdImage", true}); -// Saves specified collection of symbols lists to files. -// Saves file list if user specified corresponding filename. -string_vector saveResultSymbolsLists(string_vector &ResSymbolsLists, - StringRef Suffix) { - string_vector Res; - - std::string TxtFilesList; - for (size_t I = 0; I < ResSymbolsLists.size(); ++I) { - std::string CurOutFileName = makeResultFileName(".sym", I, Suffix); - writeToFile(CurOutFileName, ResSymbolsLists[I]); - Res.emplace_back(std::move(CurOutFileName)); + { + std::vector FuncNames = getKernelNamesUsingAssert(M); + for (const StringRef &FName : FuncNames) + PropSet[PropSetRegTy::SYCL_ASSERT_USED].insert({FName, true}); } - return Res; + + std::error_code EC; + raw_fd_ostream SCOut(PropSetFile, EC); + checkError(EC, "error opening file '" + PropSetFile + "'"); + PropSet.write(SCOut); } #define CHECK_AND_EXIT(E) \ @@ -783,6 +711,66 @@ void lowerEsimdConstructs(Module &M) { MPM.run(M); } +bool processSpecConstants(Module &M) { + if (SpecConstLower.getNumOccurrences() == 0) + return false; + + ModulePassManager RunSpecConst; + ModuleAnalysisManager MAM; + bool SetSpecConstAtRT = (SpecConstLower == SC_USE_RT_VAL); + SpecConstantsPass SCP(SetSpecConstAtRT); + // Register required analysis + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + RunSpecConst.addPass(std::move(SCP)); + + // perform the spec constant intrinsics transformation on resulting module + PreservedAnalyses Res = RunSpecConst.run(M, MAM); + return !Res.areAllPreserved(); +} + +// Module split helper. +// Supports 2 modes of splitting: +// 1. No split. Just provide source module. +// 2. Split. Split on submodules using subsequences of entry points in an input +// module as a split condition. +class ModuleSplitter { + std::unique_ptr InputModule{nullptr}; + EntryPointGroupMap GMap; + EntryPointGroupMap::const_iterator GMapIt; + bool IsSplit; + +public: + ModuleSplitter(std::unique_ptr M, bool Split, + EntryPointsGroupScope Scope) + : InputModule(std::move(M)), IsSplit(Split) { + groupEntryPoints(*InputModule, GMap, Scope); + assert(!GMap.empty() && "Entry points group map is empty!"); + GMapIt = GMap.cbegin(); + } + + // Gets next subsequence of entry points in an input module and provides split + // submodule containing these entry points and their dependencies. + std::pair, const EntryPointGroup &> nextSplit() { + assert(InputModule); + + assert(GMapIt != GMap.cend()); + const EntryPointGroup &SplitModuleEntryPoints = GMapIt->second; + ++GMapIt; + + std::unique_ptr SplitModule{nullptr}; + if (IsSplit && !SplitModuleEntryPoints.empty()) + SplitModule = extractCallGraph(*InputModule, SplitModuleEntryPoints); + else { + assert(GMap.size() == 1 && "Too many entry points groups in map!"); + SplitModule = std::move(InputModule); + } + + return {std::move(SplitModule), SplitModuleEntryPoints}; + } + + size_t totalSplits() { return GMap.size(); } +}; + using TableFiles = std::map; TableFiles processOneModule(std::unique_ptr M, bool IsEsimd, @@ -808,98 +796,71 @@ TableFiles processOneModule(std::unique_ptr M, bool IsEsimd, if (IsEsimd && LowerEsimd) lowerEsimdConstructs(*M); - EntryPointGroupMap GMap; - - bool DoSplit = SplitMode.getNumOccurrences() > 0; - - if (DoSplit || DoSymGen) { - EntryPointsGroupScope Scope = selectDeviceCodeGroupScope(*M); - groupEntryPoints(*M, GMap, Scope); - } + EntryPointsGroupScope Scope = selectDeviceCodeGroupScope(*M); + bool DoSplit = (SplitMode.getNumOccurrences() > 0); + ModuleSplitter MSplit(std::move(M), DoSplit, Scope); StringRef FileSuffix = IsEsimd ? "esimd_" : ""; - std::vector ResultModules; - - if (DoSplit) - ResultModules = splitModule(*M, GMap); - // post-link always produces a code result, even if it is unmodified input - if (ResultModules.empty()) - ResultModules.push_back({GLOBAL_SCOPE_NAME, std::move(M)}); - - bool DoSpecConst = SpecConstLower.getNumOccurrences() > 0; - bool SpecConstsMet = false; + for (size_t I = 0; I < MSplit.totalSplits(); ++I) { + std::unique_ptr ResM; + EntryPointGroup SplitModuleEntryPoints; + std::tie(ResM, SplitModuleEntryPoints) = MSplit.nextSplit(); - if (DoSpecConst) { - bool SetSpecConstAtRT = (SpecConstLower == SC_USE_RT_VAL); - ModulePassManager RunSpecConst; - ModuleAnalysisManager MAM; - SpecConstantsPass SCP(SetSpecConstAtRT); - // Register required analysis - MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); - RunSpecConst.addPass(std::move(SCP)); + bool SpecConstsMet = processSpecConstants(*ResM); - for (auto &ResultModule : ResultModules) { - // perform the spec constant intrinsics transformation on each resulting - // module - PreservedAnalyses Res = RunSpecConst.run(*ResultModule.ModulePtr, MAM); - SpecConstsMet |= !Res.areAllPreserved(); + if (IROutputOnly) { + // the result is the transformed input LLVM IR file rather than a file + // table + saveModuleIR(*ResM, OutputFilename); + return TblFiles; } - } - - if (IROutputOnly) { - // the result is the transformed input LLVMIR file rather than a file table - saveModuleIR(*ResultModules.front().ModulePtr, OutputFilename); - return TblFiles; - } - { - // Reuse input module with only regular SYCL kernels if there were - // no spec constants and no splitting. - // We cannot reuse input module for ESIMD code since it was transformed. - bool CanReuseInputModule = !SyclAndEsimdCode && !IsEsimd && - !IsLLVMUsedRemoved && !SpecConstsMet && - (ResultModules.size() == 1); - string_vector Files = CanReuseInputModule - ? string_vector{InputFilename} - : saveResultModules(ResultModules, FileSuffix); - - // "Code" column is always output - std::copy(Files.begin(), Files.end(), - std::back_inserter(TblFiles[COL_CODE])); - } + { + // Reuse input module with only regular SYCL kernels if there were + // no spec constants and no splitting. + // We cannot reuse input module for ESIMD code since it was transformed. + std::string ResModuleFile{}; + bool CanReuseInputModule = !SyclAndEsimdCode && !IsEsimd && + !IsLLVMUsedRemoved && !SpecConstsMet && + (MSplit.totalSplits() == 1); + if (CanReuseInputModule) + ResModuleFile = InputFilename; + else { + ResModuleFile = + makeResultFileName((OutputAssembly) ? ".ll" : ".bc", I, FileSuffix); + saveModuleIR(*ResM, ResModuleFile); + } + // "Code" column is always output + TblFiles[COL_CODE].push_back(ResModuleFile); + } - { - GlobalBinImageProps ImgPSInfo = {SpecConstsMet, EmitKernelParamInfo, - EmitProgramMetadata, EmitExportedSymbols, - IsEsimd}; - string_vector Files = saveModuleProperties(ResultModules, GMap, ImgPSInfo); - std::copy(Files.begin(), Files.end(), - std::back_inserter(TblFiles[COL_PROPS])); - } + { + GlobalBinImageProps ImgPSInfo = {SpecConstsMet, EmitKernelParamInfo, + EmitProgramMetadata, EmitExportedSymbols, + IsEsimd}; + std::string PropSetFile = makeResultFileName(".prop", I, FileSuffix); + saveModuleProperties(*ResM, SplitModuleEntryPoints, ImgPSInfo, + PropSetFile); + TblFiles[COL_PROPS].push_back(PropSetFile); + } - if (DoSymGen) { - // extract symbols per each module - string_vector ResultSymbolsLists = collectSymbolsLists(GMap); - if (ResultSymbolsLists.empty()) { - // push empty symbols list for consistency - assert(ResultModules.size() == 1); - ResultSymbolsLists.push_back(""); + if (DoSymGen) { + // extract symbols from module + std::string ResultSymbolsList = + collectSymbolsList(SplitModuleEntryPoints); + std::string ResultSymbolsFile = makeResultFileName(".sym", I, FileSuffix); + writeToFile(ResultSymbolsFile, ResultSymbolsList); + TblFiles[COL_SYM].push_back(ResultSymbolsFile); } - string_vector Files = - saveResultSymbolsLists(ResultSymbolsLists, FileSuffix); - std::copy(Files.begin(), Files.end(), - std::back_inserter(TblFiles[COL_SYM])); } return TblFiles; } -using ModulePair = std::pair, std::unique_ptr>; - -// This function splits a module with a mix of SYCL and ESIMD kernels -// into two separate modules. -ModulePair splitSyclEsimd(std::unique_ptr M) { +TableFiles processInputModule(std::unique_ptr M) { + if (!SplitEsimd) + return processOneModule(std::move(M), false, false); EntryPointGroup SyclFunctions; EntryPointGroup EsimdFunctions; // Collect information about the SYCL and ESIMD functions in the module. @@ -913,37 +874,22 @@ ModulePair splitSyclEsimd(std::unique_ptr M) { } } + // Do we have both Sycl and Esimd code? + bool SyclAndEsimdCode = !SyclFunctions.empty() && !EsimdFunctions.empty(); + // If only SYCL kernels or only ESIMD kernels, no splitting needed. + // Otherwise splitting a module with a mix of SYCL and ESIMD kernels into two + // separate modules. + std::unique_ptr SyclModule{nullptr}; + std::unique_ptr EsimdModule{nullptr}; if (EsimdFunctions.empty()) - return std::make_pair(std::move(M), std::unique_ptr(nullptr)); - - if (SyclFunctions.empty()) - return std::make_pair(std::unique_ptr(nullptr), std::move(M)); - - // Key values in SyclEsimdEntryPointGroupMap are not significant, but they - // define the order, in which entry points are processed in the - // splitModule function. The caller of the splitSyclEsimd function - // expects a pair of 1-Sycl and 2-Esimd modules, hence the strings names - // below. - EntryPointGroupMap SyclEsimdEntryPointGroupMap( - {{"1-SYCL", SyclFunctions}, {"2-ESIMD", EsimdFunctions}}); - std::vector ResultModules = - splitModule(*M, SyclEsimdEntryPointGroupMap); - assert(ResultModules.size() == 2); - return std::make_pair(std::move(ResultModules[0].ModulePtr), - std::move(ResultModules[1].ModulePtr)); -} - -TableFiles processInputModule(std::unique_ptr M) { - if (!SplitEsimd) - return processOneModule(std::move(M), false, false); - - std::unique_ptr SyclModule; - std::unique_ptr EsimdModule; - std::tie(SyclModule, EsimdModule) = splitSyclEsimd(std::move(M)); - - // Do we have both Sycl and Esimd code? - bool SyclAndEsimdCode = SyclModule && EsimdModule; + SyclModule = std::move(M); + else if (SyclFunctions.empty()) + EsimdModule = std::move(M); + else { + SyclModule = extractCallGraph(*M, SyclFunctions); + EsimdModule = extractCallGraph(*M, EsimdFunctions); + } TableFiles SyclTblFiles = processOneModule(std::move(SyclModule), false, SyclAndEsimdCode);