Skip to content

Commit 9058762

Browse files
committed
[OpenMP][Flang][MLIR] Lowering of requires directive from MLIR to LLVM IR
Default atomic ordering information is processed in the OpenMP dialect to LLVM IR lowering stage at every spot where an operation can be affected by it. The rest of clauses are stored globally in the OpenMPIRBuilderConfig object before starting that lowering stage, so that the OMPIRBuilder can conditionally modify code generation depending on these. At the end of the process, the omp.requires attribute is itself lowered into a global constructor that passes these clauses as flags to the OpenMP runtime. Depends on D147217, D147218 and D158278. Differential Revision: https://reviews.llvm.org/D147219
1 parent 29aa749 commit 9058762

File tree

6 files changed

+165
-79
lines changed

6 files changed

+165
-79
lines changed

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,9 +1039,10 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
10391039
CGM.getLangOpts().OpenMPOffloadMandatory,
10401040
/*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
10411041
hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
1042-
OMPBuilder.initialize(CGM.getLangOpts().OpenMPIsTargetDevice
1043-
? CGM.getLangOpts().OMPHostIRFile
1044-
: StringRef{});
1042+
OMPBuilder.initialize();
1043+
OMPBuilder.loadOffloadInfoMetadata(CGM.getLangOpts().OpenMPIsTargetDevice
1044+
? CGM.getLangOpts().OMPHostIRFile
1045+
: StringRef{});
10451046
OMPBuilder.setConfig(Config);
10461047
}
10471048

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ class OpenMPIRBuilderConfig {
154154

155155
void setIsTargetDevice(bool Value) { IsTargetDevice = Value; }
156156
void setIsGPU(bool Value) { IsGPU = Value; }
157+
void setOpenMPOffloadMandatory(bool Value) { OpenMPOffloadMandatory = Value; }
157158
void setFirstSeparator(StringRef FS) { FirstSeparator = FS; }
158159
void setSeparator(StringRef S) { Separator = S; }
159160

@@ -449,14 +450,9 @@ class OpenMPIRBuilder {
449450

450451
/// Initialize the internal state, this will put structures types and
451452
/// potentially other helpers into the underlying module. Must be called
452-
/// before any other method and only once! This internal state includes
453-
/// Types used in the OpenMPIRBuilder generated from OMPKinds.def as well
454-
/// as loading offload metadata for device from the OpenMP host IR file
455-
/// passed in as the HostFilePath argument.
456-
/// \param HostFilePath The path to the host IR file, used to load in
457-
/// offload metadata for the device, allowing host and device to
458-
/// maintain the same metadata mapping.
459-
void initialize(StringRef HostFilePath = {});
453+
/// before any other method and only once! This internal state includes types
454+
/// used in the OpenMPIRBuilder generated from OMPKinds.def.
455+
void initialize();
460456

461457
void setConfig(OpenMPIRBuilderConfig C) { Config = C; }
462458

@@ -2519,6 +2515,15 @@ class OpenMPIRBuilder {
25192515
/// loaded from bitcode file, i.e, different from OpenMPIRBuilder::M module.
25202516
void loadOffloadInfoMetadata(Module &M);
25212517

2518+
/// Loads all the offload entries information from the host IR
2519+
/// metadata read from the file passed in as the HostFilePath argument. This
2520+
/// function is only meant to be used with device code generation.
2521+
///
2522+
/// \param HostFilePath The path to the host IR file,
2523+
/// used to load in offload metadata for the device, allowing host and device
2524+
/// to maintain the same metadata mapping.
2525+
void loadOffloadInfoMetadata(StringRef HostFilePath);
2526+
25222527
/// Gets (if variable with the given name already exist) or creates
25232528
/// internal global variable with the specified Name. The created variable has
25242529
/// linkage CommonLinkage by default and is initialized by null value.

llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -582,31 +582,7 @@ Function *OpenMPIRBuilder::getOrCreateRuntimeFunctionPtr(RuntimeFunction FnID) {
582582
return Fn;
583583
}
584584

585-
void OpenMPIRBuilder::initialize(StringRef HostFilePath) {
586-
initializeTypes(M);
587-
588-
if (HostFilePath.empty())
589-
return;
590-
591-
auto Buf = MemoryBuffer::getFile(HostFilePath);
592-
if (std::error_code Err = Buf.getError()) {
593-
report_fatal_error(("error opening host file from host file path inside of "
594-
"OpenMPIRBuilder: " +
595-
Err.message())
596-
.c_str());
597-
}
598-
599-
LLVMContext Ctx;
600-
auto M = expectedToErrorOrAndEmitErrors(
601-
Ctx, parseBitcodeFile(Buf.get()->getMemBufferRef(), Ctx));
602-
if (std::error_code Err = M.getError()) {
603-
report_fatal_error(
604-
("error parsing host file inside of OpenMPIRBuilder: " + Err.message())
605-
.c_str());
606-
}
607-
608-
loadOffloadInfoMetadata(*M.get());
609-
}
585+
void OpenMPIRBuilder::initialize() { initializeTypes(M); }
610586

611587
void OpenMPIRBuilder::finalize(Function *Fn) {
612588
SmallPtrSet<BasicBlock *, 32> ParallelRegionBlockSet;
@@ -6206,6 +6182,30 @@ void OpenMPIRBuilder::loadOffloadInfoMetadata(Module &M) {
62066182
}
62076183
}
62086184

6185+
void OpenMPIRBuilder::loadOffloadInfoMetadata(StringRef HostFilePath) {
6186+
if (HostFilePath.empty())
6187+
return;
6188+
6189+
auto Buf = MemoryBuffer::getFile(HostFilePath);
6190+
if (std::error_code Err = Buf.getError()) {
6191+
report_fatal_error(("error opening host file from host file path inside of "
6192+
"OpenMPIRBuilder: " +
6193+
Err.message())
6194+
.c_str());
6195+
}
6196+
6197+
LLVMContext Ctx;
6198+
auto M = expectedToErrorOrAndEmitErrors(
6199+
Ctx, parseBitcodeFile(Buf.get()->getMemBufferRef(), Ctx));
6200+
if (std::error_code Err = M.getError()) {
6201+
report_fatal_error(
6202+
("error parsing host file inside of OpenMPIRBuilder: " + Err.message())
6203+
.c_str());
6204+
}
6205+
6206+
loadOffloadInfoMetadata(*M.get());
6207+
}
6208+
62096209
Function *OpenMPIRBuilder::createRegisterRequires(StringRef Name) {
62106210
// Skip the creation of the registration function if this is device codegen
62116211
if (Config.isTargetDevice())

mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "mlir/IR/IRMapping.h"
1818
#include "mlir/IR/Operation.h"
1919
#include "mlir/Support/LLVM.h"
20+
#include "mlir/Support/LogicalResult.h"
2021
#include "mlir/Target/LLVMIR/Dialect/OpenMPCommon.h"
2122
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
2223
#include "mlir/Transforms/RegionUtils.h"
@@ -28,6 +29,8 @@
2829
#include "llvm/IR/DebugInfoMetadata.h"
2930
#include "llvm/IR/IRBuilder.h"
3031
#include "llvm/Support/FileSystem.h"
32+
#include "llvm/Transforms/Utils/ModuleUtils.h"
33+
#include <optional>
3134

3235
using namespace mlir;
3336

@@ -1165,7 +1168,7 @@ convertOmpSimdLoop(Operation &opInst, llvm::IRBuilderBase &builder,
11651168
}
11661169

11671170
/// Convert an Atomic Ordering attribute to llvm::AtomicOrdering.
1168-
llvm::AtomicOrdering
1171+
static llvm::AtomicOrdering
11691172
convertAtomicOrdering(std::optional<omp::ClauseMemoryOrderKind> ao) {
11701173
if (!ao)
11711174
return llvm::AtomicOrdering::Monotonic; // Default Memory Ordering
@@ -1932,6 +1935,27 @@ convertDeclareTargetAttr(Operation *op,
19321935
return success();
19331936
}
19341937

1938+
/// Converts the module-level set of OpenMP requires clauses into LLVM IR using
1939+
/// OpenMPIRBuilder.
1940+
static LogicalResult
1941+
convertRequiresAttr(Operation &op, omp::ClauseRequiresAttr requiresAttr,
1942+
LLVM::ModuleTranslation &moduleTranslation) {
1943+
auto *ompBuilder = moduleTranslation.getOpenMPBuilder();
1944+
1945+
// No need to read requiresAttr here, because it has already been done in
1946+
// translateModuleToLLVMIR(). There, flags are stored in the
1947+
// OpenMPIRBuilderConfig object, available to the OpenMPIRBuilder.
1948+
auto *regFn =
1949+
ompBuilder->createRegisterRequires(ompBuilder->createPlatformSpecificName(
1950+
{"omp_offloading", "requires_reg"}));
1951+
1952+
// Add registration function as global constructor
1953+
if (regFn)
1954+
llvm::appendToGlobalCtors(ompBuilder->M, regFn, /* Priority = */ 0);
1955+
1956+
return success();
1957+
}
1958+
19351959
namespace {
19361960

19371961
/// Implementation of the dialect interface that converts operations belonging
@@ -1947,38 +1971,99 @@ class OpenMPDialectLLVMIRTranslationInterface
19471971
convertOperation(Operation *op, llvm::IRBuilderBase &builder,
19481972
LLVM::ModuleTranslation &moduleTranslation) const final;
19491973

1974+
/// Given an OpenMP MLIR attribute, create the corresponding LLVM-IR, runtime
1975+
/// calls, or operation amendments
19501976
LogicalResult
19511977
amendOperation(Operation *op, NamedAttribute attribute,
19521978
LLVM::ModuleTranslation &moduleTranslation) const final;
19531979
};
19541980

