Skip to content

Commit 2aa218c

Browse files
authored
[flang][OpenMP] Diagnose invalid reduction modifiers (#92406)
Emit diagnostic messages for invalid modifiers in "reduction" clause. Fixes #92397
1 parent cf12830 commit 2aa218c

File tree

4 files changed

+150
-3
lines changed

4 files changed

+150
-3
lines changed

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2310,6 +2310,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
23102310
if (CheckReductionOperators(x)) {
23112311
CheckReductionTypeList(x);
23122312
}
2313+
CheckReductionModifier(x);
23132314
}
23142315

23152316
bool OmpStructureChecker::CheckReductionOperators(
@@ -2394,6 +2395,64 @@ void OmpStructureChecker::CheckReductionTypeList(
23942395
}
23952396
}
23962397

2398+
void OmpStructureChecker::CheckReductionModifier(
2399+
const parser::OmpClause::Reduction &x) {
2400+
using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
2401+
const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v.t)};
2402+
if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
2403+
// No modifier, or the default one is always ok.
2404+
return;
2405+
}
2406+
ReductionModifier modifier{*maybeModifier};
2407+
const DirectiveContext &dirCtx{GetContext()};
2408+
if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
2409+
// [5.2:257:33-34]
2410+
// If a reduction-modifier is specified in a reduction clause that
2411+
// appears on the directive, then the reduction modifier must be
2412+
// default.
2413+
context_.Say(GetContext().clauseSource,
2414+
"REDUCTION modifier on LOOP directive must be DEFAULT"_err_en_US);
2415+
}
2416+
if (modifier == ReductionModifier::Task) {
2417+
// "Task" is only allowed on worksharing or "parallel" directive.
2418+
static llvm::omp::Directive worksharing[]{
2419+
llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_scope,
2420+
llvm::omp::Directive::OMPD_sections,
2421+
// There are more worksharing directives, but they do not apply:
2422+
// "for" is C++ only,
2423+
// "single" and "workshare" don't allow reduction clause,
2424+
// "loop" has different restrictions (checked above).
2425+
};
2426+
if (dirCtx.directive != llvm::omp::Directive::OMPD_parallel &&
2427+
!llvm::is_contained(worksharing, dirCtx.directive)) {
2428+
context_.Say(GetContext().clauseSource,
2429+
"Modifier 'TASK' on REDUCTION clause is only allowed with "
2430+
"PARALLEL or worksharing directive"_err_en_US);
2431+
}
2432+
} else if (modifier == ReductionModifier::Inscan) {
2433+
// "Inscan" is only allowed on worksharing-loop, worksharing-loop simd,
2434+
// or "simd" directive.
2435+
// The worksharing-loop directives are OMPD_do and OMPD_for. Only the
2436+
// former is allowed in Fortran.
2437+
switch (dirCtx.directive) {
2438+
case llvm::omp::Directive::OMPD_do: // worksharing-loop
2439+
case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
2440+
case llvm::omp::Directive::OMPD_simd: // "simd"
2441+
break;
2442+
default:
2443+
context_.Say(GetContext().clauseSource,
2444+
"Modifier 'INSCAN' on REDUCTION clause is only allowed with "
2445+
"worksharing-loop, worksharing-loop simd, "
2446+
"or SIMD directive"_err_en_US);
2447+
}
2448+
} else {
2449+
// Catch-all for potential future modifiers to make sure that this
2450+
// function is up-to-date.
2451+
context_.Say(GetContext().clauseSource,
2452+
"Unexpected modifier on REDUCTION clause"_err_en_US);
2453+
}
2454+
}
2455+
23972456
void OmpStructureChecker::CheckIntentInPointerAndDefinable(
23982457
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
23992458
for (const auto &ompObject : objectList.v) {

flang/lib/Semantics/check-omp-structure.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ class OmpStructureChecker
205205
bool CheckIntrinsicOperator(
206206
const parser::DefinedOperator::IntrinsicOperator &);
207207
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
208+
void CheckReductionModifier(const parser::OmpClause::Reduction &);
208209
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
209210
void ChecksOnOrderedAsBlock();
210211
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);

flang/test/Lower/OpenMP/invalid-reduction-modifier.f90

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
!Remove the --crash below once we can diagnose the issue more gracefully.
2-
!REQUIRES: asserts
3-
!RUN: not --crash %flang_fc1 -fopenmp -emit-hlfir -o - %s
1+
!RUN: not %flang_fc1 -fopenmp -emit-hlfir -o - %s
42

53
! Check that we reject the "task" reduction modifier on the "simd" directive.
64

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52
2+
3+
subroutine mod_task1(x)
4+
integer, intent(inout) :: x
5+
6+
!Correct: "parallel" directive.
7+
!$omp parallel reduction(task, +:x)
8+
do i = 1, 100
9+
x = foo(i)
10+
enddo
11+
!$omp end parallel
12+
end
13+
14+
subroutine mod_task2(x)
15+
integer, intent(inout) :: x
16+
17+
!Correct: worksharing directive.
18+
!$omp sections reduction(task, +:x)
19+
do i = 1, 100
20+
x = foo(i)
21+
enddo
22+
!$omp end sections
23+
end
24+
25+
subroutine mod_task3(x)
26+
integer, intent(inout) :: x
27+
28+
!ERROR: Modifier 'TASK' on REDUCTION clause is only allowed with PARALLEL or worksharing directive
29+
!$omp simd reduction(task, +:x)
30+
do i = 1, 100
31+
x = foo(i)
32+
enddo
33+
!$omp end simd
34+
end
35+
36+
subroutine mod_inscan1(x)
37+
integer, intent(inout) :: x
38+
39+
!Correct: worksharing-loop directive
40+
!$omp do reduction(inscan, +:x)
41+
do i = 1, 100
42+
x = foo(i)
43+
enddo
44+
!$omp end do
45+
end
46+
47+
subroutine mod_inscan2(x)
48+
integer, intent(inout) :: x
49+
50+
!Correct: worksharing-loop simd directive
51+
!$omp do simd reduction(inscan, +:x)
52+
do i = 1, 100
53+
x = foo(i)
54+
enddo
55+
!$omp end do simd
56+
end
57+
58+
subroutine mod_inscan3(x)
59+
integer, intent(inout) :: x
60+
61+
!Correct: "simd" directive
62+
!$omp simd reduction(inscan, +:x)
63+
do i = 1, 100
64+
x = foo(i)
65+
enddo
66+
!$omp end simd
67+
end
68+
69+
subroutine mod_inscan4(x)
70+
integer, intent(inout) :: x
71+
72+
!ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
73+
!$omp parallel reduction(inscan, +:x)
74+
do i = 1, 100
75+
x = foo(i)
76+
enddo
77+
!$omp end parallel
78+
end
79+
80+
subroutine mod_inscan5(x)
81+
integer, intent(inout) :: x
82+
83+
!ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
84+
!$omp sections reduction(inscan, +:x)
85+
do i = 1, 100
86+
x = foo(i)
87+
enddo
88+
!$omp end sections
89+
end

0 commit comments

Comments
 (0)