Skip to content

Commit 4c09ae0

Browse files
authored
[flang][OpenMP] Lowering for CANCEL and CANCELLATIONPOINT (#134248)
These will still hit TODOs in OpenMPToLLVMIRConversion.cpp
1 parent 446d4f5 commit 4c09ae0

File tree

7 files changed

+371
-5
lines changed

7 files changed

+371
-5
lines changed

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "flang/Lower/PFTBuilder.h"
1919
#include "flang/Parser/tools.h"
2020
#include "flang/Semantics/tools.h"
21+
#include "llvm/Frontend/OpenMP/OMP.h.inc"
2122
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
2223

2324
namespace Fortran {
@@ -220,6 +221,39 @@ bool ClauseProcessor::processBind(mlir::omp::BindClauseOps &result) const {
220221
return false;
221222
}
222223

224+
bool ClauseProcessor::processCancelDirectiveName(
225+
mlir::omp::CancelDirectiveNameClauseOps &result) const {
226+
using ConstructType = mlir::omp::ClauseCancellationConstructType;
227+
mlir::MLIRContext *context = &converter.getMLIRContext();
228+
229+
ConstructType directive;
230+
if (auto *clause = findUniqueClause<omp::CancellationConstructType>()) {
231+
switch (clause->v) {
232+
case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Parallel:
233+
directive = mlir::omp::ClauseCancellationConstructType::Parallel;
234+
break;
235+
case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Loop:
236+
directive = mlir::omp::ClauseCancellationConstructType::Loop;
237+
break;
238+
case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Sections:
239+
directive = mlir::omp::ClauseCancellationConstructType::Sections;
240+
break;
241+
case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Taskgroup:
242+
directive = mlir::omp::ClauseCancellationConstructType::Taskgroup;
243+
break;
244+
case llvm::omp::OMP_CANCELLATION_CONSTRUCT_None:
245+
llvm_unreachable("OMP_CANCELLATION_CONSTRUCT_None");
246+
break;
247+
}
248+
} else {
249+
llvm_unreachable("cancel construct missing cancellation construct type");
250+
}
251+
252+
result.cancelDirective =
253+
mlir::omp::ClauseCancellationConstructTypeAttr::get(context, directive);
254+
return true;
255+
}
256+
223257
bool ClauseProcessor::processCollapse(
224258
mlir::Location currentLocation, lower::pft::Evaluation &eval,
225259
mlir::omp::LoopRelatedClauseOps &result,

flang/lib/Lower/OpenMP/ClauseProcessor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class ClauseProcessor {
5656
// 'Unique' clauses: They can appear at most once in the clause list.
5757
bool processBare(mlir::omp::BareClauseOps &result) const;
5858
bool processBind(mlir::omp::BindClauseOps &result) const;
59+
bool processCancelDirectiveName(
60+
mlir::omp::CancelDirectiveNameClauseOps &result) const;
5961
bool
6062
processCollapse(mlir::Location currentLocation, lower::pft::Evaluation &eval,
6163
mlir::omp::LoopRelatedClauseOps &result,

flang/lib/Lower/OpenMP/Clauses.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ MAKE_EMPTY_CLASS(Weak, Weak);
249249
MAKE_EMPTY_CLASS(Write, Write);
250250

251251
// Artificial clauses
252-
MAKE_EMPTY_CLASS(CancellationConstructType, CancellationConstructType);
253252
MAKE_EMPTY_CLASS(Depobj, Depobj);
254253
MAKE_EMPTY_CLASS(Flush, Flush);
255254
MAKE_EMPTY_CLASS(MemoryOrder, MemoryOrder);
@@ -524,7 +523,23 @@ Bind make(const parser::OmpClause::Bind &inp,
524523
return Bind{/*Binding=*/convert(inp.v.v)};
525524
}
526525

527-
// CancellationConstructType: empty
526+
CancellationConstructType
527+
make(const parser::OmpClause::CancellationConstructType &inp,
528+
semantics::SemanticsContext &semaCtx) {
529+
auto name = std::get<parser::OmpDirectiveName>(inp.v.t);
530+
CLAUSET_ENUM_CONVERT(
531+
convert, llvm::omp::Directive, llvm::omp::CancellationConstructType,
532+
// clang-format off
533+
MS(OMPD_parallel, OMP_CANCELLATION_CONSTRUCT_Parallel)
534+
MS(OMPD_do, OMP_CANCELLATION_CONSTRUCT_Loop)
535+
MS(OMPD_sections, OMP_CANCELLATION_CONSTRUCT_Sections)
536+
MS(OMPD_taskgroup, OMP_CANCELLATION_CONSTRUCT_Taskgroup)
537+
// clang-format on
538+
);
539+
540+
return CancellationConstructType{convert(name.v)};
541+
}
542+
528543
// Capture: empty
529544

530545
Collapse make(const parser::OmpClause::Collapse &inp,

flang/lib/Lower/OpenMP/Clauses.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "llvm/ADT/STLExtras.h"
1919
#include "llvm/Frontend/OpenMP/ClauseT.h"
20+
#include "llvm/Frontend/OpenMP/OMP.h.inc"
2021

2122
#include <optional>
2223
#include <type_traits>
@@ -306,7 +307,8 @@ using Write = tomp::clause::WriteT<TypeTy, IdTy, ExprTy>;
306307
using tomp::type::operator==;
307308

308309
struct CancellationConstructType {
309-
using EmptyTrait = std::true_type;
310+
using WrapperTrait = std::true_type;
311+
llvm::omp::CancellationConstructType v;
310312
};
311313
struct Depobj {
312314
using EmptyTrait = std::true_type;

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,24 @@ static OpTy genWrapperOp(lower::AbstractConverter &converter,
15331533
// Code generation functions for clauses
15341534
//===----------------------------------------------------------------------===//
15351535

1536+
static void genCancelClauses(lower::AbstractConverter &converter,
1537+
semantics::SemanticsContext &semaCtx,
1538+
const List<Clause> &clauses, mlir::Location loc,
1539+
mlir::omp::CancelOperands &clauseOps) {
1540+
ClauseProcessor cp(converter, semaCtx, clauses);
1541+
cp.processCancelDirectiveName(clauseOps);
1542+
cp.processIf(llvm::omp::Directive::OMPD_cancel, clauseOps);
1543+
}
1544+
1545+
static void
1546+
genCancellationPointClauses(lower::AbstractConverter &converter,
1547+
semantics::SemanticsContext &semaCtx,
1548+
const List<Clause> &clauses, mlir::Location loc,
1549+
mlir::omp::CancellationPointOperands &clauseOps) {
1550+
ClauseProcessor cp(converter, semaCtx, clauses);
1551+
cp.processCancelDirectiveName(clauseOps);
1552+
}
1553+
15361554
static void genCriticalDeclareClauses(
15371555
lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
15381556
const List<Clause> &clauses, mlir::Location loc,
@@ -1849,6 +1867,31 @@ genBarrierOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
18491867
return converter.getFirOpBuilder().create<mlir::omp::BarrierOp>(loc);
18501868
}
18511869

1870+
static mlir::omp::CancelOp genCancelOp(lower::AbstractConverter &converter,
1871+
semantics::SemanticsContext &semaCtx,
1872+
lower::pft::Evaluation &eval,
1873+
mlir::Location loc,
1874+
const ConstructQueue &queue,
1875+
ConstructQueue::const_iterator item) {
1876+
mlir::omp::CancelOperands clauseOps;
1877+
genCancelClauses(converter, semaCtx, item->clauses, loc, clauseOps);
1878+
1879+
return converter.getFirOpBuilder().create<mlir::omp::CancelOp>(loc,
1880+
clauseOps);
1881+
}
1882+
1883+
static mlir::omp::CancellationPointOp genCancellationPointOp(
1884+
lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
1885+
lower::pft::Evaluation &eval, mlir::Location loc,
1886+
const ConstructQueue &queue, ConstructQueue::const_iterator item) {
1887+
mlir::omp::CancellationPointOperands clauseOps;
1888+
genCancellationPointClauses(converter, semaCtx, item->clauses, loc,
1889+
clauseOps);
1890+
1891+
return converter.getFirOpBuilder().create<mlir::omp::CancellationPointOp>(
1892+
loc, clauseOps);
1893+
}
1894+
18521895
static mlir::omp::CriticalOp
18531896
genCriticalOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
18541897
semantics::SemanticsContext &semaCtx,
@@ -3354,15 +3397,32 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
33543397
semantics::SemanticsContext &semaCtx,
33553398
lower::pft::Evaluation &eval,
33563399
const parser::OpenMPCancelConstruct &cancelConstruct) {
3357-
TODO(converter.getCurrentLocation(), "OpenMPCancelConstruct");
3400+
List<Clause> clauses = makeList(cancelConstruct.v.Clauses().v, [&](auto &&s) {
3401+
return makeClause(s, semaCtx);
3402+
});
3403+
mlir::Location loc = converter.genLocation(cancelConstruct.source);
3404+
3405+
ConstructQueue queue{buildConstructQueue(
3406+
converter.getFirOpBuilder().getModule(), semaCtx, eval,
3407+
cancelConstruct.source, llvm::omp::Directive::OMPD_cancel, clauses)};
3408+
genCancelOp(converter, semaCtx, eval, loc, queue, queue.begin());
33583409
}
33593410

33603411
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
33613412
semantics::SemanticsContext &semaCtx,
33623413
lower::pft::Evaluation &eval,
33633414
const parser::OpenMPCancellationPointConstruct
33643415
&cancellationPointConstruct) {
3365-
TODO(converter.getCurrentLocation(), "OpenMPCancelConstruct");
3416+
List<Clause> clauses =
3417+
makeList(cancellationPointConstruct.v.Clauses().v,
3418+
[&](auto &&s) { return makeClause(s, semaCtx); });
3419+
mlir::Location loc = converter.genLocation(cancellationPointConstruct.source);
3420+
3421+
ConstructQueue queue{
3422+
buildConstructQueue(converter.getFirOpBuilder().getModule(), semaCtx,
3423+
eval, cancellationPointConstruct.source,
3424+
llvm::omp::Directive::OMPD_cancel, clauses)};
3425+
genCancellationPointOp(converter, semaCtx, eval, loc, queue, queue.begin());
33663426
}
33673427

33683428
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,

flang/test/Lower/OpenMP/cancel.f90

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s
2+
! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s
3+
4+
subroutine cancel_parallel()
5+
!$omp parallel
6+
!$omp cancel parallel
7+
!$omp end parallel
8+
end subroutine
9+
! CHECK-LABEL: func.func @_QPcancel_parallel() {
10+
! CHECK: omp.parallel {
11+
! CHECK: omp.cancel cancellation_construct_type(parallel)
12+
! CHECK: omp.terminator
13+
! CHECK: }
14+
! CHECK: return
15+
! CHECK: }
16+
17+
subroutine cancel_do()
18+
!$omp parallel do
19+
do i = 1,100
20+
!$omp cancel do
21+
enddo
22+
!$omp end parallel do
23+
end subroutine
24+
! CHECK-LABEL: func.func @_QPcancel_do() {
25+
! CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFcancel_doEi"}
26+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFcancel_doEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
27+
! CHECK: omp.parallel {
28+
! CHECK: %[[VAL_2:.*]] = arith.constant 1 : i32
29+
! CHECK: %[[VAL_3:.*]] = arith.constant 100 : i32
30+
! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i32
31+
! CHECK: omp.wsloop private(@_QFcancel_doEi_private_i32 %[[VAL_1]]#0 -> %[[VAL_5:.*]] : !fir.ref<i32>) {
32+
! CHECK: omp.loop_nest (%[[VAL_6:.*]]) : i32 = (%[[VAL_2]]) to (%[[VAL_3]]) inclusive step (%[[VAL_4]]) {
33+
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFcancel_doEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
34+
! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_7]]#0 : i32, !fir.ref<i32>
35+
! CHECK: omp.cancel cancellation_construct_type(loop)
36+
! CHECK: omp.yield
37+
! CHECK: }
38+
! CHECK: }
39+
! CHECK: omp.terminator
40+
! CHECK: }
41+
! CHECK: return
42+
! CHECK: }
43+
44+
subroutine cancel_sections()
45+
!$omp sections
46+
!$omp section
47+
!$omp cancel sections
48+
!$omp end sections
49+
end subroutine
50+
! CHECK-LABEL: func.func @_QPcancel_sections() {
51+
! CHECK: omp.sections {
52+
! CHECK: omp.section {
53+
! CHECK: omp.cancel cancellation_construct_type(sections)
54+
! CHECK: omp.terminator
55+
! CHECK: }
56+
! CHECK: omp.terminator
57+
! CHECK: }
58+
! CHECK: return
59+
! CHECK: }
60+
61+
subroutine cancel_taskgroup()
62+
!$omp taskgroup
63+
!$omp task
64+
!$omp cancel taskgroup
65+
!$omp end task
66+
!$omp end taskgroup
67+
end subroutine
68+
! CHECK-LABEL: func.func @_QPcancel_taskgroup() {
69+
! CHECK: omp.taskgroup {
70+
! CHECK: omp.task {
71+
! CHECK: omp.cancel cancellation_construct_type(taskgroup)
72+
! CHECK: omp.terminator
73+
! CHECK: }
74+
! CHECK: omp.terminator
75+
! CHECK: }
76+
! CHECK: return
77+
! CHECK: }
78+
79+
subroutine cancel_parallel_if(cond)
80+
logical :: cond
81+
!$omp parallel
82+
!$omp cancel parallel if(cond)
83+
!$omp end parallel
84+
end subroutine
85+
! CHECK-LABEL: func.func @_QPcancel_parallel_if(
86+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
87+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
88+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFcancel_parallel_ifEcond"} : (!fir.ref<!fir.logical<4>>, !fir.dscope) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
89+
! CHECK: omp.parallel {
90+
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.logical<4>>
91+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.logical<4>) -> i1
92+
! CHECK: omp.cancel cancellation_construct_type(parallel) if(%[[VAL_4]])
93+
! CHECK: omp.terminator
94+
! CHECK: }
95+
! CHECK: return
96+
! CHECK: }
97+
98+
subroutine cancel_do_if(cond)
99+
logical :: cond
100+
!$omp parallel do
101+
do i = 1,100
102+
!$omp cancel do if (cond)
103+
enddo
104+
!$omp end parallel do
105+
end subroutine
106+
! CHECK-LABEL: func.func @_QPcancel_do_if(
107+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
108+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
109+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFcancel_do_ifEcond"} : (!fir.ref<!fir.logical<4>>, !fir.dscope) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
110+
! CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFcancel_do_ifEi"}
111+
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "_QFcancel_do_ifEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
112+
! CHECK: omp.parallel {
113+
! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32
114+
! CHECK: %[[VAL_6:.*]] = arith.constant 100 : i32
115+
! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32
116+
! CHECK: omp.wsloop private(@_QFcancel_do_ifEi_private_i32 %[[VAL_4]]#0 -> %[[VAL_8:.*]] : !fir.ref<i32>) {
117+
! CHECK: omp.loop_nest (%[[VAL_9:.*]]) : i32 = (%[[VAL_5]]) to (%[[VAL_6]]) inclusive step (%[[VAL_7]]) {
118+
! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFcancel_do_ifEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
119+
! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_10]]#0 : i32, !fir.ref<i32>
120+
! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.logical<4>>
121+
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.logical<4>) -> i1
122+
! CHECK: omp.cancel cancellation_construct_type(loop) if(%[[VAL_12]])
123+
! CHECK: omp.yield
124+
! CHECK: }
125+
! CHECK: }
126+
! CHECK: omp.terminator
127+
! CHECK: }
128+
! CHECK: return
129+
! CHECK: }
130+
131+
subroutine cancel_sections_if(cond)
132+
logical :: cond
133+
!$omp sections
134+
!$omp section
135+
!$omp cancel sections if(cond)
136+
!$omp end sections
137+
end subroutine
138+
! CHECK-LABEL: func.func @_QPcancel_sections_if(
139+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
140+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
141+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFcancel_sections_ifEcond"} : (!fir.ref<!fir.logical<4>>, !fir.dscope) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
142+
! CHECK: omp.sections {
143+
! CHECK: omp.section {
144+
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.logical<4>>
145+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.logical<4>) -> i1
146+
! CHECK: omp.cancel cancellation_construct_type(sections) if(%[[VAL_4]])
147+
! CHECK: omp.terminator
148+
! CHECK: }
149+
! CHECK: omp.terminator
150+
! CHECK: }
151+
! CHECK: return
152+
! CHECK: }
153+
154+
subroutine cancel_taskgroup_if(cond)
155+
logical :: cond
156+
!$omp taskgroup
157+
!$omp task
158+
!$omp cancel taskgroup if(cond)
159+
!$omp end task
160+
!$omp end taskgroup
161+
end subroutine
162+
! CHECK-LABEL: func.func @_QPcancel_taskgroup_if(
163+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
164+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
165+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFcancel_taskgroup_ifEcond"} : (!fir.ref<!fir.logical<4>>, !fir.dscope) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
166+
! CHECK: omp.taskgroup {
167+
! CHECK: omp.task {
168+
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.logical<4>>
169+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.logical<4>) -> i1
170+
! CHECK: omp.cancel cancellation_construct_type(taskgroup) if(%[[VAL_4]])
171+
! CHECK: omp.terminator
172+
! CHECK: }
173+
! CHECK: omp.terminator
174+
! CHECK: }
175+
! CHECK: return
176+
! CHECK: }

0 commit comments

Comments
 (0)