@@ -30,19 +30,37 @@ class GenericLoopConversionPattern
30
30
: public mlir::OpConversionPattern<mlir::omp::LoopOp> {
31
31
public:
32
32
enum class GenericLoopCombinedInfo {
33
- None ,
33
+ Standalone ,
34
34
TargetTeamsLoop,
35
35
TargetParallelLoop
36
36
};
37
37
38
38
using mlir::OpConversionPattern<mlir::omp::LoopOp>::OpConversionPattern;
39
39
40
+ explicit GenericLoopConversionPattern (mlir::MLIRContext *ctx)
41
+ : mlir::OpConversionPattern<mlir::omp::LoopOp>{ctx} {
42
+ this ->setHasBoundedRewriteRecursion (true );
43
+ }
44
+
40
45
mlir::LogicalResult
41
46
matchAndRewrite (mlir::omp::LoopOp loopOp, OpAdaptor adaptor,
42
47
mlir::ConversionPatternRewriter &rewriter) const override {
43
48
assert (mlir::succeeded (checkLoopConversionSupportStatus (loopOp)));
44
49
45
- rewriteToDistributeParallelDo (loopOp, rewriter);
50
+ GenericLoopCombinedInfo combinedInfo = findGenericLoopCombineInfo (loopOp);
51
+
52
+ switch (combinedInfo) {
53
+ case GenericLoopCombinedInfo::Standalone:
54
+ rewriteToSimdLoop (loopOp, rewriter);
55
+ break ;
56
+ case GenericLoopCombinedInfo::TargetParallelLoop:
57
+ assert (false );
58
+ break ;
59
+ case GenericLoopCombinedInfo::TargetTeamsLoop:
60
+ rewriteToDistributeParallelDo (loopOp, rewriter);
61
+ break ;
62
+ }
63
+
46
64
rewriter.eraseOp (loopOp);
47
65
return mlir::success ();
48
66
}
@@ -52,9 +70,8 @@ class GenericLoopConversionPattern
52
70
GenericLoopCombinedInfo combinedInfo = findGenericLoopCombineInfo (loopOp);
53
71
54
72
switch (combinedInfo) {
55
- case GenericLoopCombinedInfo::None:
56
- return loopOp.emitError (
57
- " not yet implemented: Standalone `omp loop` directive" );
73
+ case GenericLoopCombinedInfo::Standalone:
74
+ break ;
58
75
case GenericLoopCombinedInfo::TargetParallelLoop:
59
76
return loopOp.emitError (
60
77
" not yet implemented: Combined `omp target parallel loop` directive" );
@@ -86,7 +103,7 @@ class GenericLoopConversionPattern
86
103
static GenericLoopCombinedInfo
87
104
findGenericLoopCombineInfo (mlir::omp::LoopOp loopOp) {
88
105
mlir::Operation *parentOp = loopOp->getParentOp ();
89
- GenericLoopCombinedInfo result = GenericLoopCombinedInfo::None ;
106
+ GenericLoopCombinedInfo result = GenericLoopCombinedInfo::Standalone ;
90
107
91
108
if (auto teamsOp = mlir::dyn_cast_if_present<mlir::omp::TeamsOp>(parentOp))
92
109
if (mlir::isa_and_present<mlir::omp::TargetOp>(teamsOp->getParentOp ()))
@@ -100,6 +117,62 @@ class GenericLoopConversionPattern
100
117
return result;
101
118
}
102
119
120
+ // / Rewrites standalone `loop` directives to equivalent `simd` constructs.
121
+ // / The reasoning behind this decision is that according to the spec (version
122
+ // / 5.2, section 11.7.1):
123
+ // /
124
+ // / "If the bind clause is not specified on a construct for which it may be
125
+ // / specified and the construct is closely nested inside a teams or parallel
126
+ // / construct, the effect is as if binding is teams or parallel. If none of
127
+ // / those conditions hold, the binding region is not defined."
128
+ // /
129
+ // / which means that standalone `loop` directives have undefined binding
130
+ // / region. Moreover, the spec says (in the next paragraph):
131
+ // /
132
+ // / "The specified binding region determines the binding thread set.
133
+ // / Specifically, if the binding region is a teams region, then the binding
134
+ // / thread set is the set of initial threads that are executing that region
135
+ // / while if the binding region is a parallel region, then the binding thread
136
+ // / set is the team of threads that are executing that region. If the binding
137
+ // / region is not defined, then the binding thread set is the encountering
138
+ // / thread."
139
+ // /
140
+ // / which means that the binding thread set for a standalone `loop` directive
141
+ // / is only the encountering thread.
142
+ // /
143
+ // / Since the encountering thread is the binding thread (set) for a
144
+ // / standalone `loop` directive, the best we can do in such case is to "simd"
145
+ // / the directive.
146
+ void rewriteToSimdLoop (mlir::omp::LoopOp loopOp,
147
+ mlir::ConversionPatternRewriter &rewriter) const {
148
+ loopOp.emitWarning (" Detected standalone OpenMP `loop` directive, the "
149
+ " associated loop will be rewritten to `simd`." );
150
+ mlir::omp::SimdOperands simdClauseOps;
151
+ simdClauseOps.privateVars = loopOp.getPrivateVars ();
152
+
153
+ auto privateSyms = loopOp.getPrivateSyms ();
154
+ if (privateSyms)
155
+ simdClauseOps.privateSyms .assign (privateSyms->begin (),
156
+ privateSyms->end ());
157
+
158
+ Fortran::common::openmp::EntryBlockArgs simdArgs;
159
+ simdArgs.priv .vars = simdClauseOps.privateVars ;
160
+
161
+ auto simdOp =
162
+ rewriter.create <mlir::omp::SimdOp>(loopOp.getLoc (), simdClauseOps);
163
+ mlir::Block *simdBlock =
164
+ genEntryBlock (rewriter, simdArgs, simdOp.getRegion ());
165
+
166
+ mlir::IRMapping mapper;
167
+ mlir::Block &loopBlock = *loopOp.getRegion ().begin ();
168
+
169
+ for (auto [loopOpArg, simdopArg] :
170
+ llvm::zip_equal (loopBlock.getArguments (), simdBlock->getArguments ()))
171
+ mapper.map (loopOpArg, simdopArg);
172
+
173
+ rewriter.clone (*loopOp.begin (), mapper);
174
+ }
175
+
103
176
void rewriteToDistributeParallelDo (
104
177
mlir::omp::LoopOp loopOp,
105
178
mlir::ConversionPatternRewriter &rewriter) const {
0 commit comments