19551981
} // namespace
19561982

1957-
/// Given an OpenMP MLIR attribute, create the corresponding LLVM-IR, runtime
1958-
/// calls, or operation amendments
19591983
LogicalResult OpenMPDialectLLVMIRTranslationInterface::amendOperation(
19601984
Operation *op, NamedAttribute attribute,
19611985
LLVM::ModuleTranslation &moduleTranslation) const {
1962-
return llvm::TypeSwitch<Attribute, LogicalResult>(attribute.getValue())
1963-
.Case([&](mlir::omp::FlagsAttr rtlAttr) {
1964-
return convertFlagsAttr(op, rtlAttr, moduleTranslation);
1965-
})
1966-
.Case([&](mlir::omp::VersionAttr versionAttr) {
1967-
llvm::OpenMPIRBuilder *ompBuilder =
1968-
moduleTranslation.getOpenMPBuilder();
1969-
ompBuilder->M.addModuleFlag(llvm::Module::Max, "openmp",
1970-
versionAttr.getVersion());
1971-
return success();
1972-
})
1973-
.Case([&](mlir::omp::DeclareTargetAttr declareTargetAttr) {
1974-
return convertDeclareTargetAttr(op, declareTargetAttr,
1975-
moduleTranslation);
1976-
})
1977-
.Default([&](Attribute attr) {
1978-
// fall through for omp attributes that do not require lowering and/or
1979-
// have no concrete definition and thus no type to define a case on
1986+
return llvm::StringSwitch<llvm::function_ref<LogicalResult(Attribute)>>(
1987+
attribute.getName())
1988+
.Case("omp.is_target_device",
1989+
[&](Attribute attr) {
1990+
if (auto deviceAttr = attr.dyn_cast<BoolAttr>()) {
1991+
llvm::OpenMPIRBuilderConfig &config =
1992+
moduleTranslation.getOpenMPBuilder()->Config;
1993+
config.setIsTargetDevice(deviceAttr.getValue());
1994+
return success();
1995+
}
1996+
return failure();
1997+
})
1998+
.Case("omp.is_gpu",
1999+
[&](Attribute attr) {
2000+
if (auto gpuAttr = attr.dyn_cast<BoolAttr>()) {
2001+
llvm::OpenMPIRBuilderConfig &config =
2002+
moduleTranslation.getOpenMPBuilder()->Config;
2003+
config.setIsGPU(gpuAttr.getValue());
2004+
return success();
2005+
}
2006+
return failure();
2007+
})
2008+
.Case("omp.host_ir_filepath",
2009+
[&](Attribute attr) {
2010+
if (auto filepathAttr = attr.dyn_cast<StringAttr>()) {
2011+
llvm::OpenMPIRBuilder *ompBuilder =
2012+
moduleTranslation.getOpenMPBuilder();
2013+
ompBuilder->loadOffloadInfoMetadata(filepathAttr.getValue());
2014+
return success();
2015+
}
2016+
return failure();
2017+
})
2018+
.Case("omp.flags",
2019+
[&](Attribute attr) {
2020+
if (auto rtlAttr = attr.dyn_cast<omp::FlagsAttr>())
2021+
return convertFlagsAttr(op, rtlAttr, moduleTranslation);
2022+
return failure();
2023+
})
2024+
.Case("omp.version",
2025+
[&](Attribute attr) {
2026+
if (auto versionAttr = attr.dyn_cast<omp::VersionAttr>()) {
2027+
llvm::OpenMPIRBuilder *ompBuilder =
2028+
moduleTranslation.getOpenMPBuilder();
2029+
ompBuilder->M.addModuleFlag(llvm::Module::Max, "openmp",
2030+
versionAttr.getVersion());
2031+
return success();
2032+
}
2033+
return failure();
2034+
})
2035+
.Case("omp.declare_target",
2036+
[&](Attribute attr) {
2037+
if (auto declareTargetAttr =
2038+
attr.dyn_cast<omp::DeclareTargetAttr>())
2039+
return convertDeclareTargetAttr(op, declareTargetAttr,
2040+
moduleTranslation);
2041+
return failure();
2042+
})
2043+
.Case(
2044+
"omp.requires",
2045+
[&](Attribute attr) {
2046+
if (auto requiresAttr = attr.dyn_cast<omp::ClauseRequiresAttr>()) {
2047+
using Requires = omp::ClauseRequires;
2048+
Requires flags = requiresAttr.getValue();
2049+
llvm::OpenMPIRBuilderConfig &config =
2050+
moduleTranslation.getOpenMPBuilder()->Config;
2051+
config.setHasRequiresReverseOffload(
2052+
bitEnumContainsAll(flags, Requires::reverse_offload));
2053+
config.setHasRequiresUnifiedAddress(
2054+
bitEnumContainsAll(flags, Requires::unified_address));
2055+
config.setHasRequiresUnifiedSharedMemory(
2056+
bitEnumContainsAll(flags, Requires::unified_shared_memory));
2057+
config.setHasRequiresDynamicAllocators(
2058+
bitEnumContainsAll(flags, Requires::dynamic_allocators));
2059+
return convertRequiresAttr(*op, requiresAttr, moduleTranslation);
2060+
}
2061+
return failure();
2062+
})
2063+
.Default([](Attribute) {
2064+
// Fall through for omp attributes that do not require lowering.
19802065
return success();
1981-
});
2066+
})(attribute.getValue());
19822067

19832068
return failure();
19842069
}

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,32 +1278,18 @@ SmallVector<llvm::Value *> ModuleTranslation::lookupValues(ValueRange values) {
12781278
llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
12791279
if (!ompBuilder) {
12801280
ompBuilder = std::make_unique<llvm::OpenMPIRBuilder>(*llvmModule);
1281+
ompBuilder->initialize();
12811282

1282-
bool isTargetDevice = false, isGPU = false;
1283-
llvm::StringRef hostIRFilePath = "";
1284-
1285-
if (auto deviceAttr =
1286-
mlirModule->getAttrOfType<mlir::BoolAttr>("omp.is_target_device"))
1287-
isTargetDevice = deviceAttr.getValue();
1288-
1289-
if (auto gpuAttr = mlirModule->getAttrOfType<mlir::BoolAttr>("omp.is_gpu"))
1290-
isGPU = gpuAttr.getValue();
1291-
1292-
if (auto filepathAttr =
1293-
mlirModule->getAttrOfType<mlir::StringAttr>("omp.host_ir_filepath"))
1294-
hostIRFilePath = filepathAttr.getValue();
1295-
1296-
ompBuilder->initialize(hostIRFilePath);
1297-
1298-
// TODO: set the flags when available
1299-
llvm::OpenMPIRBuilderConfig config(
1300-
isTargetDevice, isGPU,
1283+
// Flags represented as top-level OpenMP dialect attributes are set in
1284+
// `OpenMPDialectLLVMIRTranslationInterface::amendOperation()`. Here we set
1285+
// the default configuration.
1286+
ompBuilder->setConfig(llvm::OpenMPIRBuilderConfig(
1287+
/* IsTargetDevice = */ false, /* IsGPU = */ false,
13011288
/* OpenMPOffloadMandatory = */ false,
13021289
/* HasRequiresReverseOffload = */ false,
13031290
/* HasRequiresUnifiedAddress = */ false,
13041291
/* HasRequiresUnifiedSharedMemory = */ false,
1305-
/* HasRequiresDynamicAllocators = */ false);
1306-
ompBuilder->setConfig(config);
1292+
/* HasRequiresDynamicAllocators = */ false));
13071293
}
13081294
return ompBuilder.get();
13091295
}

mlir/test/Target/LLVMIR/openmp-llvm.mlir

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2661,3 +2661,12 @@ llvm.func @omp_task_if(%boolexpr: i1) {
26612661
// CHECK: call void @foo_after()
26622662
// CHECK: ret void
26632663

2664+
// -----
2665+
2666+
// Check that OpenMP requires flags are registered by a global constructor.
2667+
// CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }]
2668+
// CHECK-SAME: [{ i32, ptr, ptr } { i32 0, ptr @[[REG_FN:.*]], ptr null }]
2669+
// CHECK: define {{.*}} @[[REG_FN]]({{.*}})
2670+
// CHECK-NOT: }
2671+
// CHECK: call void @__tgt_register_requires(i64 10)
2672+
module attributes {omp.requires = #omp<clause_requires reverse_offload|unified_shared_memory>} {}

0 commit comments

Comments
 (0)