Skip to content

Commit 85a6fc6

Browse files
committed
[flang][OpenMP] WIP: Rewrite omp.loop to semantically equivalent ops
Introduces a new conversion pass that rewrites `omp.loop` ops to their semantically equivalent op nests bases on the surrounding/binding context of the `loop` op. Not all forms of `omp.loop` are supported yet.
1 parent 922282e commit 85a6fc6

File tree

10 files changed

+411
-97
lines changed

10 files changed

+411
-97
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===-- include/flang/Common/OpenMP-utils.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+
#ifndef FORTRAN_COMMON_OPENMP_UTILS_H_
10+
#define FORTRAN_COMMON_OPENMP_UTILS_H_
11+
12+
#include "flang/Semantics/symbol.h"
13+
14+
#include "mlir/IR/Builders.h"
15+
#include "mlir/IR/Value.h"
16+
17+
#include "llvm/ADT/ArrayRef.h"
18+
19+
namespace Fortran::openmp::common {
20+
/// Structure holding the information needed to create and bind entry block
21+
/// arguments associated to a single clause.
22+
struct EntryBlockArgsEntry {
23+
llvm::ArrayRef<const Fortran::semantics::Symbol *> syms;
24+
llvm::ArrayRef<mlir::Value> vars;
25+
26+
bool isValid() const {
27+
// This check allows specifying a smaller number of symbols than values
28+
// because in some case cases a single symbol generates multiple block
29+
// arguments.
30+
return syms.size() <= vars.size();
31+
}
32+
};
33+
34+
/// Structure holding the information needed to create and bind entry block
35+
/// arguments associated to all clauses that can define them.
36+
struct EntryBlockArgs {
37+
EntryBlockArgsEntry inReduction;
38+
EntryBlockArgsEntry map;
39+
EntryBlockArgsEntry priv;
40+
EntryBlockArgsEntry reduction;
41+
EntryBlockArgsEntry taskReduction;
42+
EntryBlockArgsEntry useDeviceAddr;
43+
EntryBlockArgsEntry useDevicePtr;
44+
45+
bool isValid() const {
46+
return inReduction.isValid() && map.isValid() && priv.isValid() &&
47+
reduction.isValid() && taskReduction.isValid() &&
48+
useDeviceAddr.isValid() && useDevicePtr.isValid();
49+
}
50+
51+
auto getSyms() const {
52+
return llvm::concat<const Fortran::semantics::Symbol *const>(
53+
inReduction.syms, map.syms, priv.syms, reduction.syms,
54+
taskReduction.syms, useDeviceAddr.syms, useDevicePtr.syms);
55+
}
56+
57+
auto getVars() const {
58+
return llvm::concat<const mlir::Value>(inReduction.vars, map.vars,
59+
priv.vars, reduction.vars, taskReduction.vars, useDeviceAddr.vars,
60+
useDevicePtr.vars);
61+
}
62+
};
63+
64+
mlir::Block *genEntryBlock(
65+
mlir::OpBuilder &builder, const EntryBlockArgs &args, mlir::Region &region);
66+
} // namespace Fortran::openmp::common
67+
68+
#endif // FORTRAN_COMMON_OPENMP_UTILS_H_

flang/include/flang/Optimizer/OpenMP/Passes.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,25 @@ def FunctionFilteringPass : Pass<"omp-function-filtering"> {
5050
];
5151
}
5252

53+
5354
// Needs to be scheduled on Module as we create functions in it
5455
def LowerWorkshare : Pass<"lower-workshare", "::mlir::ModuleOp"> {
5556
let summary = "Lower workshare construct";
5657
}
5758

59+
def GenericLoopConversionPass
60+
: Pass<"omp-generic-loop-conversion", "mlir::func::FuncOp"> {
61+
let summary = "Converts OpenMP generic `loop` directive to semantically "
62+
"equivalent OpenMP ops";
63+
let description = [{
64+
Rewrites `loop` ops to their semantically equivalent nest of ops. The
65+
rewrite depends on the nesting/combination structure of the `loop` op
66+
within its surrounding context as well as its `bind` clause value.
67+
}];
68+
let dependentDialects = [
69+
"mlir::func::FuncDialect",
70+
"mlir::omp::OpenMPDialect"
71+
];
72+
}
73+
5874
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES

