Skip to content

[flang][OpenMP] Diagnose invalid reduction modifiers #92406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2309,6 +2309,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
if (CheckReductionOperators(x)) {
CheckReductionTypeList(x);
}
CheckReductionModifier(x);
}

bool OmpStructureChecker::CheckReductionOperators(
Expand Down Expand Up @@ -2393,6 +2394,64 @@ void OmpStructureChecker::CheckReductionTypeList(
}
}

void OmpStructureChecker::CheckReductionModifier(
const parser::OmpClause::Reduction &x) {
using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v.t)};
if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
// No modifier, or the default one is always ok.
return;
}
ReductionModifier modifier{*maybeModifier};
const DirectiveContext &dirCtx{GetContext()};
if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
// [5.2:257:33-34]
// If a reduction-modifier is specified in a reduction clause that
// appears on the directive, then the reduction modifier must be
// default.
context_.Say(GetContext().clauseSource,
"REDUCTION modifier on LOOP directive must be DEFAULT"_err_en_US);
}
if (modifier == ReductionModifier::Task) {
// "Task" is only allowed on worksharing or "parallel" directive.
static llvm::omp::Directive worksharing[]{
llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_scope,
llvm::omp::Directive::OMPD_sections,
// There are more worksharing directives, but they do not apply:
// "for" is C++ only,
// "single" and "workshare" don't allow reduction clause,
// "loop" has different restrictions (checked above).
};
if (dirCtx.directive != llvm::omp::Directive::OMPD_parallel &&
!llvm::is_contained(worksharing, dirCtx.directive)) {
context_.Say(GetContext().clauseSource,
"Modifier 'TASK' on REDUCTION clause is only allowed with "
"PARALLEL or worksharing directive"_err_en_US);
}
} else if (modifier == ReductionModifier::Inscan) {
// "Inscan" is only allowed on worksharing-loop, worksharing-loop simd,
// or "simd" directive.
// The worksharing-loop directives are OMPD_do and OMPD_for. Only the
// former is allowed in Fortran.
switch (dirCtx.directive) {
case llvm::omp::Directive::OMPD_do: // worksharing-loop
case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
case llvm::omp::Directive::OMPD_simd: // "simd"
break;
default:
context_.Say(GetContext().clauseSource,
"Modifier 'INSCAN' on REDUCTION clause is only allowed with "
"worksharing-loop, worksharing-loop simd, "
"or SIMD directive"_err_en_US);
}
} else {
// Catch-all for potential future modifiers to make sure that this
// function is up-to-date.
context_.Say(GetContext().clauseSource,
"Unexpected modifier on REDUCTION clause"_err_en_US);
}
}

void OmpStructureChecker::CheckIntentInPointerAndDefinable(
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
for (const auto &ompObject : objectList.v) {
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Semantics/check-omp-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ class OmpStructureChecker
bool CheckIntrinsicOperator(
const parser::DefinedOperator::IntrinsicOperator &);
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
void CheckReductionModifier(const parser::OmpClause::Reduction &);
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
void ChecksOnOrderedAsBlock();
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
Expand Down
4 changes: 1 addition & 3 deletions flang/test/Lower/OpenMP/invalid-reduction-modifier.f90
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
!Remove the --crash below once we can diagnose the issue more gracefully.
!REQUIRES: asserts
!RUN: not --crash %flang_fc1 -fopenmp -emit-hlfir -o - %s
!RUN: not %flang_fc1 -fopenmp -emit-hlfir -o - %s

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

Expand Down
89 changes: 89 additions & 0 deletions flang/test/Semantics/OpenMP/reduction-modifiers.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52

subroutine mod_task1(x)
integer, intent(inout) :: x

!Correct: "parallel" directive.
!$omp parallel reduction(task, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end parallel
end

subroutine mod_task2(x)
integer, intent(inout) :: x

!Correct: worksharing directive.
!$omp sections reduction(task, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end sections
end

subroutine mod_task3(x)
integer, intent(inout) :: x

!ERROR: Modifier 'TASK' on REDUCTION clause is only allowed with PARALLEL or worksharing directive
!$omp simd reduction(task, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end simd
end

subroutine mod_inscan1(x)
integer, intent(inout) :: x

!Correct: worksharing-loop directive
!$omp do reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end do
end

subroutine mod_inscan2(x)
integer, intent(inout) :: x

!Correct: worksharing-loop simd directive
!$omp do simd reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end do simd
end

subroutine mod_inscan3(x)
integer, intent(inout) :: x

!Correct: "simd" directive
!$omp simd reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end simd
end

subroutine mod_inscan4(x)
integer, intent(inout) :: x

!ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
!$omp parallel reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end parallel
end

subroutine mod_inscan5(x)
integer, intent(inout) :: x

!ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
!$omp sections reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
enddo
!$omp end sections
end
Loading