Skip to content

Commit 67a0bd2

Browse files
ergawygithub-actions[bot]
authored andcommitted
Automerge: [flang][OpenMP] Support bind clause code-gen for standalone loops (#122674)
Extends rewriting of `loop` directives by supporting `bind` clause for standalone directives. This follows both the spec and the current state of clang as follows: * No `bind` or `bind(thread)`: the `loop` is rewritten to `simd`. * `bind(parallel)`: the `loop` is rewritten to `do`. * `bind(teams)`: the `loop` is rewritten to `distribute`. This is a follow-up PR for llvm/llvm-project#122632, only the latest commit in this PR is relevant to the PR.
2 parents a017a64 + d7e561b commit 67a0bd2

File tree

2 files changed

+109
-19
lines changed

2 files changed

+109
-19
lines changed

flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class GenericLoopConversionPattern
5353

5454
switch (combinedInfo) {
5555
case GenericLoopCombinedInfo::Standalone:
56-
rewriteToSimdLoop(loopOp, rewriter);
56+
rewriteStandaloneLoop(loopOp, rewriter);
5757
break;
5858
case GenericLoopCombinedInfo::TargetParallelLoop:
5959
llvm_unreachable("not yet implemented: `parallel loop` direcitve");
@@ -87,7 +87,10 @@ class GenericLoopConversionPattern
8787
<< loopOp->getName() << " operation";
8888
};
8989

90-
if (loopOp.getBindKind())
90+
// For standalone directives, `bind` is already supported. Other combined
91+
// forms will be supported in a follow-up PR.
92+
if (combinedInfo != GenericLoopCombinedInfo::Standalone &&
93+
loopOp.getBindKind())
9194
return todo("bind");
9295

9396
if (loopOp.getOrder())
@@ -119,7 +122,27 @@ class GenericLoopConversionPattern
119122
return result;
120123
}
121124

122-
/// Rewrites standalone `loop` directives to equivalent `simd` constructs.
125+
void rewriteStandaloneLoop(mlir::omp::LoopOp loopOp,
126+
mlir::ConversionPatternRewriter &rewriter) const {
127+
using namespace mlir::omp;
128+
std::optional<ClauseBindKind> bindKind = loopOp.getBindKind();
129+
130+
if (!bindKind.has_value())
131+
return rewriteToSimdLoop(loopOp, rewriter);
132+
133+
switch (*loopOp.getBindKind()) {
134+
case ClauseBindKind::Parallel:
135+
return rewriteToWsloop(loopOp, rewriter);
136+
case ClauseBindKind::Teams:
137+
return rewriteToDistrbute(loopOp, rewriter);
138+
case ClauseBindKind::Thread:
139+
return rewriteToSimdLoop(loopOp, rewriter);
140+
}
141+
}
142+
143+
/// Rewrites standalone `loop` (without `bind` clause or with
144+
/// `bind(parallel)`) directives to equivalent `simd` constructs.
145+
///
123146
/// The reasoning behind this decision is that according to the spec (version
124147
/// 5.2, section 11.7.1):
125148
///
@@ -147,30 +170,57 @@ class GenericLoopConversionPattern
147170
/// the directive.
148171
void rewriteToSimdLoop(mlir::omp::LoopOp loopOp,
149172
mlir::ConversionPatternRewriter &rewriter) const {
150-
loopOp.emitWarning("Detected standalone OpenMP `loop` directive, the "
151-
"associated loop will be rewritten to `simd`.");
152-
mlir::omp::SimdOperands simdClauseOps;
153-
simdClauseOps.privateVars = loopOp.getPrivateVars();
173+
loopOp.emitWarning(
174+
"Detected standalone OpenMP `loop` directive with thread binding, "
175+
"the associated loop will be rewritten to `simd`.");
176+
rewriteToSingleWrapperOp<mlir::omp::SimdOp, mlir::omp::SimdOperands>(
177+
loopOp, rewriter);
178+
}
179+
180+
void rewriteToDistrbute(mlir::omp::LoopOp loopOp,
181+
mlir::ConversionPatternRewriter &rewriter) const {
182+
rewriteToSingleWrapperOp<mlir::omp::DistributeOp,
183+
mlir::omp::DistributeOperands>(loopOp, rewriter);
184+
}
185+
186+
void rewriteToWsloop(mlir::omp::LoopOp loopOp,
187+
mlir::ConversionPatternRewriter &rewriter) const {
188+
rewriteToSingleWrapperOp<mlir::omp::WsloopOp, mlir::omp::WsloopOperands>(
189+
loopOp, rewriter);
190+
}
191+
192+
// TODO Suggestion by Sergio: tag auto-generated operations for constructs
193+
// that weren't part of the original program, that would be useful
194+
// information for debugging purposes later on. This new attribute could be
195+
// used for `omp.loop`, but also for `do concurrent` transformations,
196+
// `workshare`, `workdistribute`, etc. The tag could be used for all kinds of
197+
// auto-generated operations using a dialect attribute (named something like
198+
// `omp.origin` or `omp.derived`) and perhaps hold the name of the operation
199+
// it was derived from, the reason it was transformed or something like that
200+
// we could use when emitting any messages related to it later on.
201+
template <typename OpTy, typename OpOperandsTy>
202+
void
203+
rewriteToSingleWrapperOp(mlir::omp::LoopOp loopOp,
204+
mlir::ConversionPatternRewriter &rewriter) const {
205+
OpOperandsTy clauseOps;
206+
clauseOps.privateVars = loopOp.getPrivateVars();
154207

155208
auto privateSyms = loopOp.getPrivateSyms();
156209
if (privateSyms)
157-
simdClauseOps.privateSyms.assign(privateSyms->begin(),
158-
privateSyms->end());
210+
clauseOps.privateSyms.assign(privateSyms->begin(), privateSyms->end());
159211

160-
Fortran::common::openmp::EntryBlockArgs simdArgs;
161-
simdArgs.priv.vars = simdClauseOps.privateVars;
212+
Fortran::common::openmp::EntryBlockArgs args;
213+
args.priv.vars = clauseOps.privateVars;
162214

163-
auto simdOp =
164-
rewriter.create<mlir::omp::SimdOp>(loopOp.getLoc(), simdClauseOps);
165-
mlir::Block *simdBlock =
166-
genEntryBlock(rewriter, simdArgs, simdOp.getRegion());
215+
auto wrapperOp = rewriter.create<OpTy>(loopOp.getLoc(), clauseOps);
216+
mlir::Block *opBlock = genEntryBlock(rewriter, args, wrapperOp.getRegion());
167217

168218
mlir::IRMapping mapper;
169219
mlir::Block &loopBlock = *loopOp.getRegion().begin();
170220

171-
for (auto [loopOpArg, simdopArg] :
172-
llvm::zip_equal(loopBlock.getArguments(), simdBlock->getArguments()))
173-
mapper.map(loopOpArg, simdopArg);
221+
for (auto [loopOpArg, opArg] :
222+
llvm::zip_equal(loopBlock.getArguments(), opBlock->getArguments()))
223+
mapper.map(loopOpArg, opArg);
174224

175225
rewriter.clone(*loopOp.begin(), mapper);
176226
}