flang/lib/Common/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,13 @@ add_flang_library(FortranCommon
4040
default-kinds.cpp
4141
idioms.cpp
4242
LangOptions.cpp
43+
OpenMP-utils.cpp
4344
Version.cpp
4445
${version_inc}
4546

4647
LINK_COMPONENTS
4748
Support
49+
50+
LINK_LIBS
51+
MLIRIR
4852
)

flang/lib/Common/OpenMP-utils.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===-- include/flang/Common/OpenMP-utils.cpp ------------------*- 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+
#include "flang/Common/OpenMP-utils.h"
10+
11+
#include "mlir/IR/OpDefinition.h"
12+
13+
namespace Fortran::openmp::common {
14+
mlir::Block *genEntryBlock(mlir::OpBuilder &builder, const EntryBlockArgs &args,
15+
mlir::Region &region) {
16+
assert(args.isValid() && "invalid args");
17+
assert(region.empty() && "non-empty region");
18+
19+
llvm::SmallVector<mlir::Type> types;
20+
llvm::SmallVector<mlir::Location> locs;
21+
unsigned numVars = args.inReduction.vars.size() + args.map.vars.size() +
22+
args.priv.vars.size() + args.reduction.vars.size() +
23+
args.taskReduction.vars.size() + args.useDeviceAddr.vars.size() +
24+
args.useDevicePtr.vars.size();
25+
types.reserve(numVars);
26+
locs.reserve(numVars);
27+
28+
auto extractTypeLoc = [&types, &locs](llvm::ArrayRef<mlir::Value> vals) {
29+
llvm::transform(vals, std::back_inserter(types),
30+
[](mlir::Value v) { return v.getType(); });
31+
llvm::transform(vals, std::back_inserter(locs),
32+
[](mlir::Value v) { return v.getLoc(); });
33+
};
34+
35+
// Populate block arguments in clause name alphabetical order to match
36+
// expected order by the BlockArgOpenMPOpInterface.
37+
extractTypeLoc(args.inReduction.vars);
38+
extractTypeLoc(args.map.vars);
39+
extractTypeLoc(args.priv.vars);
40+
extractTypeLoc(args.reduction.vars);
41+
extractTypeLoc(args.taskReduction.vars);
42+
extractTypeLoc(args.useDeviceAddr.vars);
43+
extractTypeLoc(args.useDevicePtr.vars);
44+
45+
return builder.createBlock(&region, {}, types, locs);
46+
}
47+
} // namespace Fortran::openmp::common

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 10 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "DirectivesCommon.h"
2020
#include "ReductionProcessor.h"
2121
#include "Utils.h"
22+
#include "flang/Common/OpenMP-utils.h"
2223
#include "flang/Common/idioms.h"
2324
#include "flang/Lower/Bridge.h"
2425
#include "flang/Lower/ConvertExpr.h"
@@ -41,57 +42,12 @@
4142
#include "llvm/Frontend/OpenMP/OMPConstants.h"
4243

4344
using namespace Fortran::lower::omp;
45+
using namespace Fortran::openmp::common;
4446

4547
//===----------------------------------------------------------------------===//
4648
// Code generation helper functions
4749
//===----------------------------------------------------------------------===//
4850

