[flang-commits] [flang] [NFC][flang][OpenMP] Split `DataSharing` and `Clause` processors (PR #81973)
via flang-commits
flang-commits at lists.llvm.org
Fri Feb 16 00:09:02 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-openmp
Author: Kareem Ergawy (ergawy)
<details>
<summary>Changes</summary>
This started as an experiment to reduce the compilation time of iterating over `Lower/OpenMP.cpp` a bit since it is too slow at the moment. Trying to do that, I split the `DataSharingProcessor` and `ClauseProcessor` into their own files and extracted some shared code into a util file.
This resulted is a slightly better orgnaization of the OpenMP lowering code and hence opening this NFC.
As for the compilation time, this unfortunately does not affect it much (it shaves off a few seconds of `OpenMP.cpp` compilation) since from what I learned the bottleneck is in `DirectivesCommon.h` and `PFTBuilder.h` which both consume a lot of time in template instantiation it seems.
### This is just a proposal, please let me know if you disagree with this reorganization for any reason.
---
Patch is 183.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81973.diff
8 Files Affected:
- (modified) flang/lib/Lower/CMakeLists.txt (+3)
- (added) flang/lib/Lower/ClauseProcessor.cpp (+1298)
- (added) flang/lib/Lower/ClauseProcessor.h (+414)
- (added) flang/lib/Lower/DataSharingProcessor.cpp (+350)
- (added) flang/lib/Lower/DataSharingProcessor.h (+89)
- (modified) flang/lib/Lower/OpenMP.cpp (+4-2034)
- (added) flang/lib/Lower/OpenMPUtils.cpp (+56)
- (added) flang/lib/Lower/OpenMPUtils.h (+27)
``````````diff
diff --git a/flang/lib/Lower/CMakeLists.txt b/flang/lib/Lower/CMakeLists.txt
index b13d415e02f1d9..dfd942ac21aeb1 100644
--- a/flang/lib/Lower/CMakeLists.txt
+++ b/flang/lib/Lower/CMakeLists.txt
@@ -5,6 +5,7 @@ add_flang_library(FortranLower
Allocatable.cpp
Bridge.cpp
CallInterface.cpp
+ ClauseProcessor.cpp
Coarray.cpp
ComponentPath.cpp
ConvertArrayConstructor.cpp
@@ -16,6 +17,7 @@ add_flang_library(FortranLower
ConvertType.cpp
ConvertVariable.cpp
CustomIntrinsicCall.cpp
+ DataSharingProcessor.cpp
DumpEvaluateExpr.cpp
HlfirIntrinsics.cpp
HostAssociations.cpp
@@ -25,6 +27,7 @@ add_flang_library(FortranLower
Mangler.cpp
OpenACC.cpp
OpenMP.cpp
+ OpenMPUtils.cpp
PFTBuilder.cpp
Runtime.cpp
SymbolMap.cpp
diff --git a/flang/lib/Lower/ClauseProcessor.cpp b/flang/lib/Lower/ClauseProcessor.cpp
new file mode 100644
index 00000000000000..b5c5586fa1e3ea
--- /dev/null
+++ b/flang/lib/Lower/ClauseProcessor.cpp
@@ -0,0 +1,1298 @@
+//===-- ClauseProcessor.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClauseProcessor.h"
+
+#include "flang/Lower/PFTBuilder.h"
+#include "flang/Parser/tools.h"
+#include "flang/Semantics/tools.h"
+
+namespace Fortran {
+namespace lower {
+namespace omp {
+
+//===----------------------------------------------------------------------===//
+// Common helper functions
+//===----------------------------------------------------------------------===//
+
+void genObjectList(const Fortran::parser::OmpObjectList &objectList,
+ Fortran::lower::AbstractConverter &converter,
+ llvm::SmallVectorImpl<mlir::Value> &operands) {
+ auto addOperands = [&](Fortran::lower::SymbolRef sym) {
+ const mlir::Value variable = converter.getSymbolAddress(sym);
+ if (variable) {
+ operands.push_back(variable);
+ } else {
+ if (const auto *details =
+ sym->detailsIf<Fortran::semantics::HostAssocDetails>()) {
+ operands.push_back(converter.getSymbolAddress(details->symbol()));
+ converter.copySymbolBinding(details->symbol(), sym);
+ }
+ }
+ };
+ for (const Fortran::parser::OmpObject &ompObject : objectList.v) {
+ Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject);
+ addOperands(*sym);
+ }
+}
+
+void gatherFuncAndVarSyms(
+ const Fortran::parser::OmpObjectList &objList,
+ mlir::omp::DeclareTargetCaptureClause clause,
+ llvm::SmallVectorImpl<DeclareTargetCapturePair> &symbolAndClause) {
+ for (const Fortran::parser::OmpObject &ompObject : objList.v) {
+ Fortran::common::visit(
+ Fortran::common::visitors{
+ [&](const Fortran::parser::Designator &designator) {
+ if (const Fortran::parser::Name *name =
+ Fortran::semantics::getDesignatorNameIfDataRef(
+ designator)) {
+ symbolAndClause.emplace_back(clause, *name->symbol);
+ }
+ },
+ [&](const Fortran::parser::Name &name) {
+ symbolAndClause.emplace_back(clause, *name.symbol);
+ }},
+ ompObject.u);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// ClauseProcessor helper functions
+//===----------------------------------------------------------------------===//
+
+/// Check for unsupported map operand types.
+static void checkMapType(mlir::Location location, mlir::Type type) {
+ if (auto refType = type.dyn_cast<fir::ReferenceType>())
+ type = refType.getElementType();
+ if (auto boxType = type.dyn_cast_or_null<fir::BoxType>())
+ if (!boxType.getElementType().isa<fir::PointerType>())
+ TODO(location, "OMPD_target_data MapOperand BoxType");
+}
+
+static mlir::omp::ScheduleModifier
+translateScheduleModifier(const Fortran::parser::OmpScheduleModifierType &m) {
+ switch (m.v) {
+ case Fortran::parser::OmpScheduleModifierType::ModType::Monotonic:
+ return mlir::omp::ScheduleModifier::monotonic;
+ case Fortran::parser::OmpScheduleModifierType::ModType::Nonmonotonic:
+ return mlir::omp::ScheduleModifier::nonmonotonic;
+ case Fortran::parser::OmpScheduleModifierType::ModType::Simd:
+ return mlir::omp::ScheduleModifier::simd;
+ }
+ return mlir::omp::ScheduleModifier::none;
+}
+
+static mlir::omp::ScheduleModifier
+getScheduleModifier(const Fortran::parser::OmpScheduleClause &x) {
+ const auto &modifier =
+ std::get<std::optional<Fortran::parser::OmpScheduleModifier>>(x.t);
+ // The input may have the modifier any order, so we look for one that isn't
+ // SIMD. If modifier is not set at all, fall down to the bottom and return
+ // "none".
+ if (modifier) {
+ const auto &modType1 =
+ std::get<Fortran::parser::OmpScheduleModifier::Modifier1>(modifier->t);
+ if (modType1.v.v ==
+ Fortran::parser::OmpScheduleModifierType::ModType::Simd) {
+ const auto &modType2 = std::get<
+ std::optional<Fortran::parser::OmpScheduleModifier::Modifier2>>(
+ modifier->t);
+ if (modType2 &&
+ modType2->v.v !=
+ Fortran::parser::OmpScheduleModifierType::ModType::Simd)
+ return translateScheduleModifier(modType2->v);
+
+ return mlir::omp::ScheduleModifier::none;
+ }
+
+ return translateScheduleModifier(modType1.v);
+ }
+ return mlir::omp::ScheduleModifier::none;
+}
+
+static mlir::omp::ScheduleModifier
+getSimdModifier(const Fortran::parser::OmpScheduleClause &x) {
+ const auto &modifier =
+ std::get<std::optional<Fortran::parser::OmpScheduleModifier>>(x.t);
+ // Either of the two possible modifiers in the input can be the SIMD modifier,
+ // so look in either one, and return simd if we find one. Not found = return
+ // "none".
+ if (modifier) {
+ const auto &modType1 =
+ std::get<Fortran::parser::OmpScheduleModifier::Modifier1>(modifier->t);
+ if (modType1.v.v == Fortran::parser::OmpScheduleModifierType::ModType::Simd)
+ return mlir::omp::ScheduleModifier::simd;
+
+ const auto &modType2 = std::get<
+ std::optional<Fortran::parser::OmpScheduleModifier::Modifier2>>(
+ modifier->t);
+ if (modType2 && modType2->v.v ==
+ Fortran::parser::OmpScheduleModifierType::ModType::Simd)
+ return mlir::omp::ScheduleModifier::simd;
+ }
+ return mlir::omp::ScheduleModifier::none;
+}
+
+static void
+genAllocateClause(Fortran::lower::AbstractConverter &converter,
+ const Fortran::parser::OmpAllocateClause &ompAllocateClause,
+ llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,
+ llvm::SmallVectorImpl<mlir::Value> &allocateOperands) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ mlir::Location currentLocation = converter.getCurrentLocation();
+ Fortran::lower::StatementContext stmtCtx;
+
+ mlir::Value allocatorOperand;
+ const Fortran::parser::OmpObjectList &ompObjectList =
+ std::get<Fortran::parser::OmpObjectList>(ompAllocateClause.t);
+ const auto &allocateModifier = std::get<
+ std::optional<Fortran::parser::OmpAllocateClause::AllocateModifier>>(
+ ompAllocateClause.t);
+
+ // If the allocate modifier is present, check if we only use the allocator
+ // submodifier. ALIGN in this context is unimplemented
+ const bool onlyAllocator =
+ allocateModifier &&
+ std::holds_alternative<
+ Fortran::parser::OmpAllocateClause::AllocateModifier::Allocator>(
+ allocateModifier->u);
+
+ if (allocateModifier && !onlyAllocator) {
+ TODO(currentLocation, "OmpAllocateClause ALIGN modifier");
+ }
+
+ // Check if allocate clause has allocator specified. If so, add it
+ // to list of allocators, otherwise, add default allocator to
+ // list of allocators.
+ if (onlyAllocator) {
+ const auto &allocatorValue = std::get<
+ Fortran::parser::OmpAllocateClause::AllocateModifier::Allocator>(
+ allocateModifier->u);
+ allocatorOperand = fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(allocatorValue.v), stmtCtx));
+ allocatorOperands.insert(allocatorOperands.end(), ompObjectList.v.size(),
+ allocatorOperand);
+ } else {
+ allocatorOperand = firOpBuilder.createIntegerConstant(
+ currentLocation, firOpBuilder.getI32Type(), 1);
+ allocatorOperands.insert(allocatorOperands.end(), ompObjectList.v.size(),
+ allocatorOperand);
+ }
+ genObjectList(ompObjectList, converter, allocateOperands);
+}
+
+static mlir::omp::ClauseProcBindKindAttr genProcBindKindAttr(
+ fir::FirOpBuilder &firOpBuilder,
+ const Fortran::parser::OmpClause::ProcBind *procBindClause) {
+ mlir::omp::ClauseProcBindKind procBindKind;
+ switch (procBindClause->v.v) {
+ case Fortran::parser::OmpProcBindClause::Type::Master:
+ procBindKind = mlir::omp::ClauseProcBindKind::Master;
+ break;
+ case Fortran::parser::OmpProcBindClause::Type::Close:
+ procBindKind = mlir::omp::ClauseProcBindKind::Close;
+ break;
+ case Fortran::parser::OmpProcBindClause::Type::Spread:
+ procBindKind = mlir::omp::ClauseProcBindKind::Spread;
+ break;
+ case Fortran::parser::OmpProcBindClause::Type::Primary:
+ procBindKind = mlir::omp::ClauseProcBindKind::Primary;
+ break;
+ }
+ return mlir::omp::ClauseProcBindKindAttr::get(firOpBuilder.getContext(),
+ procBindKind);
+}
+
+static mlir::omp::ClauseTaskDependAttr
+genDependKindAttr(fir::FirOpBuilder &firOpBuilder,
+ const Fortran::parser::OmpClause::Depend *dependClause) {
+ mlir::omp::ClauseTaskDepend pbKind;
+ switch (
+ std::get<Fortran::parser::OmpDependenceType>(
+ std::get<Fortran::parser::OmpDependClause::InOut>(dependClause->v.u)
+ .t)
+ .v) {
+ case Fortran::parser::OmpDependenceType::Type::In:
+ pbKind = mlir::omp::ClauseTaskDepend::taskdependin;
+ break;
+ case Fortran::parser::OmpDependenceType::Type::Out:
+ pbKind = mlir::omp::ClauseTaskDepend::taskdependout;
+ break;
+ case Fortran::parser::OmpDependenceType::Type::Inout:
+ pbKind = mlir::omp::ClauseTaskDepend::taskdependinout;
+ break;
+ default:
+ llvm_unreachable("unknown parser task dependence type");
+ break;
+ }
+ return mlir::omp::ClauseTaskDependAttr::get(firOpBuilder.getContext(),
+ pbKind);
+}
+
+static mlir::Value getIfClauseOperand(
+ Fortran::lower::AbstractConverter &converter,
+ const Fortran::parser::OmpClause::If *ifClause,
+ Fortran::parser::OmpIfClause::DirectiveNameModifier directiveName,
+ mlir::Location clauseLocation) {
+ // Only consider the clause if it's intended for the given directive.
+ auto &directive = std::get<
+ std::optional<Fortran::parser::OmpIfClause::DirectiveNameModifier>>(
+ ifClause->v.t);
+ if (directive && directive.value() != directiveName)
+ return nullptr;
+
+ Fortran::lower::StatementContext stmtCtx;
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ auto &expr = std::get<Fortran::parser::ScalarLogicalExpr>(ifClause->v.t);
+ mlir::Value ifVal = fir::getBase(
+ converter.genExprValue(*Fortran::semantics::GetExpr(expr), stmtCtx));
+ return firOpBuilder.createConvert(clauseLocation, firOpBuilder.getI1Type(),
+ ifVal);
+}
+
+static void
+addUseDeviceClause(Fortran::lower::AbstractConverter &converter,
+ const Fortran::parser::OmpObjectList &useDeviceClause,
+ llvm::SmallVectorImpl<mlir::Value> &operands,
+ llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
+ llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
+ llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
+ &useDeviceSymbols) {
+ genObjectList(useDeviceClause, converter, operands);
+ for (mlir::Value &operand : operands) {
+ checkMapType(operand.getLoc(), operand.getType());
+ useDeviceTypes.push_back(operand.getType());
+ useDeviceLocs.push_back(operand.getLoc());
+ }
+ for (const Fortran::parser::OmpObject &ompObject : useDeviceClause.v) {
+ Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject);
+ useDeviceSymbols.push_back(sym);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// ClauseProcessor unique clauses
+//===----------------------------------------------------------------------===//
+
+bool ClauseProcessor::processCollapse(
+ mlir::Location currentLocation, Fortran::lower::pft::Evaluation &eval,
+ llvm::SmallVectorImpl<mlir::Value> &lowerBound,
+ llvm::SmallVectorImpl<mlir::Value> &upperBound,
+ llvm::SmallVectorImpl<mlir::Value> &step,
+ llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &iv,
+ std::size_t &loopVarTypeSize) const {
+ bool found = false;
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+
+ // Collect the loops to collapse.
+ Fortran::lower::pft::Evaluation *doConstructEval =
+ &eval.getFirstNestedEvaluation();
+ if (doConstructEval->getIf<Fortran::parser::DoConstruct>()
+ ->IsDoConcurrent()) {
+ TODO(currentLocation, "Do Concurrent in Worksharing loop construct");
+ }
+
+ std::int64_t collapseValue = 1l;
+ if (auto *collapseClause = findUniqueClause<ClauseTy::Collapse>()) {
+ const auto *expr = Fortran::semantics::GetExpr(collapseClause->v);
+ collapseValue = Fortran::evaluate::ToInt64(*expr).value();
+ found = true;
+ }
+
+ loopVarTypeSize = 0;
+ do {
+ Fortran::lower::pft::Evaluation *doLoop =
+ &doConstructEval->getFirstNestedEvaluation();
+ auto *doStmt = doLoop->getIf<Fortran::parser::NonLabelDoStmt>();
+ assert(doStmt && "Expected do loop to be in the nested evaluation");
+ const auto &loopControl =
+ std::get<std::optional<Fortran::parser::LoopControl>>(doStmt->t);
+ const Fortran::parser::LoopControl::Bounds *bounds =
+ std::get_if<Fortran::parser::LoopControl::Bounds>(&loopControl->u);
+ assert(bounds && "Expected bounds for worksharing do loop");
+ Fortran::lower::StatementContext stmtCtx;
+ lowerBound.push_back(fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(bounds->lower), stmtCtx)));
+ upperBound.push_back(fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(bounds->upper), stmtCtx)));
+ if (bounds->step) {
+ step.push_back(fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(bounds->step), stmtCtx)));
+ } else { // If `step` is not present, assume it as `1`.
+ step.push_back(firOpBuilder.createIntegerConstant(
+ currentLocation, firOpBuilder.getIntegerType(32), 1));
+ }
+ iv.push_back(bounds->name.thing.symbol);
+ loopVarTypeSize = std::max(loopVarTypeSize,
+ bounds->name.thing.symbol->GetUltimate().size());
+ collapseValue--;
+ doConstructEval =
+ &*std::next(doConstructEval->getNestedEvaluations().begin());
+ } while (collapseValue > 0);
+
+ return found;
+}
+
+bool ClauseProcessor::processDefault() const {
+ if (auto *defaultClause = findUniqueClause<ClauseTy::Default>()) {
+ // Private, Firstprivate, Shared, None
+ switch (defaultClause->v.v) {
+ case Fortran::parser::OmpDefaultClause::Type::Shared:
+ case Fortran::parser::OmpDefaultClause::Type::None:
+ // Default clause with shared or none do not require any handling since
+ // Shared is the default behavior in the IR and None is only required
+ // for semantic checks.
+ break;
+ case Fortran::parser::OmpDefaultClause::Type::Private:
+ // TODO Support default(private)
+ break;
+ case Fortran::parser::OmpDefaultClause::Type::Firstprivate:
+ // TODO Support default(firstprivate)
+ break;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ClauseProcessor::processDevice(Fortran::lower::StatementContext &stmtCtx,
+ mlir::Value &result) const {
+ const Fortran::parser::CharBlock *source = nullptr;
+ if (auto *deviceClause = findUniqueClause<ClauseTy::Device>(&source)) {
+ mlir::Location clauseLocation = converter.genLocation(*source);
+ if (auto deviceModifier = std::get<
+ std::optional<Fortran::parser::OmpDeviceClause::DeviceModifier>>(
+ deviceClause->v.t)) {
+ if (deviceModifier ==
+ Fortran::parser::OmpDeviceClause::DeviceModifier::Ancestor) {
+ TODO(clauseLocation, "OMPD_target Device Modifier Ancestor");
+ }
+ }
+ if (const auto *deviceExpr = Fortran::semantics::GetExpr(
+ std::get<Fortran::parser::ScalarIntExpr>(deviceClause->v.t))) {
+ result = fir::getBase(converter.genExprValue(*deviceExpr, stmtCtx));
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ClauseProcessor::processDeviceType(
+ mlir::omp::DeclareTargetDeviceType &result) const {
+ if (auto *deviceTypeClause = findUniqueClause<ClauseTy::DeviceType>()) {
+ // Case: declare target ... device_type(any | host | nohost)
+ switch (deviceTypeClause->v.v) {
+ case Fortran::parser::OmpDeviceTypeClause::Type::Nohost:
+ result = mlir::omp::DeclareTargetDeviceType::nohost;
+ break;
+ case Fortran::parser::OmpDeviceTypeClause::Type::Host:
+ result = mlir::omp::DeclareTargetDeviceType::host;
+ break;
+ case Fortran::parser::OmpDeviceTypeClause::Type::Any:
+ result = mlir::omp::DeclareTargetDeviceType::any;
+ break;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ClauseProcessor::processFinal(Fortran::lower::StatementContext &stmtCtx,
+ mlir::Value &result) const {
+ const Fortran::parser::CharBlock *source = nullptr;
+ if (auto *finalClause = findUniqueClause<ClauseTy::Final>(&source)) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ mlir::Location clauseLocation = converter.genLocation(*source);
+
+ mlir::Value finalVal = fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(finalClause->v), stmtCtx));
+ result = firOpBuilder.createConvert(clauseLocation,
+ firOpBuilder.getI1Type(), finalVal);
+ return true;
+ }
+ return false;
+}
+
+bool ClauseProcessor::processHint(mlir::IntegerAttr &result) const {
+ if (auto *hintClause = findUniqueClause<ClauseTy::Hint>()) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
+ int64_t hintValue = *Fortran::evaluate::ToInt64(*expr);
+ result = firOpBuilder.getI64IntegerAttr(hintValue);
+ return true;
+ }
+ return false;
+}
+
+bool ClauseProcessor::processMergeable(mlir::UnitAttr &result) const {
+ return markClauseOccurrence<ClauseTy::Mergeable>(result);
+}
+
+bool ClauseProcessor::processNowait(mlir::UnitAttr &result) const {
+ return markClauseOccurrence<ClauseTy::Nowait>(result);
+}
+
+bool ClauseProcessor::processNumTeams(Fortran::lower::StatementContext &stmtCtx,
+ mlir::Value &result) const {
+ // TODO Get lower and upper bounds for num_teams when parser is updated to
+ // accept both.
+ if (auto *numTeamsClause = findUniqueClause<ClauseTy::NumTeams>()) {
+ result = fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(numTeamsClause->v), stmtCtx));
+ return true;
+ }
+ return false;
+}
+
+bool ClauseProcessor::processNumThreads(
+ Fortran::lower::StatementContext &stmtCtx, mlir::Value &result) const {
+ if (auto *numThreadsClause = findUniqueClause<ClauseTy::NumThreads>()) {
+ // OMPIRBuilder expects `NUM_THREADS` clause as a `Value`.
+ result = fir::getBase(converter.genExprValue(
+ *Fortran::semantics::GetExpr(numThreadsClause->v), stmtCtx));
+ return true;
+ }
+ return false;
+...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/81973
More information about the flang-commits
mailing list