flang/test/Lower/OpenMP/loop-directive.f90

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ subroutine test_reduction()
9292
! CHECK-LABEL: func.func @_QPtest_bind
9393
subroutine test_bind()
9494
integer :: i, dummy = 1
95-
! CHECK: omp.loop bind(thread) private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
95+
! CHECK: omp.simd private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
9696
! CHECK: }
9797
!$omp loop bind(thread)
9898
do i=1,10
@@ -139,3 +139,43 @@ subroutine test_nested_directives
139139
end do
140140
!$omp end target teams
141141
end subroutine
142+
143+
! CHECK-LABEL: func.func @_QPtest_standalone_bind_teams
144+
subroutine test_standalone_bind_teams
145+
implicit none
146+
integer, parameter :: N = 100000
147+
integer a(N), b(N), c(N)
148+
integer j,i, num, flag;
149+
num = N
150+
151+
! CHECK: omp.distribute
152+
! CHECK-SAME: private(@{{.*}}Ea_private_ref_100000xi32 {{[^,]*}},
153+
! CHECK-SAME: @{{.*}}Ei_private_ref_i32 {{.*}} : {{.*}}) {
154+
! CHECK: omp.loop_nest {{.*}} {
155+
! CHECK: }
156+
! CHECK: }
157+
!$omp loop bind(teams) private(a)
158+
do i=1,N
159+
c(i) = a(i) * b(i)
160+
end do
161+
end subroutine
162+
163+
! CHECK-LABEL: func.func @_QPtest_standalone_bind_parallel
164+
subroutine test_standalone_bind_parallel
165+
implicit none
166+
integer, parameter :: N = 100000
167+
integer a(N), b(N), c(N)
168+
integer j,i, num, flag;
169+
num = N
170+
171+
! CHECK: omp.wsloop
172+
! CHECK-SAME: private(@{{.*}}Ea_private_ref_100000xi32 {{[^,]*}},
173+
! CHECK-SAME: @{{.*}}Ei_private_ref_i32 {{.*}} : {{.*}}) {
174+
! CHECK: omp.loop_nest {{.*}} {
175+
! CHECK: }
176+
! CHECK: }
177+
!$omp loop bind(parallel) private(a)
178+
do i=1,N
179+
c(i) = a(i) * b(i)
180+
end do
181+
end subroutine

0 commit comments

Comments
 (0)