49-
namespace {
50-
/// Structure holding the information needed to create and bind entry block
51-
/// arguments associated to a single clause.
52-
struct EntryBlockArgsEntry {
53-
llvm::ArrayRef<const semantics::Symbol *> syms;
54-
llvm::ArrayRef<mlir::Value> vars;
55-
56-
bool isValid() const {
57-
// This check allows specifying a smaller number of symbols than values
58-
// because in some case cases a single symbol generates multiple block
59-
// arguments.
60-
return syms.size() <= vars.size();
61-
}
62-
};
63-
64-
/// Structure holding the information needed to create and bind entry block
65-
/// arguments associated to all clauses that can define them.
66-
struct EntryBlockArgs {
67-
EntryBlockArgsEntry inReduction;
68-
EntryBlockArgsEntry map;
69-
EntryBlockArgsEntry priv;
70-
EntryBlockArgsEntry reduction;
71-
EntryBlockArgsEntry taskReduction;
72-
EntryBlockArgsEntry useDeviceAddr;
73-
EntryBlockArgsEntry useDevicePtr;
74-
75-
bool isValid() const {
76-
return inReduction.isValid() && map.isValid() && priv.isValid() &&
77-
reduction.isValid() && taskReduction.isValid() &&
78-
useDeviceAddr.isValid() && useDevicePtr.isValid();
79-
}
80-
81-
auto getSyms() const {
82-
return llvm::concat<const semantics::Symbol *const>(
83-
inReduction.syms, map.syms, priv.syms, reduction.syms,
84-
taskReduction.syms, useDeviceAddr.syms, useDevicePtr.syms);
85-
}
86-
87-
auto getVars() const {
88-
return llvm::concat<const mlir::Value>(
89-
inReduction.vars, map.vars, priv.vars, reduction.vars,
90-
taskReduction.vars, useDeviceAddr.vars, useDevicePtr.vars);
91-
}
92-
};
93-
} // namespace
94-
9551
static void genOMPDispatch(lower::AbstractConverter &converter,
9652
lower::SymMap &symTable,
9753
semantics::SemanticsContext &semaCtx,
@@ -623,50 +579,6 @@ static void genLoopVars(
623579
firOpBuilder.setInsertionPointAfter(storeOp);
624580
}
625581

626-
/// Create an entry block for the given region, including the clause-defined
627-
/// arguments specified.
628-
///
629-
/// \param [in] converter - PFT to MLIR conversion interface.
630-
/// \param [in] args - entry block arguments information for the given
631-
/// operation.
632-
/// \param [in] region - Empty region in which to create the entry block.
633-
static mlir::Block *genEntryBlock(lower::AbstractConverter &converter,
634-
const EntryBlockArgs &args,
635-
mlir::Region &region) {
636-
assert(args.isValid() && "invalid args");
637-
assert(region.empty() && "non-empty region");
638-
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
639-
640-
llvm::SmallVector<mlir::Type> types;
641-
llvm::SmallVector<mlir::Location> locs;
642-
unsigned numVars = args.inReduction.vars.size() + args.map.vars.size() +
643-
args.priv.vars.size() + args.reduction.vars.size() +
644-
args.taskReduction.vars.size() +
645-
args.useDeviceAddr.vars.size() +
646-
args.useDevicePtr.vars.size();
647-
types.reserve(numVars);
648-
locs.reserve(numVars);
649-
650-
auto extractTypeLoc = [&types, &locs](llvm::ArrayRef<mlir::Value> vals) {
651-
llvm::transform(vals, std::back_inserter(types),
652-
[](mlir::Value v) { return v.getType(); });
653-
llvm::transform(vals, std::back_inserter(locs),
654-
[](mlir::Value v) { return v.getLoc(); });
655-
};
656-
657-
// Populate block arguments in clause name alphabetical order to match
658-
// expected order by the BlockArgOpenMPOpInterface.
659-
extractTypeLoc(args.inReduction.vars);
660-
extractTypeLoc(args.map.vars);
661-
extractTypeLoc(args.priv.vars);
662-
extractTypeLoc(args.reduction.vars);
663-
extractTypeLoc(args.taskReduction.vars);
664-
extractTypeLoc(args.useDeviceAddr.vars);
665-
extractTypeLoc(args.useDevicePtr.vars);
666-
667-
return firOpBuilder.createBlock(&region, {}, types, locs);
668-
}
669-
670582
static void
671583
markDeclareTarget(mlir::Operation *op, lower::AbstractConverter &converter,
672584
mlir::omp::DeclareTargetCaptureClause captureClause,
@@ -919,7 +831,7 @@ static void genBodyOfTargetDataOp(
919831
ConstructQueue::const_iterator item) {
920832
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
921833

922-
genEntryBlock(converter, args, dataOp.getRegion());
834+
genEntryBlock(converter.getFirOpBuilder(), args, dataOp.getRegion());
923835
bindEntryBlockArgs(converter, dataOp, args);
924836

925837
// Insert dummy instruction to remember the insertion position. The
@@ -996,7 +908,8 @@ static void genBodyOfTargetOp(
996908
auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
997909

998910
mlir::Region &region = targetOp.getRegion();
999-
mlir::Block *entryBlock = genEntryBlock(converter, args, region);
911+
mlir::Block *entryBlock =
912+
genEntryBlock(converter.getFirOpBuilder(), args, region);
1000913
bindEntryBlockArgs(converter, targetOp, args);
1001914

1002915
// Check if cloning the bounds introduced any dependency on the outer region.
@@ -1122,7 +1035,7 @@ static OpTy genWrapperOp(lower::AbstractConverter &converter,
11221035
auto op = firOpBuilder.create<OpTy>(loc, clauseOps);
11231036

11241037
// Create entry block with arguments.
1125-
genEntryBlock(converter, args, op.getRegion());
1038+
genEntryBlock(converter.getFirOpBuilder(), args, op.getRegion());
11261039

11271040
return op;
11281041
}
@@ -1588,7 +1501,7 @@ genParallelOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
15881501
const EntryBlockArgs &args, DataSharingProcessor *dsp,
15891502
bool isComposite = false) {
15901503
auto genRegionEntryCB = [&](mlir::Operation *op) {
1591-
genEntryBlock(converter, args, op->getRegion(0));
1504+
genEntryBlock(converter.getFirOpBuilder(), args, op->getRegion(0));
15921505
bindEntryBlockArgs(
15931506
converter, llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op), args);
15941507
return llvm::to_vector(args.getSyms());
@@ -1661,12 +1574,12 @@ genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
16611574
args.reduction.syms = reductionSyms;
16621575
args.reduction.vars = clauseOps.reductionVars;
16631576

1664-
genEntryBlock(converter, args, sectionsOp.getRegion());
1577+
genEntryBlock(converter.getFirOpBuilder(), args, sectionsOp.getRegion());
16651578
mlir::Operation *terminator =
16661579
lower::genOpenMPTerminator(builder, sectionsOp, loc);
16671580

16681581
auto genRegionEntryCB = [&](mlir::Operation *op) {
1669-
genEntryBlock(converter, args, op->getRegion(0));
1582+
genEntryBlock(converter.getFirOpBuilder(), args, op->getRegion(0));
16701583
bindEntryBlockArgs(
16711584
converter, llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op), args);
16721585
return llvm::to_vector(args.getSyms());
@@ -1989,7 +1902,7 @@ genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
19891902
taskArgs.priv.vars = clauseOps.privateVars;
19901903

19911904
auto genRegionEntryCB = [&](mlir::Operation *op) {
1992-
genEntryBlock(converter, taskArgs, op->getRegion(0));
1905+
genEntryBlock(converter.getFirOpBuilder(), taskArgs, op->getRegion(0));
19931906
bindEntryBlockArgs(converter,
19941907
llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op),
19951908
taskArgs);

flang/lib/Optimizer/OpenMP/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
22

33
add_flang_library(FlangOpenMPTransforms
44
FunctionFiltering.cpp
5+
GenericLoopConversion.cpp
56
MapsForPrivatizedSymbols.cpp
67
MapInfoFinalization.cpp
78
MarkDeclareTarget.cpp
@@ -25,4 +26,5 @@ add_flang_library(FlangOpenMPTransforms
2526
HLFIRDialect
2627
MLIRIR
2728
MLIRPass
29+
MLIRTransformUtils
2830
)

0 commit comments

Comments
 (0)