Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1061,7 +1061,8 @@ : CGM(CGM), OMPBuilder(CGM.getModule()), OffloadEntriesInfoManager() { KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8); llvm::OpenMPIRBuilderConfig Config(CGM.getLangOpts().OpenMPIsDevice, false, - hasRequiresUnifiedSharedMemory()); + hasRequiresUnifiedSharedMemory(), + CGM.getLangOpts().OpenMPOffloadMandatory); // Initialize Types used in OpenMPIRBuilder from OMPKinds.def OMPBuilder.initialize(); OMPBuilder.setConfig(Config); @@ -6094,49 +6095,19 @@ const OMPExecutableDirective &D, StringRef ParentName, llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID, bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) { - // Create a unique name for the entry function using the source location - // information of the current target region. The name will be something like: - // - // __omp_offloading_DD_FFFF_PP_lBB[_CC] - // - // where DD_FFFF is an ID unique to the file (device and file IDs), PP is the - // mangled name of the function that encloses the target region and BB is the - // line number of the target region. CC is a count added when more than one - // region is located at the same location. - const bool BuildOutlinedFn = CGM.getLangOpts().OpenMPIsDevice || - !CGM.getLangOpts().OpenMPOffloadMandatory; auto EntryInfo = getTargetEntryUniqueInfo(CGM.getContext(), D.getBeginLoc(), ParentName); - SmallString<64> EntryFnName; - OffloadEntriesInfoManager.getTargetRegionEntryFnName(EntryFnName, EntryInfo); - - const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target); - CodeGenFunction CGF(CGM, true); - CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName); - CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); + llvm::OpenMPIRBuilder::FunctionGenCallback &&GenerateOutlinedFunction = + [this, &CGF, &D, &CodeGen](StringRef EntryFnName) { + const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target); - OutlinedFn = BuildOutlinedFn - ? CGF.GenerateOpenMPCapturedStmtFunction(CS, D.getBeginLoc()) - : nullptr; - - // If this target outline function is not an offload entry, we don't need to - // register it. - if (!IsOffloadEntry) - return; - - // The target region ID is used by the runtime library to identify the current - // target region, so it only has to be unique and not necessarily point to - // anything. It could be the pointer to the outlined function that implements - // the target region, but we aren't using that so that the compiler doesn't - // need to keep that, and could therefore inline the host function if proven - // worthwhile during optimization. In the other hand, if emitting code for the - // device, the ID has to be the function address so that it can retrieved from - // the offloading entry and launched by the runtime library. We also mark the - // outlined function to have external linkage in case we are emitting code for - // the device, because these functions will be entry points to the device. + CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName); + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); + return CGF.GenerateOpenMPCapturedStmtFunction(CS, D.getBeginLoc()); + }; // Get NumTeams and ThreadLimit attributes int32_t DefaultValTeams = -1; @@ -6144,15 +6115,12 @@ getNumTeamsExprForTargetDirective(CGF, D, DefaultValTeams); getNumThreadsExprForTargetDirective(CGF, D, DefaultValThreads); - std::string EntryFnIDName = CGM.getLangOpts().OpenMPIsDevice - ? std::string(EntryFnName) - : getName({EntryFnName, "region_id"}); - - OutlinedFnID = OMPBuilder.registerTargetRegionFunction( - OffloadEntriesInfoManager, EntryInfo, OutlinedFn, EntryFnName, - EntryFnIDName, DefaultValTeams, DefaultValThreads); + OMPBuilder.emitTargetRegionFunction(OffloadEntriesInfoManager, EntryInfo, + GenerateOutlinedFunction, DefaultValTeams, + DefaultValThreads, IsOffloadEntry, + OutlinedFn, OutlinedFnID); - if (BuildOutlinedFn) + if (OutlinedFn != nullptr) CGM.getTargetCodeGenInfo().setTargetAttributes(nullptr, OutlinedFn, CGM); } Index: clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp =================================================================== --- clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -891,7 +891,8 @@ CGOpenMPRuntimeGPU::CGOpenMPRuntimeGPU(CodeGenModule &CGM) : CGOpenMPRuntime(CGM) { llvm::OpenMPIRBuilderConfig Config(CGM.getLangOpts().OpenMPIsDevice, true, - hasRequiresUnifiedSharedMemory()); + hasRequiresUnifiedSharedMemory(), + CGM.getLangOpts().OpenMPOffloadMandatory); OMPBuilder.setConfig(Config); OffloadEntriesInfoManager.setConfig(Config); Index: llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -92,6 +92,9 @@ /// directive is present or not. Optional HasRequiresUnifiedSharedMemory; + // Flag for specifying if offloading is mandatory. + Optional OpenMPOffloadMandatory; + /// First separator used between the initial two parts of a name. Optional FirstSeparator; /// Separator used between all of the rest consecutive parts of s name @@ -99,9 +102,11 @@ OpenMPIRBuilderConfig() {} OpenMPIRBuilderConfig(bool IsEmbedded, bool IsTargetCodegen, - bool HasRequiresUnifiedSharedMemory) + bool HasRequiresUnifiedSharedMemory, + bool OpenMPOffloadMandatory) : IsEmbedded(IsEmbedded), IsTargetCodegen(IsTargetCodegen), - HasRequiresUnifiedSharedMemory(HasRequiresUnifiedSharedMemory) {} + HasRequiresUnifiedSharedMemory(HasRequiresUnifiedSharedMemory), + OpenMPOffloadMandatory(OpenMPOffloadMandatory) {} // Getters functions that assert if the required values are not present. bool isEmbedded() const { @@ -120,6 +125,11 @@ return HasRequiresUnifiedSharedMemory.value(); } + bool openMPOffloadMandatory() const { + assert(OpenMPOffloadMandatory.has_value() && + "OpenMPOffloadMandatory is not set"); + return OpenMPOffloadMandatory.value(); + } // Returns the FirstSeparator if set, otherwise use the default // separator depending on isTargetCodegen StringRef firstSeparator() const { @@ -1480,6 +1490,49 @@ StringRef EntryFnName); public: + /// Functions used to generate a function with the given name. + using FunctionGenCallback = std::function; + + /// Create a unique name for the entry function using the source location + /// information of the current target region. The name will be something like: + /// + /// __omp_offloading_DD_FFFF_PP_lBB[_CC] + /// + /// where DD_FFFF is an ID unique to the file (device and file IDs), PP is the + /// mangled name of the function that encloses the target region and BB is the + /// line number of the target region. CC is a count added when more than one + /// region is located at the same location. + /// + /// If this target outline function is not an offload entry, we don't need to + /// register it. This may happen if it is guarded by an if clause that is + /// false at compile time, or no target archs have been specified. + /// + /// The created target region ID is used by the runtime library to identify + /// the current target region, so it only has to be unique and not + /// necessarily point to anything. It could be the pointer to the outlined + /// function that implements the target region, but we aren't using that so + /// that the compiler doesn't need to keep that, and could therefore inline + /// the host function if proven worthwhile during optimization. In the other + /// hand, if emitting code for the device, the ID has to be the function + /// address so that it can retrieved from the offloading entry and launched + /// by the runtime library. We also mark the outlined function to have + /// external linkage in case we are emitting code for the device, because + /// these functions will be entry points to the device. + /// + /// \param InfoManager The info manager keeping track of the offload entries + /// \param EntryInfo The entry information about the function + /// \param GenerateFunctionCallback The callback function to generate the code + /// \param NumTeams Number default teams + /// \param NumThreads Number default threads + /// \param OutlinedFunction Pointer to the outlined function + /// \param EntryFnIDName Name of the ID o be created + void emitTargetRegionFunction(OffloadEntriesInfoManager &InfoManager, + TargetRegionEntryInfo &EntryInfo, + FunctionGenCallback &GenerateFunctionCallback, + int32_t NumTeams, int32_t NumThreads, + bool IsOffloadEntry, Function *&OutlinedFn, + Constant *&OutlinedFnID); + /// Registers the given function and sets up the attribtues of the function /// Returns the FunctionID. /// Index: llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp =================================================================== --- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -3973,6 +3973,35 @@ Constant::getNullValue(Builder.getInt8Ty()), EntryFnName); } +void OpenMPIRBuilder::emitTargetRegionFunction( + OffloadEntriesInfoManager &InfoManager, TargetRegionEntryInfo &EntryInfo, + FunctionGenCallback &GenerateFunctionCallback, int32_t NumTeams, + int32_t NumThreads, bool IsOffloadEntry, Function *&OutlinedFn, + Constant *&OutlinedFnID) { + + SmallString<64> EntryFnName; + InfoManager.getTargetRegionEntryFnName(EntryFnName, EntryInfo); + + OutlinedFn = Config.isEmbedded() || !Config.openMPOffloadMandatory() + ? GenerateFunctionCallback(EntryFnName) + : nullptr; + + // If this target outline function is not an offload entry, we don't need to + // register it. This may be in the case of a false if clause, or if there are + // no OpenMP targets. + if (!IsOffloadEntry) + return; + + std::string EntryFnIDName = + Config.isEmbedded() + ? std::string(EntryFnName) + : createPlatformSpecificName({EntryFnName, "region_id"}); + + OutlinedFnID = registerTargetRegionFunction( + InfoManager, EntryInfo, OutlinedFn, EntryFnName, EntryFnIDName, NumTeams, + NumThreads); +} + Constant *OpenMPIRBuilder::registerTargetRegionFunction( OffloadEntriesInfoManager &InfoManager, TargetRegionEntryInfo &EntryInfo, Function *OutlinedFn, StringRef EntryFnName, StringRef EntryFnIDName, Index: llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp =================================================================== --- llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp +++ llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp @@ -5490,7 +5490,7 @@ TEST_F(OpenMPIRBuilderTest, OffloadEntriesInfoManager) { OffloadEntriesInfoManager InfoManager; - InfoManager.setConfig(OpenMPIRBuilderConfig(true, false, false)); + InfoManager.setConfig(OpenMPIRBuilderConfig(true, false, false, false)); TargetRegionEntryInfo EntryInfo("parent", 1, 2, 4, 0); InfoManager.initializeTargetRegionEntryInfo(EntryInfo, 0); EXPECT_TRUE(InfoManager.hasTargetRegionEntryInfo(EntryInfo));