Skip to content

Commit 094a63a

Browse files
committed
[OpenMP][OMPIRBuilder] OpenMPIRBuilder support for requires directive
This patch updates the `OpenMPIRBuilderConfig` structure to hold all available 'requires' clauses, and it replicates part of the code generation for the 'requires' registration function from clang in the `OMPIRBuilder`, to be used with flang. Porting the rest of features of the clang implementation to the IRBuilder and sharing it between clang and flang remains for a future patch, due to the complexity of the logic selecting the attributes of the generated registration function. Differential Revision: https://reviews.llvm.org/D147217
1 parent 967604a commit 094a63a

File tree

6 files changed

+239
-56
lines changed

6 files changed

+239
-56
lines changed

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -480,27 +480,6 @@ enum OpenMPLocationFlags : unsigned {
480480
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE)
481481
};
482482

483-
namespace {
484-
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
485-
/// Values for bit flags for marking which requires clauses have been used.
486-
enum OpenMPOffloadingRequiresDirFlags : int64_t {
487-
/// flag undefined.
488-
OMP_REQ_UNDEFINED = 0x000,
489-
/// no requires clause present.
490-
OMP_REQ_NONE = 0x001,
491-
/// reverse_offload clause.
492-
OMP_REQ_REVERSE_OFFLOAD = 0x002,
493-
/// unified_address clause.
494-
OMP_REQ_UNIFIED_ADDRESS = 0x004,
495-
/// unified_shared_memory clause.
496-
OMP_REQ_UNIFIED_SHARED_MEMORY = 0x008,
497-
/// dynamic_allocators clause.
498-
OMP_REQ_DYNAMIC_ALLOCATORS = 0x010,
499-
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_REQ_DYNAMIC_ALLOCATORS)
500-
};
501-
502-
} // anonymous namespace
503-
504483
/// Describes ident structure that describes a source location.
505484
/// All descriptions are taken from
506485
/// https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
@@ -1055,9 +1034,11 @@ static FieldDecl *addFieldToRecordDecl(ASTContext &C, DeclContext *DC,
10551034
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
10561035
: CGM(CGM), OMPBuilder(CGM.getModule()) {
10571036
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
1058-
llvm::OpenMPIRBuilderConfig Config(CGM.getLangOpts().OpenMPIsTargetDevice,
1059-
isGPU(), hasRequiresUnifiedSharedMemory(),
1060-
CGM.getLangOpts().OpenMPOffloadMandatory);
1037+
llvm::OpenMPIRBuilderConfig Config(
1038+
CGM.getLangOpts().OpenMPIsTargetDevice, isGPU(),
1039+
CGM.getLangOpts().OpenMPOffloadMandatory,
1040+
/*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
1041+
hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
10611042
OMPBuilder.initialize(CGM.getLangOpts().OpenMPIsTargetDevice
10621043
? CGM.getLangOpts().OMPHostIRFile
10631044
: StringRef{});
@@ -10162,7 +10143,6 @@ llvm::Function *CGOpenMPRuntime::emitRequiresDirectiveRegFun() {
1016210143
std::string ReqName = getName({"omp_offloading", "requires_reg"});
1016310144
RequiresRegFn = CGM.CreateGlobalInitOrCleanUpFunction(FTy, ReqName, FI);
1016410145
CGF.StartFunction(GlobalDecl(), C.VoidTy, RequiresRegFn, FI, {});
10165-
OpenMPOffloadingRequiresDirFlags Flags = OMP_REQ_NONE;
1016610146
// TODO: check for other requires clauses.
1016710147
// The requires directive takes effect only when a target region is
1016810148
// present in the compilation unit. Otherwise it is ignored and not
@@ -10172,11 +10152,10 @@ llvm::Function *CGOpenMPRuntime::emitRequiresDirectiveRegFun() {
1017210152
assert((HasEmittedTargetRegion || HasEmittedDeclareTargetRegion ||
1017310153
!OMPBuilder.OffloadInfoManager.empty()) &&
1017410154
"Target or declare target region expected.");
10175-
if (HasRequiresUnifiedSharedMemory)
10176-
Flags = OMP_REQ_UNIFIED_SHARED_MEMORY;
1017710155
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1017810156
CGM.getModule(), OMPRTL___tgt_register_requires),
10179-
llvm::ConstantInt::get(CGM.Int64Ty, Flags));
10157+
llvm::ConstantInt::get(
10158+
CGM.Int64Ty, OMPBuilder.Config.getRequiresFlags()));
1018010159
CGF.FinishFunction();
1018110160
}
1018210161
return RequiresRegFn;

clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,9 +853,11 @@ void CGOpenMPRuntimeGPU::emitTargetOutlinedFunction(
853853

854854
CGOpenMPRuntimeGPU::CGOpenMPRuntimeGPU(CodeGenModule &CGM)
855855
: CGOpenMPRuntime(CGM) {
856-
llvm::OpenMPIRBuilderConfig Config(CGM.getLangOpts().OpenMPIsTargetDevice,
857-
isGPU(), hasRequiresUnifiedSharedMemory(),
858-
CGM.getLangOpts().OpenMPOffloadMandatory);
856+
llvm::OpenMPIRBuilderConfig Config(
857+
CGM.getLangOpts().OpenMPIsTargetDevice, isGPU(),
858+
CGM.getLangOpts().OpenMPOffloadMandatory,
859+
/*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
860+
hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
859861
OMPBuilder.setConfig(Config);
860862

861863
if (!CGM.getLangOpts().OpenMPIsTargetDevice)

llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,6 @@ class OpenMPIRBuilderConfig {
8989
/// Flag for specifying if the compilation is done for an accelerator.
9090
std::optional<bool> IsGPU;
9191

92-
/// Flag for specifying weather a requires unified_shared_memory
93-
/// directive is present or not.
94-
std::optional<bool> HasRequiresUnifiedSharedMemory;
95-
9692
// Flag for specifying if offloading is mandatory.
9793
std::optional<bool> OpenMPOffloadMandatory;
9894

@@ -101,13 +97,13 @@ class OpenMPIRBuilderConfig {
10197
/// Separator used between all of the rest consecutive parts of s name
10298
std::optional<StringRef> Separator;
10399

104-
OpenMPIRBuilderConfig() {}
100+
OpenMPIRBuilderConfig();
105101
OpenMPIRBuilderConfig(bool IsTargetDevice, bool IsGPU,
102+
bool OpenMPOffloadMandatory,
103+
bool HasRequiresReverseOffload,
104+
bool HasRequiresUnifiedAddress,
106105
bool HasRequiresUnifiedSharedMemory,
107-
bool OpenMPOffloadMandatory)
108-
: IsTargetDevice(IsTargetDevice), IsGPU(IsGPU),
109-
HasRequiresUnifiedSharedMemory(HasRequiresUnifiedSharedMemory),
110-
OpenMPOffloadMandatory(OpenMPOffloadMandatory) {}
106+
bool HasRequiresDynamicAllocators);
111107

112108
// Getters functions that assert if the required values are not present.
113109
bool isTargetDevice() const {
@@ -120,17 +116,22 @@ class OpenMPIRBuilderConfig {
120116
return *IsGPU;
121117
}
122118

123-
bool hasRequiresUnifiedSharedMemory() const {
124-
assert(HasRequiresUnifiedSharedMemory.has_value() &&
125-
"HasUnifiedSharedMemory is not set");
126-
return *HasRequiresUnifiedSharedMemory;
127-
}
128-
129119
bool openMPOffloadMandatory() const {
130120
assert(OpenMPOffloadMandatory.has_value() &&
131121
"OpenMPOffloadMandatory is not set");
132122
return *OpenMPOffloadMandatory;
133123
}
124+
125+
bool hasRequiresFlags() const { return RequiresFlags; }
126+
bool hasRequiresReverseOffload() const;
127+
bool hasRequiresUnifiedAddress() const;
128+
bool hasRequiresUnifiedSharedMemory() const;
129+
bool hasRequiresDynamicAllocators() const;
130+
131+
/// Returns requires directive clauses as flags compatible with those expected
132+
/// by libomptarget.
133+
int64_t getRequiresFlags() const;
134+
134135
// Returns the FirstSeparator if set, otherwise use the default separator
135136
// depending on isGPU
136137
StringRef firstSeparator() const {
@@ -153,11 +154,17 @@ class OpenMPIRBuilderConfig {
153154

154155
void setIsTargetDevice(bool Value) { IsTargetDevice = Value; }
155156
void setIsGPU(bool Value) { IsGPU = Value; }
156-
void setHasRequiresUnifiedSharedMemory(bool Value) {
157-
HasRequiresUnifiedSharedMemory = Value;
158-
}
159157
void setFirstSeparator(StringRef FS) { FirstSeparator = FS; }
160158
void setSeparator(StringRef S) { Separator = S; }
159+
160+
void setHasRequiresReverseOffload(bool Value);
161+
void setHasRequiresUnifiedAddress(bool Value);
162+
void setHasRequiresUnifiedSharedMemory(bool Value);
163+
void setHasRequiresDynamicAllocators(bool Value);
164+
165+
private:
166+
/// Flags for specifying which requires directive clauses are present.
167+
int64_t RequiresFlags;
161168
};
162169

163170
/// Data structure to contain the information needed to uniquely identify
@@ -2520,6 +2527,16 @@ class OpenMPIRBuilder {
25202527
/// \param Name Name of the variable.
25212528
GlobalVariable *getOrCreateInternalVariable(Type *Ty, const StringRef &Name,
25222529
unsigned AddressSpace = 0);
2530+
2531+
/// Create a global function to register OpenMP requires flags into the
2532+
/// runtime, according to the `Config`.
2533+
///
2534+
/// This function should be added to the list of constructors of the
2535+
/// compilation unit in order to be called before other OpenMP runtime
2536+
/// functions.
2537+
///
2538+
/// \param Name Name of the created function.
2539+
Function *createRegisterRequires(StringRef Name);
25232540
};
25242541

25252542
/// Class to represented the control flow structure of an OpenMP canonical loop.

llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
#include "llvm/Bitcode/BitcodeReader.h"
2626
#include "llvm/Frontend/OpenMP/OMPGridValues.h"
2727
#include "llvm/IR/Attributes.h"
28+
#include "llvm/IR/BasicBlock.h"
2829
#include "llvm/IR/CFG.h"
2930
#include "llvm/IR/CallingConv.h"
3031
#include "llvm/IR/Constant.h"
3132
#include "llvm/IR/Constants.h"
3233
#include "llvm/IR/DebugInfoMetadata.h"
3334
#include "llvm/IR/DerivedTypes.h"
35+
#include "llvm/IR/Function.h"
3436
#include "llvm/IR/GlobalVariable.h"
3537
#include "llvm/IR/IRBuilder.h"
3638
#include "llvm/IR/LLVMContext.h"
@@ -338,6 +340,104 @@ BasicBlock *llvm::splitBBWithSuffix(IRBuilderBase &Builder, bool CreateBranch,
338340
return splitBB(Builder, CreateBranch, Old->getName() + Suffix);
339341
}
340342

343+
//===----------------------------------------------------------------------===//
344+
// OpenMPIRBuilderConfig
345+
//===----------------------------------------------------------------------===//
346+
347+
namespace {
348+
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
349+
/// Values for bit flags for marking which requires clauses have been used.
350+
enum OpenMPOffloadingRequiresDirFlags {
351+
/// flag undefined.
352+
OMP_REQ_UNDEFINED = 0x000,
353+
/// no requires directive present.
354+
OMP_REQ_NONE = 0x001,
355+
/// reverse_offload clause.
356+
OMP_REQ_REVERSE_OFFLOAD = 0x002,
357+
/// unified_address clause.
358+
OMP_REQ_UNIFIED_ADDRESS = 0x004,
359+
/// unified_shared_memory clause.
360+
OMP_REQ_UNIFIED_SHARED_MEMORY = 0x008,
361+
/// dynamic_allocators clause.
362+
OMP_REQ_DYNAMIC_ALLOCATORS = 0x010,
363+
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_REQ_DYNAMIC_ALLOCATORS)
364+
};
365+
366+
} // anonymous namespace
367+
368+
OpenMPIRBuilderConfig::OpenMPIRBuilderConfig()
369+
: RequiresFlags(OMP_REQ_UNDEFINED) {}
370+
371+
OpenMPIRBuilderConfig::OpenMPIRBuilderConfig(
372+
bool IsTargetDevice, bool IsGPU, bool OpenMPOffloadMandatory,
373+
bool HasRequiresReverseOffload, bool HasRequiresUnifiedAddress,
374+
bool HasRequiresUnifiedSharedMemory, bool HasRequiresDynamicAllocators)
375+
: IsTargetDevice(IsTargetDevice), IsGPU(IsGPU),
376+
OpenMPOffloadMandatory(OpenMPOffloadMandatory),
377+
RequiresFlags(OMP_REQ_UNDEFINED) {
378+
if (HasRequiresReverseOffload)
379+
RequiresFlags |= OMP_REQ_REVERSE_OFFLOAD;
380+
if (HasRequiresUnifiedAddress)
381+
RequiresFlags |= OMP_REQ_UNIFIED_ADDRESS;
382+
if (HasRequiresUnifiedSharedMemory)
383+
RequiresFlags |= OMP_REQ_UNIFIED_SHARED_MEMORY;
384+
if (HasRequiresDynamicAllocators)
385+
RequiresFlags |= OMP_REQ_DYNAMIC_ALLOCATORS;
386+
}
387+
388+
bool OpenMPIRBuilderConfig::hasRequiresReverseOffload() const {
389+
return RequiresFlags & OMP_REQ_REVERSE_OFFLOAD;
390+
}
391+
392+
bool OpenMPIRBuilderConfig::hasRequiresUnifiedAddress() const {
393+
return RequiresFlags & OMP_REQ_UNIFIED_ADDRESS;
394+
}
395+
396+
bool OpenMPIRBuilderConfig::hasRequiresUnifiedSharedMemory() const {
397+
return RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY;
398+
}
399+
400+
bool OpenMPIRBuilderConfig::hasRequiresDynamicAllocators() const {
401+
return RequiresFlags & OMP_REQ_DYNAMIC_ALLOCATORS;
402+
}
403+
404+
int64_t OpenMPIRBuilderConfig::getRequiresFlags() const {
405+
return hasRequiresFlags() ? RequiresFlags
406+
: static_cast<int64_t>(OMP_REQ_NONE);
407+
}
408+
409+
void OpenMPIRBuilderConfig::setHasRequiresReverseOffload(bool Value) {
410+
if (Value)
411+
RequiresFlags |= OMP_REQ_REVERSE_OFFLOAD;
412+
else
413+
RequiresFlags &= ~OMP_REQ_REVERSE_OFFLOAD;
414+
}
415+
416+
void OpenMPIRBuilderConfig::setHasRequiresUnifiedAddress(bool Value) {
417+
if (Value)
418+
RequiresFlags |= OMP_REQ_UNIFIED_ADDRESS;
419+
else
420+
RequiresFlags &= ~OMP_REQ_UNIFIED_ADDRESS;
421+
}
422+
423+
void OpenMPIRBuilderConfig::setHasRequiresUnifiedSharedMemory(bool Value) {
424+
if (Value)
425+
RequiresFlags |= OMP_REQ_UNIFIED_SHARED_MEMORY;
426+
else
427+
RequiresFlags &= ~OMP_REQ_UNIFIED_SHARED_MEMORY;
428+
}
429+
430+
void OpenMPIRBuilderConfig::setHasRequiresDynamicAllocators(bool Value) {
431+
if (Value)
432+
RequiresFlags |= OMP_REQ_DYNAMIC_ALLOCATORS;
433+
else
434+
RequiresFlags &= ~OMP_REQ_DYNAMIC_ALLOCATORS;
435+
}
436+
437+
//===----------------------------------------------------------------------===//
438+
// OpenMPIRBuilder
439+
//===----------------------------------------------------------------------===//
440+
341441
void OpenMPIRBuilder::getKernelArgsVector(TargetKernelArgs &KernelArgs,
342442
IRBuilderBase &Builder,
343443
SmallVector<Value *> &ArgsVector) {
@@ -6106,6 +6206,39 @@ void OpenMPIRBuilder::loadOffloadInfoMetadata(Module &M) {
61066206
}
61076207
}
61086208

6209+
Function *OpenMPIRBuilder::createRegisterRequires(StringRef Name) {
6210+
// Skip the creation of the registration function if this is device codegen
6211+
if (Config.isTargetDevice())
6212+
return nullptr;
6213+
6214+
Builder.ClearInsertionPoint();
6215+
6216+
// Create registration function prototype
6217+
auto *RegFnTy = FunctionType::get(Builder.getVoidTy(), {});
6218+
auto *RegFn = Function::Create(
6219+
RegFnTy, GlobalVariable::LinkageTypes::InternalLinkage, Name, M);
6220+
RegFn->setSection(".text.startup");
6221+
RegFn->addFnAttr(Attribute::NoInline);
6222+
RegFn->addFnAttr(Attribute::NoUnwind);
6223+
6224+
// Create registration function body
6225+
auto *BB = BasicBlock::Create(M.getContext(), "entry", RegFn);
6226+
ConstantInt *FlagsVal =
6227+
ConstantInt::getSigned(Builder.getInt64Ty(), Config.getRequiresFlags());
6228+
Function *RTLRegFn = getOrCreateRuntimeFunctionPtr(
6229+
omp::RuntimeFunction::OMPRTL___tgt_register_requires);
6230+
6231+
Builder.SetInsertPoint(BB);
6232+
Builder.CreateCall(RTLRegFn, {FlagsVal});
6233+
Builder.CreateRetVoid();
6234+
6235+
return RegFn;
6236+
}
6237+
6238+
//===----------------------------------------------------------------------===//
6239+
// OffloadEntriesInfoManager
6240+
//===----------------------------------------------------------------------===//
6241+
61096242
bool OffloadEntriesInfoManager::empty() const {
61106243
return OffloadEntriesTargetRegion.empty() &&
61116244
OffloadEntriesDeviceGlobalVar.empty();
@@ -6244,6 +6377,10 @@ void OffloadEntriesInfoManager::actOnDeviceGlobalVarEntriesInfo(
62446377
Action(E.getKey(), E.getValue());
62456378
}
62466379

6380+
//===----------------------------------------------------------------------===//
6381+
// CanonicalLoopInfo
6382+
//===----------------------------------------------------------------------===//
6383+
62476384
void CanonicalLoopInfo::collectControlBlocks(
62486385
SmallVectorImpl<BasicBlock *> &BBs) {
62496386
// We only count those BBs as control block for which we do not need to

0 commit comments

Comments
 (0)