Skip to content

Commit bb85bdf

Browse files
committed
[NFC][flang][OpenMP] Split DataSharing and Clause processors
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.
1 parent b8ed69e commit bb85bdf

10 files changed

+2321
-2034
lines changed

flang/lib/Lower/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ add_flang_library(FortranLower
2525
Mangler.cpp
2626
OpenACC.cpp
2727
OpenMP.cpp
28+
OpenMP/ClauseProcessor.cpp
29+
OpenMP/DataSharingProcessor.cpp
30+
OpenMP/Utils.cpp
31+
OpenMP/ReductionProcessor.cpp
2832
PFTBuilder.cpp
2933
Runtime.cpp
3034
SymbolMap.cpp

flang/lib/Lower/OpenMP.cpp

Lines changed: 5 additions & 2034 deletions
Large diffs are not rendered by default.

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 930 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
//===-- Lower/OpenMP/ClauseProcessor.h --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#ifndef FORTRAN_LOWER_CLAUASEPROCESSOR_H
13+
#define FORTRAN_LOWER_CLAUASEPROCESSOR_H
14+
15+
#include "DirectivesCommon.h"
16+
#include "ReductionProcessor.h"
17+
#include "Utils.h"
18+
#include "flang/Lower/AbstractConverter.h"
19+
#include "flang/Lower/Bridge.h"
20+
#include "flang/Optimizer/Builder/Todo.h"
21+
#include "flang/Parser/dump-parse-tree.h"
22+
#include "flang/Parser/parse-tree.h"
23+
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
24+
#include "llvm/Support/CommandLine.h"
25+
26+
extern llvm::cl::opt<bool> treatIndexAsSection;
27+
28+
namespace fir {
29+
class FirOpBuilder;
30+
} // namespace fir
31+
32+
namespace Fortran {
33+
namespace lower {
34+
namespace omp {
35+
36+
using DeclareTargetCapturePair =
37+
std::pair<mlir::omp::DeclareTargetCaptureClause,
38+
Fortran::semantics::Symbol>;
39+
40+
mlir::omp::MapInfoOp
41+
createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
42+
mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name,
43+
mlir::SmallVector<mlir::Value> bounds,
44+
mlir::SmallVector<mlir::Value> members, uint64_t mapType,
45+
mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
46+
bool isVal = false);
47+
48+
void gatherFuncAndVarSyms(
49+
const Fortran::parser::OmpObjectList &objList,
50+
mlir::omp::DeclareTargetCaptureClause clause,
51+
llvm::SmallVectorImpl<DeclareTargetCapturePair> &symbolAndClause);
52+
53+
void genObjectList(const Fortran::parser::OmpObjectList &objectList,
54+
Fortran::lower::AbstractConverter &converter,
55+
llvm::SmallVectorImpl<mlir::Value> &operands);
56+
57+
/// Class that handles the processing of OpenMP clauses.
58+
///
59+
/// Its `process<ClauseName>()` methods perform MLIR code generation for their
60+
/// corresponding clause if it is present in the clause list. Otherwise, they
61+
/// will return `false` to signal that the clause was not found.
62+
///
63+
/// The intended use is of this class is to move clause processing outside of
64+
/// construct processing, since the same clauses can appear attached to
65+
/// different constructs and constructs can be combined, so that code
66+
/// duplication is minimized.
67+
///
68+
/// Each construct-lowering function only calls the `process<ClauseName>()`
69+
/// methods that relate to clauses that can impact the lowering of that
70+
/// construct.
71+
class ClauseProcessor {
72+
using ClauseTy = Fortran::parser::OmpClause;
73+
74+
public:
75+
ClauseProcessor(Fortran::lower::AbstractConverter &converter,
76+
Fortran::semantics::SemanticsContext &semaCtx,
77+
const Fortran::parser::OmpClauseList &clauses)
78+
: converter(converter), semaCtx(semaCtx), clauses(clauses) {}
79+
80+
// 'Unique' clauses: They can appear at most once in the clause list.
81+
bool
82+
processCollapse(mlir::Location currentLocation,
83+
Fortran::lower::pft::Evaluation &eval,
84+
llvm::SmallVectorImpl<mlir::Value> &lowerBound,
85+
llvm::SmallVectorImpl<mlir::Value> &upperBound,
86+
llvm::SmallVectorImpl<mlir::Value> &step,
87+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &iv,
88+
std::size_t &loopVarTypeSize) const;
89+
bool processDefault() const;
90+
bool processDevice(Fortran::lower::StatementContext &stmtCtx,
91+
mlir::Value &result) const;
92+
bool processDeviceType(mlir::omp::DeclareTargetDeviceType &result) const;
93+
bool processFinal(Fortran::lower::StatementContext &stmtCtx,
94+
mlir::Value &result) const;
95+
bool processHint(mlir::IntegerAttr &result) const;
96+
bool processMergeable(mlir::UnitAttr &result) const;
97+
bool processNowait(mlir::UnitAttr &result) const;
98+
bool processNumTeams(Fortran::lower::StatementContext &stmtCtx,
99+
mlir::Value &result) const;
100+
bool processNumThreads(Fortran::lower::StatementContext &stmtCtx,
101+
mlir::Value &result) const;
102+
bool processOrdered(mlir::IntegerAttr &result) const;
103+
bool processPriority(Fortran::lower::StatementContext &stmtCtx,
104+
mlir::Value &result) const;
105+
bool processProcBind(mlir::omp::ClauseProcBindKindAttr &result) const;
106+
bool processSafelen(mlir::IntegerAttr &result) const;
107+
bool processSchedule(mlir::omp::ClauseScheduleKindAttr &valAttr,
108+
mlir::omp::ScheduleModifierAttr &modifierAttr,
109+
mlir::UnitAttr &simdModifierAttr) const;
110+
bool processScheduleChunk(Fortran::lower::StatementContext &stmtCtx,
111+
mlir::Value &result) const;
112+
bool processSimdlen(mlir::IntegerAttr &result) const;
113+
bool processThreadLimit(Fortran::lower::StatementContext &stmtCtx,
114+
mlir::Value &result) const;
115+
bool processUntied(mlir::UnitAttr &result) const;
116+
117+
// 'Repeatable' clauses: They can appear multiple times in the clause list.
118+
bool
119+
processAllocate(llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,
120+
llvm::SmallVectorImpl<mlir::Value> &allocateOperands) const;
121+
bool processCopyin() const;
122+
bool processDepend(llvm::SmallVectorImpl<mlir::Attribute> &dependTypeOperands,
123+
llvm::SmallVectorImpl<mlir::Value> &dependOperands) const;
124+
bool
125+
processEnter(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
126+
bool
127+
processIf(Fortran::parser::OmpIfClause::DirectiveNameModifier directiveName,
128+
mlir::Value &result) const;
129+
bool
130+
processLink(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
131+
132+
// This method is used to process a map clause.
133+
// The optional parameters - mapSymTypes, mapSymLocs & mapSymbols are used to
134+
// store the original type, location and Fortran symbol for the map operands.
135+
// They may be used later on to create the block_arguments for some of the
136+
// target directives that require it.
137+
bool processMap(mlir::Location currentLocation,
138+
const llvm::omp::Directive &directive,
139+
Fortran::lower::StatementContext &stmtCtx,
140+
llvm::SmallVectorImpl<mlir::Value> &mapOperands,
141+
llvm::SmallVectorImpl<mlir::Type> *mapSymTypes = nullptr,
142+
llvm::SmallVectorImpl<mlir::Location> *mapSymLocs = nullptr,
143+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
144+
*mapSymbols = nullptr) const;
145+
bool
146+
processReduction(mlir::Location currentLocation,
147+
llvm::SmallVectorImpl<mlir::Value> &reductionVars,
148+
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
149+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
150+
*reductionSymbols = nullptr) const;
151+
bool processSectionsReduction(mlir::Location currentLocation) const;
152+
bool processTo(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
153+
bool
154+
processUseDeviceAddr(llvm::SmallVectorImpl<mlir::Value> &operands,
155+
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
156+
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
157+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
158+
&useDeviceSymbols) const;
159+
bool
160+
processUseDevicePtr(llvm::SmallVectorImpl<mlir::Value> &operands,
161+
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
162+
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
163+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
164+
&useDeviceSymbols) const;
165+
166+
template <typename T>
167+
bool processMotionClauses(Fortran::lower::StatementContext &stmtCtx,
168+
llvm::SmallVectorImpl<mlir::Value> &mapOperands) {
169+
return findRepeatableClause<T>(
170+
[&](const T *motionClause, const Fortran::parser::CharBlock &source) {
171+
mlir::Location clauseLocation = converter.genLocation(source);
172+
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
173+
174+
static_assert(std::is_same_v<T, ClauseProcessor::ClauseTy::To> ||
175+
std::is_same_v<T, ClauseProcessor::ClauseTy::From>);
176+
177+
// TODO Support motion modifiers: present, mapper, iterator.
178+
constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
179+
std::is_same_v<T, ClauseProcessor::ClauseTy::To>
180+
? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO
181+
: llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
182+
183+
for (const Fortran::parser::OmpObject &ompObject :
184+
motionClause->v.v) {
185+
llvm::SmallVector<mlir::Value> bounds;
186+
std::stringstream asFortran;
187+
Fortran::lower::AddrAndBoundsInfo info =
188+
Fortran::lower::gatherDataOperandAddrAndBounds<
189+
Fortran::parser::OmpObject, mlir::omp::DataBoundsOp,
190+
mlir::omp::DataBoundsType>(
191+
converter, firOpBuilder, semaCtx, stmtCtx, ompObject,
192+
clauseLocation, asFortran, bounds, treatIndexAsSection);
193+
194+
auto origSymbol =
195+
converter.getSymbolAddress(*getOmpObjectSymbol(ompObject));
196+
mlir::Value symAddr = info.addr;
197+
if (origSymbol && fir::isTypeWithDescriptor(origSymbol.getType()))
198+
symAddr = origSymbol;
199+
200+
// Explicit map captures are captured ByRef by default,
201+
// optimisation passes may alter this to ByCopy or other capture
202+
// types to optimise
203+
mlir::Value mapOp = createMapInfoOp(
204+
firOpBuilder, clauseLocation, symAddr, mlir::Value{},
205+
asFortran.str(), bounds, {},
206+
static_cast<std::underlying_type_t<
207+
llvm::omp::OpenMPOffloadMappingFlags>>(mapTypeBits),
208+
mlir::omp::VariableCaptureKind::ByRef, symAddr.getType());
209+
210+
mapOperands.push_back(mapOp);
211+
}
212+
});
213+
}
214+
215+
// Call this method for these clauses that should be supported but are not
216+
// implemented yet. It triggers a compilation error if any of the given
217+
// clauses is found.
218+
template <typename... Ts>
219+
void processTODO(mlir::Location currentLocation,
220+
llvm::omp::Directive directive) const {
221+
auto checkUnhandledClause = [&](const auto *x) {
222+
if (!x)
223+
return;
224+
TODO(
225+
currentLocation,
226+
"Unhandled clause " +
227+
llvm::StringRef(Fortran::parser::ParseTreeDumper::GetNodeName(*x))
228+
.upper() +
229+
" in " + llvm::omp::getOpenMPDirectiveName(directive).upper() +
230+
" construct");
231+
};
232+
233+
for (ClauseIterator it = clauses.v.begin(); it != clauses.v.end(); ++it)
234+
(checkUnhandledClause(std::get_if<Ts>(&it->u)), ...);
235+
}
236+
237+
private:
238+
using ClauseIterator = std::list<ClauseTy>::const_iterator;
239+
240+
/// Utility to find a clause within a range in the clause list.
241+
template <typename T>
242+
static ClauseIterator findClause(ClauseIterator begin, ClauseIterator end) {
243+
for (ClauseIterator it = begin; it != end; ++it) {
244+
if (std::get_if<T>(&it->u))
245+
return it;
246+
}
247+
248+
return end;
249+
}
250+
251+
/// Return the first instance of the given clause found in the clause list or
252+
/// `nullptr` if not present. If more than one instance is expected, use
253+
/// `findRepeatableClause` instead.
254+
template <typename T>
255+
const T *
256+
findUniqueClause(const Fortran::parser::CharBlock **source = nullptr) const {
257+
ClauseIterator it = findClause<T>(clauses.v.begin(), clauses.v.end());
258+
if (it != clauses.v.end()) {
259+
if (source)
260+
*source = &it->source;
261+
return &std::get<T>(it->u);
262+
}
263+
return nullptr;
264+
}
265+
266+
/// Call `callbackFn` for each occurrence of the given clause. Return `true`
267+
/// if at least one instance was found.
268+
template <typename T>
269+
bool findRepeatableClause(
270+
std::function<void(const T *, const Fortran::parser::CharBlock &source)>
271+
callbackFn) const {
272+
bool found = false;
273+
ClauseIterator nextIt, endIt = clauses.v.end();
274+
for (ClauseIterator it = clauses.v.begin(); it != endIt; it = nextIt) {
275+
nextIt = findClause<T>(it, endIt);
276+
277+
if (nextIt != endIt) {
278+
callbackFn(&std::get<T>(nextIt->u), nextIt->source);
279+
found = true;
280+
++nextIt;
281+
}
282+
}
283+
return found;
284+
}
285+
286+
/// Set the `result` to a new `mlir::UnitAttr` if the clause is present.
287+
template <typename T>
288+
bool markClauseOccurrence(mlir::UnitAttr &result) const {
289+
if (findUniqueClause<T>()) {
290+
result = converter.getFirOpBuilder().getUnitAttr();
291+
return true;
292+
}
293+
return false;
294+
}
295+
296+
Fortran::lower::AbstractConverter &converter;
297+
Fortran::semantics::SemanticsContext &semaCtx;
298+
const Fortran::parser::OmpClauseList &clauses;
299+
};
300+
301+
} // namespace omp
302+
} // namespace lower
303+
} // namespace Fortran
304+
305+
#endif // FORTRAN_LOWER_CLAUASEPROCESSOR_H

0 commit comments

Comments
 (0)