2020-02-25 23:11:52 +08:00
|
|
|
//===-- lib/Semantics/check-omp-structure.cpp -----------------------------===//
|
2019-06-26 07:18:51 +08:00
|
|
|
//
|
2019-12-21 04:52:07 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2019-06-26 07:18:51 +08:00
|
|
|
//
|
2020-01-11 04:12:03 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-06-26 07:18:51 +08:00
|
|
|
|
|
|
|
#include "check-omp-structure.h"
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Parser/parse-tree.h"
|
|
|
|
#include "flang/Semantics/tools.h"
|
2020-11-05 16:55:06 +08:00
|
|
|
#include <algorithm>
|
2019-06-26 07:18:51 +08:00
|
|
|
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
|
2020-10-29 02:13:49 +08:00
|
|
|
// Use when clause falls under 'struct OmpClause' in 'parse-tree.h'.
|
|
|
|
#define CHECK_SIMPLE_CLAUSE(X, Y) \
|
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::X &) { \
|
|
|
|
CheckAllowed(llvm::omp::Clause::Y); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(X, Y) \
|
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::X &c) { \
|
|
|
|
CheckAllowed(llvm::omp::Clause::Y); \
|
|
|
|
RequiresConstantPositiveParameter(llvm::omp::Clause::Y, c.v); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CHECK_REQ_SCALAR_INT_CLAUSE(X, Y) \
|
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::X &c) { \
|
|
|
|
CheckAllowed(llvm::omp::Clause::Y); \
|
|
|
|
RequiresPositiveParameter(llvm::omp::Clause::Y, c.v); \
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use when clause don't falls under 'struct OmpClause' in 'parse-tree.h'.
|
|
|
|
#define CHECK_SIMPLE_PARSER_CLAUSE(X, Y) \
|
|
|
|
void OmpStructureChecker::Enter(const parser::X &) { \
|
|
|
|
CheckAllowed(llvm::omp::Y); \
|
|
|
|
}
|
|
|
|
|
2021-01-19 20:58:44 +08:00
|
|
|
// 'OmpWorkshareBlockChecker' is used to check the validity of the assignment
|
|
|
|
// statements and the expressions enclosed in an OpenMP Workshare construct
|
|
|
|
class OmpWorkshareBlockChecker {
|
|
|
|
public:
|
|
|
|
OmpWorkshareBlockChecker(SemanticsContext &context, parser::CharBlock source)
|
|
|
|
: context_{context}, source_{source} {}
|
|
|
|
|
|
|
|
template <typename T> bool Pre(const T &) { return true; }
|
|
|
|
template <typename T> void Post(const T &) {}
|
|
|
|
|
|
|
|
bool Pre(const parser::AssignmentStmt &assignment) {
|
|
|
|
const auto &var{std::get<parser::Variable>(assignment.t)};
|
|
|
|
const auto &expr{std::get<parser::Expr>(assignment.t)};
|
|
|
|
const auto *lhs{GetExpr(var)};
|
|
|
|
const auto *rhs{GetExpr(expr)};
|
|
|
|
Tristate isDefined{semantics::IsDefinedAssignment(
|
|
|
|
lhs->GetType(), lhs->Rank(), rhs->GetType(), rhs->Rank())};
|
|
|
|
if (isDefined == Tristate::Yes) {
|
|
|
|
context_.Say(expr.source,
|
|
|
|
"Defined assignment statement is not "
|
|
|
|
"allowed in a WORKSHARE construct"_err_en_US);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Pre(const parser::Expr &expr) {
|
|
|
|
if (const auto *e{GetExpr(expr)}) {
|
|
|
|
for (const Symbol &symbol : evaluate::CollectSymbols(*e)) {
|
|
|
|
const Symbol &root{GetAssociationRoot(symbol)};
|
|
|
|
if (IsFunction(root) &&
|
|
|
|
!(root.attrs().test(Attr::ELEMENTAL) ||
|
|
|
|
root.attrs().test(Attr::INTRINSIC))) {
|
|
|
|
context_.Say(expr.source,
|
|
|
|
"User defined non-ELEMENTAL function "
|
|
|
|
"'%s' is not allowed in a WORKSHARE construct"_err_en_US,
|
|
|
|
root.name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SemanticsContext &context_;
|
|
|
|
parser::CharBlock source_;
|
|
|
|
};
|
|
|
|
|
2021-02-15 20:54:27 +08:00
|
|
|
class OmpCycleChecker {
|
|
|
|
public:
|
|
|
|
OmpCycleChecker(SemanticsContext &context, std::int64_t cycleLevel)
|
|
|
|
: context_{context}, cycleLevel_{cycleLevel} {}
|
|
|
|
|
|
|
|
template <typename T> bool Pre(const T &) { return true; }
|
|
|
|
template <typename T> void Post(const T &) {}
|
|
|
|
|
|
|
|
bool Pre(const parser::DoConstruct &dc) {
|
|
|
|
cycleLevel_--;
|
|
|
|
const auto &labelName{std::get<0>(std::get<0>(dc.t).statement.t)};
|
|
|
|
if (labelName) {
|
|
|
|
labelNamesandLevels_.emplace(labelName.value().ToString(), cycleLevel_);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Pre(const parser::CycleStmt &cyclestmt) {
|
|
|
|
std::map<std::string, std::int64_t>::iterator it;
|
|
|
|
bool err{false};
|
|
|
|
if (cyclestmt.v) {
|
|
|
|
it = labelNamesandLevels_.find(cyclestmt.v->source.ToString());
|
|
|
|
err = (it != labelNamesandLevels_.end() && it->second > 0);
|
|
|
|
}
|
|
|
|
if (cycleLevel_ > 0 || err) {
|
|
|
|
context_.Say(*cycleSource_,
|
|
|
|
"CYCLE statement to non-innermost associated loop of an OpenMP DO construct"_err_en_US);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Pre(const parser::Statement<parser::ActionStmt> &actionstmt) {
|
|
|
|
cycleSource_ = &actionstmt.source;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SemanticsContext &context_;
|
|
|
|
const parser::CharBlock *cycleSource_;
|
|
|
|
std::int64_t cycleLevel_;
|
|
|
|
std::map<std::string, std::int64_t> labelNamesandLevels_;
|
|
|
|
};
|
|
|
|
|
2021-04-09 02:33:04 +08:00
|
|
|
bool OmpStructureChecker::IsCloselyNestedRegion(const OmpDirectiveSet &set) {
|
|
|
|
// Definition of close nesting:
|
|
|
|
//
|
|
|
|
// `A region nested inside another region with no parallel region nested
|
|
|
|
// between them`
|
|
|
|
//
|
|
|
|
// Examples:
|
|
|
|
// non-parallel construct 1
|
|
|
|
// non-parallel construct 2
|
|
|
|
// parallel construct
|
|
|
|
// construct 3
|
|
|
|
// In the above example, construct 3 is NOT closely nested inside construct 1
|
|
|
|
// or 2
|
|
|
|
//
|
|
|
|
// non-parallel construct 1
|
|
|
|
// non-parallel construct 2
|
|
|
|
// construct 3
|
|
|
|
// In the above example, construct 3 is closely nested inside BOTH construct 1
|
|
|
|
// and 2
|
|
|
|
//
|
|
|
|
// Algorithm:
|
|
|
|
// Starting from the parent context, Check in a bottom-up fashion, each level
|
|
|
|
// of the context stack. If we have a match for one of the (supplied)
|
|
|
|
// violating directives, `close nesting` is satisfied. If no match is there in
|
|
|
|
// the entire stack, `close nesting` is not satisfied. If at any level, a
|
|
|
|
// `parallel` region is found, `close nesting` is not satisfied.
|
|
|
|
|
|
|
|
if (CurrentDirectiveIsNested()) {
|
|
|
|
int index = dirContext_.size() - 2;
|
|
|
|
while (index != -1) {
|
|
|
|
if (set.test(dirContext_[index].directive)) {
|
|
|
|
return true;
|
|
|
|
} else if (llvm::omp::parallelSet.test(dirContext_[index].directive)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
index--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-26 07:18:51 +08:00
|
|
|
bool OmpStructureChecker::HasInvalidWorksharingNesting(
|
|
|
|
const parser::CharBlock &source, const OmpDirectiveSet &set) {
|
|
|
|
// set contains all the invalid closely nested directives
|
|
|
|
// for the given directive (`source` here)
|
2021-04-09 02:33:04 +08:00
|
|
|
if (IsCloselyNestedRegion(set)) {
|
2019-06-26 07:18:51 +08:00
|
|
|
context_.Say(source,
|
|
|
|
"A worksharing region may not be closely nested inside a "
|
|
|
|
"worksharing, explicit task, taskloop, critical, ordered, atomic, or "
|
2019-09-14 04:57:35 +08:00
|
|
|
"master region"_err_en_US);
|
2019-06-26 07:18:51 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-29 20:29:58 +08:00
|
|
|
void OmpStructureChecker::HasInvalidDistributeNesting(
|
|
|
|
const parser::OpenMPLoopConstruct &x) {
|
|
|
|
bool violation{false};
|
|
|
|
|
|
|
|
OmpDirectiveSet distributeSet{llvm::omp::Directive::OMPD_distribute,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_do,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_do_simd,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_for,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_for_simd,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_simd};
|
|
|
|
|
|
|
|
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
|
|
|
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
|
|
|
if (distributeSet.test(beginDir.v)) {
|
|
|
|
// `distribute` region has to be nested
|
|
|
|
if (!CurrentDirectiveIsNested()) {
|
|
|
|
violation = true;
|
|
|
|
} else {
|
|
|
|
// `distribute` region has to be strictly nested inside `teams`
|
|
|
|
if (!llvm::omp::teamSet.test(GetContextParent().directive)) {
|
|
|
|
violation = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (violation) {
|
|
|
|
context_.Say(beginDir.source,
|
|
|
|
"`DISTRIBUTE` region has to be strictly nested inside `TEAMS` region."_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::HasInvalidTeamsNesting(
|
|
|
|
const llvm::omp::Directive &dir, const parser::CharBlock &source) {
|
|
|
|
OmpDirectiveSet allowedSet{llvm::omp::Directive::OMPD_parallel,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_do,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_do_simd,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_for,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_for_simd,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_master,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_master_taskloop,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_master_taskloop_simd,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_sections,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_workshare,
|
|
|
|
llvm::omp::Directive::OMPD_distribute,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_do,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_do_simd,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_for,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_parallel_for_simd,
|
|
|
|
llvm::omp::Directive::OMPD_distribute_simd};
|
|
|
|
|
|
|
|
if (!allowedSet.test(dir)) {
|
|
|
|
context_.Say(source,
|
|
|
|
"Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region."_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
|
2021-05-07 02:00:34 +08:00
|
|
|
// Simd Construct with Ordered Construct Nesting check
|
|
|
|
// We cannot use CurrentDirectiveIsNested() here because
|
|
|
|
// PushContextAndClauseSets() has not been called yet, it is
|
|
|
|
// called individually for each construct. Therefore a
|
|
|
|
// dirContext_ size `1` means the current construct is nested
|
|
|
|
if (dirContext_.size() >= 1) {
|
|
|
|
if (GetSIMDNest() > 0) {
|
|
|
|
CheckSIMDNest(x);
|
|
|
|
}
|
|
|
|
}
|
2019-07-10 05:08:50 +08:00
|
|
|
}
|
|
|
|
|
2019-06-26 07:18:51 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
|
[flang] [OpenMP] parse tree changes for `OpenMPLoopConstruct` (flang-compiler/f18#656)
1. Following Block and Sections constructs, re-structure loop related
constructs into `{Begin, Loop, End}`. Being part of the work in
PR flang-compiler/f18#599, the `Loop` and `End` nodes are optional during parser. They
should be filled in during the phase of `CanonicalizationOfOmp`. This
commit is solely for the parse tree change. So, after this commit,
PR flang-compiler/f18#599 needs to be changed accordingly.
2. Removed parse tree nodes for `END DO` and `END DO SIMD`. Similar to
Block and Sections constructs, `End` node now accepts clauses too,
the validity checks are deferred into Semantics. This is more genernal
and error message could be better.
3. With this commit alone, assertion error would occur when `End` directive
is present, for example `!$OMP END DO` because the `End` node is not
moved into `OpenMPLoopConstruct` yet. Again, PR flang-compiler/f18#599 will handle that.
More tests will be added in PR flang-compiler/f18#599 and during the future Semantics work.
Original-commit: flang-compiler/f18@8cd1932fd61fa67f8ad5abfd337cf7a223ea89f4
Reviewed-on: https://github.com/flang-compiler/f18/pull/656
2019-08-15 06:16:27 +08:00
|
|
|
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
|
|
|
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
2019-08-28 04:30:38 +08:00
|
|
|
|
|
|
|
// check matching, End directive is optional
|
|
|
|
if (const auto &endLoopDir{
|
|
|
|
std::get<std::optional<parser::OmpEndLoopDirective>>(x.t)}) {
|
2020-08-06 02:20:26 +08:00
|
|
|
const auto &endDir{
|
|
|
|
std::get<parser::OmpLoopDirective>(endLoopDir.value().t)};
|
|
|
|
|
|
|
|
CheckMatching<parser::OmpLoopDirective>(beginDir, endDir);
|
2019-08-28 04:30:38 +08:00
|
|
|
}
|
|
|
|
|
2021-03-13 22:27:53 +08:00
|
|
|
PushContextAndClauseSets(beginDir.source, beginDir.v);
|
2021-05-07 02:00:34 +08:00
|
|
|
if (llvm::omp::simdSet.test(GetContext().directive)) {
|
|
|
|
EnterSIMDNest();
|
|
|
|
}
|
2021-03-13 22:27:53 +08:00
|
|
|
|
|
|
|
if (beginDir.v == llvm::omp::Directive::OMPD_do) {
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
// 2.7.1 do-clause -> private-clause |
|
|
|
|
// firstprivate-clause |
|
|
|
|
// lastprivate-clause |
|
|
|
|
// linear-clause |
|
|
|
|
// reduction-clause |
|
|
|
|
// schedule-clause |
|
|
|
|
// collapse-clause |
|
|
|
|
// ordered-clause
|
|
|
|
|
[flang] [OpenMP] parse tree changes for `OpenMPBlockConstruct` (flang-compiler/f18#632)
* [OpenMP] parse tree changes for `OpenMPBlockConstruct`
1. merge `Workshare` and `Single` into `OpenMPBlockConstruct` because
they both accept structured-block and syntax is similar to other block
directives.
2. `OpenMPBlockConstruct` changes to structure like `{Begin, Block, End}`,
where `Begin` and `End` are tuple of `{Directive, ClauseList}`.
3. Updated the check-omp-structure.* for necessary parts. Added all the END
directive enumeration types that may have clauses.
More tests will be added during Semantics.
* [OpenMP] Update on Tim's suggestion
1. Fix unspecified enumeration for `OmpDirective` in the `OmpContext`.
This is through getting rid of `PushContext(source)` function to
make sure whenever it is about to push a NEW context, directive
source location and enumeration are available. To do that, I moved
around all the switches for directive into high level `Construct`'s
`Enter` node. Besides fixing the issue, the side benefit is that
whenever we call `GetContext().directive`, we are sure that the
`directive` here was set already.
2. When `Enter` the `OmpEndBlockDirective` node, partial context
information, such as directive source location or legal clause lists,
needs to be reset. The new directive source location should be
`OmpEndBlockDirective`'s `source`. The enumeration `directive`
should not be reset for the END directives that do not accept
clauses because nothing needs to be checked (for example any clause
that is on `END PARALLEL` is illegal).
Original-commit: flang-compiler/f18@e5bd6b7ba0fbe9006f3e431260428b194f2d2616
Reviewed-on: https://github.com/flang-compiler/f18/pull/632
2019-08-10 06:11:20 +08:00
|
|
|
// nesting check
|
2021-04-30 04:12:28 +08:00
|
|
|
HasInvalidWorksharingNesting(
|
|
|
|
beginDir.source, llvm::omp::nestedWorkshareErrSet);
|
[flang] [OpenMP] parse tree changes for `OpenMPBlockConstruct` (flang-compiler/f18#632)
* [OpenMP] parse tree changes for `OpenMPBlockConstruct`
1. merge `Workshare` and `Single` into `OpenMPBlockConstruct` because
they both accept structured-block and syntax is similar to other block
directives.
2. `OpenMPBlockConstruct` changes to structure like `{Begin, Block, End}`,
where `Begin` and `End` are tuple of `{Directive, ClauseList}`.
3. Updated the check-omp-structure.* for necessary parts. Added all the END
directive enumeration types that may have clauses.
More tests will be added during Semantics.
* [OpenMP] Update on Tim's suggestion
1. Fix unspecified enumeration for `OmpDirective` in the `OmpContext`.
This is through getting rid of `PushContext(source)` function to
make sure whenever it is about to push a NEW context, directive
source location and enumeration are available. To do that, I moved
around all the switches for directive into high level `Construct`'s
`Enter` node. Besides fixing the issue, the side benefit is that
whenever we call `GetContext().directive`, we are sure that the
`directive` here was set already.
2. When `Enter` the `OmpEndBlockDirective` node, partial context
information, such as directive source location or legal clause lists,
needs to be reset. The new directive source location should be
`OmpEndBlockDirective`'s `source`. The enumeration `directive`
should not be reset for the END directives that do not accept
clauses because nothing needs to be checked (for example any clause
that is on `END PARALLEL` is illegal).
Original-commit: flang-compiler/f18@e5bd6b7ba0fbe9006f3e431260428b194f2d2616
Reviewed-on: https://github.com/flang-compiler/f18/pull/632
2019-08-10 06:11:20 +08:00
|
|
|
}
|
2021-01-15 13:42:49 +08:00
|
|
|
SetLoopInfo(x);
|
2021-02-03 18:18:30 +08:00
|
|
|
|
|
|
|
if (const auto &doConstruct{
|
|
|
|
std::get<std::optional<parser::DoConstruct>>(x.t)}) {
|
|
|
|
const auto &doBlock{std::get<parser::Block>(doConstruct->t)};
|
|
|
|
CheckNoBranching(doBlock, beginDir.v, beginDir.source);
|
|
|
|
}
|
2021-02-15 20:54:27 +08:00
|
|
|
CheckDoWhile(x);
|
|
|
|
CheckLoopItrVariableIsInt(x);
|
|
|
|
CheckCycleConstraints(x);
|
2021-04-29 20:29:58 +08:00
|
|
|
HasInvalidDistributeNesting(x);
|
|
|
|
if (CurrentDirectiveIsNested() &&
|
|
|
|
llvm::omp::teamSet.test(GetContextParent().directive)) {
|
|
|
|
HasInvalidTeamsNesting(beginDir.v, beginDir.source);
|
|
|
|
}
|
2021-01-15 13:42:49 +08:00
|
|
|
}
|
|
|
|
const parser::Name OmpStructureChecker::GetLoopIndex(
|
|
|
|
const parser::DoConstruct *x) {
|
|
|
|
using Bounds = parser::LoopControl::Bounds;
|
|
|
|
return std::get<Bounds>(x->GetLoopControl()->u).name.thing;
|
|
|
|
}
|
|
|
|
void OmpStructureChecker::SetLoopInfo(const parser::OpenMPLoopConstruct &x) {
|
|
|
|
if (const auto &loopConstruct{
|
|
|
|
std::get<std::optional<parser::DoConstruct>>(x.t)}) {
|
|
|
|
const parser::DoConstruct *loop{&*loopConstruct};
|
|
|
|
if (loop && loop->IsDoNormal()) {
|
|
|
|
const parser::Name &itrVal{GetLoopIndex(loop)};
|
|
|
|
SetLoopIv(itrVal.symbol);
|
|
|
|
}
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
2021-02-15 20:54:27 +08:00
|
|
|
void OmpStructureChecker::CheckDoWhile(const parser::OpenMPLoopConstruct &x) {
|
|
|
|
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
|
|
|
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
|
|
|
if (beginDir.v == llvm::omp::Directive::OMPD_do) {
|
|
|
|
if (const auto &doConstruct{
|
|
|
|
std::get<std::optional<parser::DoConstruct>>(x.t)}) {
|
|
|
|
if (doConstruct.value().IsDoWhile()) {
|
|
|
|
const auto &doStmt{std::get<parser::Statement<parser::NonLabelDoStmt>>(
|
|
|
|
doConstruct.value().t)};
|
|
|
|
context_.Say(doStmt.source,
|
|
|
|
"The DO loop cannot be a DO WHILE with DO directive."_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckLoopItrVariableIsInt(
|
|
|
|
const parser::OpenMPLoopConstruct &x) {
|
|
|
|
if (const auto &loopConstruct{
|
|
|
|
std::get<std::optional<parser::DoConstruct>>(x.t)}) {
|
|
|
|
|
|
|
|
for (const parser::DoConstruct *loop{&*loopConstruct}; loop;) {
|
|
|
|
if (loop->IsDoNormal()) {
|
|
|
|
const parser::Name &itrVal{GetLoopIndex(loop)};
|
|
|
|
if (itrVal.symbol) {
|
|
|
|
const auto *type{itrVal.symbol->GetType()};
|
|
|
|
if (!type->IsNumeric(TypeCategory::Integer)) {
|
|
|
|
context_.Say(itrVal.source,
|
|
|
|
"The DO loop iteration"
|
|
|
|
" variable must be of the type integer."_err_en_US,
|
|
|
|
itrVal.ToString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Get the next DoConstruct if block is not empty.
|
|
|
|
const auto &block{std::get<parser::Block>(loop->t)};
|
|
|
|
const auto it{block.begin()};
|
|
|
|
loop = it != block.end() ? parser::Unwrap<parser::DoConstruct>(*it)
|
|
|
|
: nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-07 02:00:34 +08:00
|
|
|
void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
|
|
|
|
// Check the following:
|
|
|
|
// The only OpenMP constructs that can be encountered during execution of
|
|
|
|
// a simd region are the `atomic` construct, the `loop` construct, the `simd`
|
|
|
|
// construct and the `ordered` construct with the `simd` clause.
|
|
|
|
// TODO: Expand the check to include `LOOP` construct as well when it is
|
|
|
|
// supported.
|
|
|
|
|
|
|
|
// Check if the parent context has the SIMD clause
|
|
|
|
// Please note that we use GetContext() instead of GetContextParent()
|
|
|
|
// because PushContextAndClauseSets() has not been called on the
|
|
|
|
// current context yet.
|
|
|
|
// TODO: Check for declare simd regions.
|
|
|
|
bool eligibleSIMD{false};
|
|
|
|
std::visit(Fortran::common::visitors{
|
|
|
|
// Allow `!$OMP ORDERED SIMD`
|
|
|
|
[&](const parser::OpenMPBlockConstruct &c) {
|
|
|
|
const auto &beginBlockDir{
|
|
|
|
std::get<parser::OmpBeginBlockDirective>(c.t)};
|
|
|
|
const auto &beginDir{
|
|
|
|
std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
|
|
|
|
if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
|
|
|
|
const auto &clauses{
|
|
|
|
std::get<parser::OmpClauseList>(beginBlockDir.t)};
|
|
|
|
for (const auto &clause : clauses.v) {
|
|
|
|
if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
|
|
|
|
eligibleSIMD = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[&](const parser::OpenMPSimpleStandaloneConstruct &c) {
|
|
|
|
const auto &dir{
|
|
|
|
std::get<parser::OmpSimpleStandaloneDirective>(c.t)};
|
|
|
|
if (dir.v == llvm::omp::Directive::OMPD_ordered) {
|
|
|
|
const auto &clauses{std::get<parser::OmpClauseList>(c.t)};
|
|
|
|
for (const auto &clause : clauses.v) {
|
|
|
|
if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
|
|
|
|
eligibleSIMD = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// Allowing SIMD construct
|
|
|
|
[&](const parser::OpenMPLoopConstruct &c) {
|
|
|
|
const auto &beginLoopDir{
|
|
|
|
std::get<parser::OmpBeginLoopDirective>(c.t)};
|
|
|
|
const auto &beginDir{
|
|
|
|
std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
|
|
|
if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
|
|
|
|
(beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
|
|
|
|
eligibleSIMD = true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[&](const parser::OpenMPAtomicConstruct &c) {
|
|
|
|
// Allow `!$OMP ATOMIC`
|
|
|
|
eligibleSIMD = true;
|
|
|
|
},
|
|
|
|
[&](const auto &c) {},
|
|
|
|
},
|
|
|
|
c.u);
|
|
|
|
if (!eligibleSIMD) {
|
|
|
|
context_.Say(parser::FindSourceLocation(c),
|
|
|
|
"The only OpenMP constructs that can be encountered during execution "
|
|
|
|
"of a 'SIMD'"
|
|
|
|
" region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD`"
|
|
|
|
" construct and the `ORDERED` construct with the `SIMD` clause."_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 20:54:27 +08:00
|
|
|
std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
|
|
|
|
const parser::OpenMPLoopConstruct &x) {
|
|
|
|
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
|
|
|
const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
|
|
|
|
std::int64_t orderedCollapseLevel{1};
|
|
|
|
std::int64_t orderedLevel{0};
|
|
|
|
std::int64_t collapseLevel{0};
|
|
|
|
|
|
|
|
for (const auto &clause : clauseList.v) {
|
|
|
|
if (const auto *collapseClause{
|
|
|
|
std::get_if<parser::OmpClause::Collapse>(&clause.u)}) {
|
|
|
|
if (const auto v{GetIntValue(collapseClause->v)}) {
|
|
|
|
collapseLevel = *v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (const auto *orderedClause{
|
|
|
|
std::get_if<parser::OmpClause::Ordered>(&clause.u)}) {
|
|
|
|
if (const auto v{GetIntValue(orderedClause->v)}) {
|
|
|
|
orderedLevel = *v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (orderedLevel >= collapseLevel) {
|
|
|
|
orderedCollapseLevel = orderedLevel;
|
|
|
|
} else {
|
|
|
|
orderedCollapseLevel = collapseLevel;
|
|
|
|
}
|
|
|
|
return orderedCollapseLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckCycleConstraints(
|
|
|
|
const parser::OpenMPLoopConstruct &x) {
|
|
|
|
std::int64_t ordCollapseLevel{GetOrdCollapseLevel(x)};
|
|
|
|
OmpCycleChecker ompCycleChecker{context_, ordCollapseLevel};
|
|
|
|
parser::Walk(x, ompCycleChecker);
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) {
|
2021-05-07 02:00:34 +08:00
|
|
|
if (llvm::omp::simdSet.test(GetContext().directive)) {
|
|
|
|
ExitSIMDNest();
|
|
|
|
}
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
|
|
|
|
[flang] [OpenMP] parse tree changes for `OpenMPLoopConstruct` (flang-compiler/f18#656)
1. Following Block and Sections constructs, re-structure loop related
constructs into `{Begin, Loop, End}`. Being part of the work in
PR flang-compiler/f18#599, the `Loop` and `End` nodes are optional during parser. They
should be filled in during the phase of `CanonicalizationOfOmp`. This
commit is solely for the parse tree change. So, after this commit,
PR flang-compiler/f18#599 needs to be changed accordingly.
2. Removed parse tree nodes for `END DO` and `END DO SIMD`. Similar to
Block and Sections constructs, `End` node now accepts clauses too,
the validity checks are deferred into Semantics. This is more genernal
and error message could be better.
3. With this commit alone, assertion error would occur when `End` directive
is present, for example `!$OMP END DO` because the `End` node is not
moved into `OpenMPLoopConstruct` yet. Again, PR flang-compiler/f18#599 will handle that.
More tests will be added in PR flang-compiler/f18#599 and during the future Semantics work.
Original-commit: flang-compiler/f18@8cd1932fd61fa67f8ad5abfd337cf7a223ea89f4
Reviewed-on: https://github.com/flang-compiler/f18/pull/656
2019-08-15 06:16:27 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpEndLoopDirective &x) {
|
|
|
|
const auto &dir{std::get<parser::OmpLoopDirective>(x.t)};
|
|
|
|
ResetPartialContext(dir.source);
|
|
|
|
switch (dir.v) {
|
|
|
|
// 2.7.1 end-do -> END DO [nowait-clause]
|
|
|
|
// 2.8.3 end-do-simd -> END DO SIMD [nowait-clause]
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
case llvm::omp::Directive::OMPD_do:
|
|
|
|
case llvm::omp::Directive::OMPD_do_simd:
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
SetClauseSets(dir.v);
|
[flang] [OpenMP] parse tree changes for `OpenMPLoopConstruct` (flang-compiler/f18#656)
1. Following Block and Sections constructs, re-structure loop related
constructs into `{Begin, Loop, End}`. Being part of the work in
PR flang-compiler/f18#599, the `Loop` and `End` nodes are optional during parser. They
should be filled in during the phase of `CanonicalizationOfOmp`. This
commit is solely for the parse tree change. So, after this commit,
PR flang-compiler/f18#599 needs to be changed accordingly.
2. Removed parse tree nodes for `END DO` and `END DO SIMD`. Similar to
Block and Sections constructs, `End` node now accepts clauses too,
the validity checks are deferred into Semantics. This is more genernal
and error message could be better.
3. With this commit alone, assertion error would occur when `End` directive
is present, for example `!$OMP END DO` because the `End` node is not
moved into `OpenMPLoopConstruct` yet. Again, PR flang-compiler/f18#599 will handle that.
More tests will be added in PR flang-compiler/f18#599 and during the future Semantics work.
Original-commit: flang-compiler/f18@8cd1932fd61fa67f8ad5abfd337cf7a223ea89f4
Reviewed-on: https://github.com/flang-compiler/f18/pull/656
2019-08-15 06:16:27 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// no clauses are allowed
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-26 07:18:51 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
|
[flang] [OpenMP] parse tree changes for `OpenMPBlockConstruct` (flang-compiler/f18#632)
* [OpenMP] parse tree changes for `OpenMPBlockConstruct`
1. merge `Workshare` and `Single` into `OpenMPBlockConstruct` because
they both accept structured-block and syntax is similar to other block
directives.
2. `OpenMPBlockConstruct` changes to structure like `{Begin, Block, End}`,
where `Begin` and `End` are tuple of `{Directive, ClauseList}`.
3. Updated the check-omp-structure.* for necessary parts. Added all the END
directive enumeration types that may have clauses.
More tests will be added during Semantics.
* [OpenMP] Update on Tim's suggestion
1. Fix unspecified enumeration for `OmpDirective` in the `OmpContext`.
This is through getting rid of `PushContext(source)` function to
make sure whenever it is about to push a NEW context, directive
source location and enumeration are available. To do that, I moved
around all the switches for directive into high level `Construct`'s
`Enter` node. Besides fixing the issue, the side benefit is that
whenever we call `GetContext().directive`, we are sure that the
`directive` here was set already.
2. When `Enter` the `OmpEndBlockDirective` node, partial context
information, such as directive source location or legal clause lists,
needs to be reset. The new directive source location should be
`OmpEndBlockDirective`'s `source`. The enumeration `directive`
should not be reset for the END directives that do not accept
clauses because nothing needs to be checked (for example any clause
that is on `END PARALLEL` is illegal).
Original-commit: flang-compiler/f18@e5bd6b7ba0fbe9006f3e431260428b194f2d2616
Reviewed-on: https://github.com/flang-compiler/f18/pull/632
2019-08-10 06:11:20 +08:00
|
|
|
const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)};
|
2019-08-28 04:30:38 +08:00
|
|
|
const auto &endBlockDir{std::get<parser::OmpEndBlockDirective>(x.t)};
|
2020-08-06 02:20:26 +08:00
|
|
|
const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
|
|
|
|
const auto &endDir{std::get<parser::OmpBlockDirective>(endBlockDir.t)};
|
2020-10-30 12:50:05 +08:00
|
|
|
const parser::Block &block{std::get<parser::Block>(x.t)};
|
|
|
|
|
2020-08-06 02:20:26 +08:00
|
|
|
CheckMatching<parser::OmpBlockDirective>(beginDir, endDir);
|
2019-08-28 04:30:38 +08:00
|
|
|
|
2021-03-13 22:27:53 +08:00
|
|
|
PushContextAndClauseSets(beginDir.source, beginDir.v);
|
|
|
|
|
2021-04-29 20:29:58 +08:00
|
|
|
if (CurrentDirectiveIsNested()) {
|
2021-03-13 22:27:53 +08:00
|
|
|
CheckIfDoOrderedClause(beginDir);
|
2021-04-29 20:29:58 +08:00
|
|
|
if (llvm::omp::teamSet.test(GetContextParent().directive)) {
|
|
|
|
HasInvalidTeamsNesting(beginDir.v, beginDir.source);
|
|
|
|
}
|
2021-05-14 02:56:07 +08:00
|
|
|
if (GetContext().directive == llvm::omp::Directive::OMPD_master) {
|
|
|
|
CheckMasterNesting(x);
|
|
|
|
}
|
2021-04-29 20:29:58 +08:00
|
|
|
}
|
2021-01-15 13:42:49 +08:00
|
|
|
|
2020-12-17 16:58:03 +08:00
|
|
|
CheckNoBranching(block, beginDir.v, beginDir.source);
|
2021-01-19 20:58:44 +08:00
|
|
|
|
|
|
|
switch (beginDir.v) {
|
|
|
|
case llvm::omp::OMPD_workshare:
|
|
|
|
case llvm::omp::OMPD_parallel_workshare:
|
|
|
|
CheckWorkshareBlockStmts(block, beginDir.source);
|
2021-04-30 04:12:28 +08:00
|
|
|
HasInvalidWorksharingNesting(
|
|
|
|
beginDir.source, llvm::omp::nestedWorkshareErrSet);
|
|
|
|
break;
|
|
|
|
case llvm::omp::Directive::OMPD_single:
|
|
|
|
// TODO: This check needs to be extended while implementing nesting of
|
|
|
|
// regions checks.
|
|
|
|
HasInvalidWorksharingNesting(
|
|
|
|
beginDir.source, llvm::omp::nestedWorkshareErrSet);
|
2021-01-19 20:58:44 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
|
|
|
|
2021-05-14 02:56:07 +08:00
|
|
|
void OmpStructureChecker::CheckMasterNesting(
|
|
|
|
const parser::OpenMPBlockConstruct &x) {
|
|
|
|
// A MASTER region may not be `closely nested` inside a worksharing, loop,
|
|
|
|
// task, taskloop, or atomic region.
|
|
|
|
// TODO: Expand the check to include `LOOP` construct as well when it is
|
|
|
|
// supported.
|
|
|
|
if (IsCloselyNestedRegion(llvm::omp::nestedMasterErrSet)) {
|
|
|
|
context_.Say(parser::FindSourceLocation(x),
|
|
|
|
"`MASTER` region may not be closely nested inside of `WORKSHARING`, "
|
|
|
|
"`LOOP`, `TASK`, `TASKLOOP`,"
|
|
|
|
" or `ATOMIC` region."_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 20:54:27 +08:00
|
|
|
void OmpStructureChecker::CheckIfDoOrderedClause(
|
|
|
|
const parser::OmpBlockDirective &blkDirective) {
|
|
|
|
if (blkDirective.v == llvm::omp::OMPD_ordered) {
|
2021-03-20 02:54:06 +08:00
|
|
|
// Loops
|
|
|
|
if (llvm::omp::doSet.test(GetContextParent().directive) &&
|
|
|
|
!FindClauseParent(llvm::omp::Clause::OMPC_ordered)) {
|
2021-02-15 20:54:27 +08:00
|
|
|
context_.Say(blkDirective.source,
|
|
|
|
"The ORDERED clause must be present on the loop"
|
|
|
|
" construct if any ORDERED region ever binds"
|
|
|
|
" to a loop region arising from the loop construct."_err_en_US);
|
|
|
|
}
|
2021-03-20 02:54:06 +08:00
|
|
|
// Other disallowed nestings, these directives do not support
|
|
|
|
// ordered clause in them, so no need to check
|
2021-04-14 01:56:43 +08:00
|
|
|
else if (IsCloselyNestedRegion(llvm::omp::nestedOrderedErrSet)) {
|
2021-03-20 02:54:06 +08:00
|
|
|
context_.Say(blkDirective.source,
|
|
|
|
"`ORDERED` region may not be closely nested inside of "
|
|
|
|
"`CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region."_err_en_US);
|
|
|
|
}
|
2021-02-15 20:54:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-26 07:18:51 +08:00
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
|
|
|
|
2019-08-02 05:32:33 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
|
2019-08-14 23:42:28 +08:00
|
|
|
const auto &beginSectionsDir{
|
|
|
|
std::get<parser::OmpBeginSectionsDirective>(x.t)};
|
2019-08-28 04:30:38 +08:00
|
|
|
const auto &endSectionsDir{std::get<parser::OmpEndSectionsDirective>(x.t)};
|
2020-08-06 02:20:26 +08:00
|
|
|
const auto &beginDir{
|
|
|
|
std::get<parser::OmpSectionsDirective>(beginSectionsDir.t)};
|
|
|
|
const auto &endDir{std::get<parser::OmpSectionsDirective>(endSectionsDir.t)};
|
|
|
|
CheckMatching<parser::OmpSectionsDirective>(beginDir, endDir);
|
2019-08-28 04:30:38 +08:00
|
|
|
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
PushContextAndClauseSets(beginDir.source, beginDir.v);
|
2021-02-03 18:18:30 +08:00
|
|
|
const auto §ionBlocks{std::get<parser::OmpSectionBlocks>(x.t)};
|
|
|
|
for (const auto &block : sectionBlocks.v) {
|
|
|
|
CheckNoBranching(block, beginDir.v, beginDir.source);
|
|
|
|
}
|
2021-04-30 04:12:28 +08:00
|
|
|
HasInvalidWorksharingNesting(
|
|
|
|
beginDir.source, llvm::omp::nestedWorkshareErrSet);
|
2019-08-02 05:32:33 +08:00
|
|
|
}
|
|
|
|
|
2019-08-07 02:59:40 +08:00
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPSectionsConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-02 05:32:33 +08:00
|
|
|
}
|
|
|
|
|
2019-08-14 23:42:28 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpEndSectionsDirective &x) {
|
|
|
|
const auto &dir{std::get<parser::OmpSectionsDirective>(x.t)};
|
|
|
|
ResetPartialContext(dir.source);
|
|
|
|
switch (dir.v) {
|
|
|
|
// 2.7.2 end-sections -> END SECTIONS [nowait-clause]
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
case llvm::omp::Directive::OMPD_sections:
|
2020-11-05 16:55:06 +08:00
|
|
|
PushContextAndClauseSets(
|
|
|
|
dir.source, llvm::omp::Directive::OMPD_end_sections);
|
2019-08-14 23:42:28 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// no clauses are allowed
|
|
|
|
break;
|
2019-08-02 05:32:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-13 01:22:21 +08:00
|
|
|
// TODO: Verify the popping of dirContext requirement after nowait
|
|
|
|
// implementation, as there is an implicit barrier at the end of the worksharing
|
|
|
|
// constructs unless a nowait clause is specified. Only OMPD_end_sections is
|
|
|
|
// popped becuase it is pushed while entering the EndSectionsDirective.
|
|
|
|
void OmpStructureChecker::Leave(const parser::OmpEndSectionsDirective &x) {
|
|
|
|
if (GetContext().directive == llvm::omp::Directive::OMPD_end_sections) {
|
|
|
|
dirContext_.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-06 05:51:02 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_declare_simd);
|
2019-08-06 05:51:02 +08:00
|
|
|
}
|
|
|
|
|
2019-08-07 02:59:40 +08:00
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-06 05:51:02 +08:00
|
|
|
}
|
|
|
|
|
2020-10-17 00:36:12 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeAllocate &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
2021-04-22 23:45:19 +08:00
|
|
|
const auto &objectList{std::get<parser::OmpObjectList>(x.t)};
|
2020-10-17 00:36:12 +08:00
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
|
2021-04-22 23:45:19 +08:00
|
|
|
CheckIsVarPartOfAnotherVar(dir.source, objectList);
|
2020-10-17 00:36:12 +08:00
|
|
|
}
|
|
|
|
|
2021-04-22 23:45:19 +08:00
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeAllocate &x) {
|
2020-10-17 00:36:12 +08:00
|
|
|
dirContext_.pop_back();
|
|
|
|
}
|
|
|
|
|
2019-08-21 01:23:56 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
PushContext(dir.source, llvm::omp::Directive::OMPD_declare_target);
|
2019-08-21 01:23:56 +08:00
|
|
|
const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x.t)};
|
|
|
|
if (std::holds_alternative<parser::OmpDeclareTargetWithClause>(spec.u)) {
|
2020-11-05 16:55:06 +08:00
|
|
|
SetClauseSets(llvm::omp::Directive::OMPD_declare_target);
|
2019-08-21 01:23:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-21 01:23:56 +08:00
|
|
|
}
|
|
|
|
|
2020-10-17 00:36:12 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
2021-04-22 23:45:19 +08:00
|
|
|
const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
|
2020-10-17 00:36:12 +08:00
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
|
2021-04-22 23:45:19 +08:00
|
|
|
if (objectList)
|
|
|
|
CheckIsVarPartOfAnotherVar(dir.source, *objectList);
|
2020-10-17 00:36:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &) {
|
|
|
|
dirContext_.pop_back();
|
|
|
|
}
|
|
|
|
|
2019-08-07 02:59:40 +08:00
|
|
|
void OmpStructureChecker::Enter(
|
|
|
|
const parser::OpenMPSimpleStandaloneConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
PushContextAndClauseSets(dir.source, dir.v);
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(
|
|
|
|
const parser::OpenMPSimpleStandaloneConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPFlushConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_flush);
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
2020-12-14 16:00:26 +08:00
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &x) {
|
|
|
|
if (FindClause(llvm::omp::Clause::OMPC_acquire) ||
|
|
|
|
FindClause(llvm::omp::Clause::OMPC_release) ||
|
|
|
|
FindClause(llvm::omp::Clause::OMPC_acq_rel)) {
|
|
|
|
if (const auto &flushList{
|
|
|
|
std::get<std::optional<parser::OmpObjectList>>(x.t)}) {
|
|
|
|
context_.Say(parser::FindSourceLocation(flushList),
|
|
|
|
"If memory-order-clause is RELEASE, ACQUIRE, or ACQ_REL, list items "
|
|
|
|
"must not be specified on the FLUSH directive"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_cancel);
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
2020-10-07 02:18:08 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::OmpCriticalDirective>(x.t)};
|
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_critical);
|
2021-02-03 18:18:30 +08:00
|
|
|
const auto &block{std::get<parser::Block>(x.t)};
|
|
|
|
CheckNoBranching(block, llvm::omp::Directive::OMPD_critical, dir.source);
|
2020-10-07 02:18:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
|
|
|
|
dirContext_.pop_back();
|
|
|
|
}
|
|
|
|
|
2019-08-07 02:59:40 +08:00
|
|
|
void OmpStructureChecker::Enter(
|
|
|
|
const parser::OpenMPCancellationPointConstruct &x) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
[flang][openmp] Check clauses allowed semantic with tablegen generated map
Summary:
This patch is enabling the generation of clauses enum sets for semantics check in Flang through
tablegen. Enum sets and directive - sets map is generated by the new tablegen infrsatructure for OpenMP
and other directive languages.
The semantic checks for OpenMP are modified to use this newly generated map.
Reviewers: DavidTruby, sscalpone, kiranchandramohan, ichoyjx, jdoerfert
Reviewed By: DavidTruby, ichoyjx
Subscribers: mgorny, yaxunl, hiraditya, guansong, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83326
2020-07-12 00:42:05 +08:00
|
|
|
PushContextAndClauseSets(
|
|
|
|
dir.source, llvm::omp::Directive::OMPD_cancellation_point);
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(
|
|
|
|
const parser::OpenMPCancellationPointConstruct &) {
|
2020-08-06 02:20:26 +08:00
|
|
|
dirContext_.pop_back();
|
2019-08-07 02:59:40 +08:00
|
|
|
}
|
|
|
|
|
[flang] [OpenMP] parse tree changes for `OpenMPBlockConstruct` (flang-compiler/f18#632)
* [OpenMP] parse tree changes for `OpenMPBlockConstruct`
1. merge `Workshare` and `Single` into `OpenMPBlockConstruct` because
they both accept structured-block and syntax is similar to other block
directives.
2. `OpenMPBlockConstruct` changes to structure like `{Begin, Block, End}`,
where `Begin` and `End` are tuple of `{Directive, ClauseList}`.
3. Updated the check-omp-structure.* for necessary parts. Added all the END
directive enumeration types that may have clauses.
More tests will be added during Semantics.
* [OpenMP] Update on Tim's suggestion
1. Fix unspecified enumeration for `OmpDirective` in the `OmpContext`.
This is through getting rid of `PushContext(source)` function to
make sure whenever it is about to push a NEW context, directive
source location and enumeration are available. To do that, I moved
around all the switches for directive into high level `Construct`'s
`Enter` node. Besides fixing the issue, the side benefit is that
whenever we call `GetContext().directive`, we are sure that the
`directive` here was set already.
2. When `Enter` the `OmpEndBlockDirective` node, partial context
information, such as directive source location or legal clause lists,
needs to be reset. The new directive source location should be
`OmpEndBlockDirective`'s `source`. The enumeration `directive`
should not be reset for the END directives that do not accept
clauses because nothing needs to be checked (for example any clause
that is on `END PARALLEL` is illegal).
Original-commit: flang-compiler/f18@e5bd6b7ba0fbe9006f3e431260428b194f2d2616
Reviewed-on: https://github.com/flang-compiler/f18/pull/632
2019-08-10 06:11:20 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) {
|
|
|
|
const auto &dir{std::get<parser::OmpBlockDirective>(x.t)};
|
|
|
|
ResetPartialContext(dir.source);
|
|
|
|
switch (dir.v) {
|
|
|
|
// 2.7.3 end-single-clause -> copyprivate-clause |
|
|
|
|
// nowait-clause
|
2020-11-05 16:55:06 +08:00
|
|
|
case llvm::omp::Directive::OMPD_single:
|
|
|
|
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_end_single);
|
|
|
|
break;
|
[flang] [OpenMP] parse tree changes for `OpenMPBlockConstruct` (flang-compiler/f18#632)
* [OpenMP] parse tree changes for `OpenMPBlockConstruct`
1. merge `Workshare` and `Single` into `OpenMPBlockConstruct` because
they both accept structured-block and syntax is similar to other block
directives.
2. `OpenMPBlockConstruct` changes to structure like `{Begin, Block, End}`,
where `Begin` and `End` are tuple of `{Directive, ClauseList}`.
3. Updated the check-omp-structure.* for necessary parts. Added all the END
directive enumeration types that may have clauses.
More tests will be added during Semantics.
* [OpenMP] Update on Tim's suggestion
1. Fix unspecified enumeration for `OmpDirective` in the `OmpContext`.
This is through getting rid of `PushContext(source)` function to
make sure whenever it is about to push a NEW context, directive
source location and enumeration are available. To do that, I moved
around all the switches for directive into high level `Construct`'s
`Enter` node. Besides fixing the issue, the side benefit is that
whenever we call `GetContext().directive`, we are sure that the
`directive` here was set already.
2. When `Enter` the `OmpEndBlockDirective` node, partial context
information, such as directive source location or legal clause lists,
needs to be reset. The new directive source location should be
`OmpEndBlockDirective`'s `source`. The enumeration `directive`
should not be reset for the END directives that do not accept
clauses because nothing needs to be checked (for example any clause
that is on `END PARALLEL` is illegal).
Original-commit: flang-compiler/f18@e5bd6b7ba0fbe9006f3e431260428b194f2d2616
Reviewed-on: https://github.com/flang-compiler/f18/pull/632
2019-08-10 06:11:20 +08:00
|
|
|
// 2.7.4 end-workshare -> END WORKSHARE [nowait-clause]
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
case llvm::omp::Directive::OMPD_workshare:
|
2020-11-05 16:55:06 +08:00
|
|
|
PushContextAndClauseSets(
|
|
|
|
dir.source, llvm::omp::Directive::OMPD_end_workshare);
|
2019-07-13 05:23:16 +08:00
|
|
|
break;
|
2019-07-13 04:35:22 +08:00
|
|
|
default:
|
[flang] [OpenMP] parse tree changes for `OpenMPBlockConstruct` (flang-compiler/f18#632)
* [OpenMP] parse tree changes for `OpenMPBlockConstruct`
1. merge `Workshare` and `Single` into `OpenMPBlockConstruct` because
they both accept structured-block and syntax is similar to other block
directives.
2. `OpenMPBlockConstruct` changes to structure like `{Begin, Block, End}`,
where `Begin` and `End` are tuple of `{Directive, ClauseList}`.
3. Updated the check-omp-structure.* for necessary parts. Added all the END
directive enumeration types that may have clauses.
More tests will be added during Semantics.
* [OpenMP] Update on Tim's suggestion
1. Fix unspecified enumeration for `OmpDirective` in the `OmpContext`.
This is through getting rid of `PushContext(source)` function to
make sure whenever it is about to push a NEW context, directive
source location and enumeration are available. To do that, I moved
around all the switches for directive into high level `Construct`'s
`Enter` node. Besides fixing the issue, the side benefit is that
whenever we call `GetContext().directive`, we are sure that the
`directive` here was set already.
2. When `Enter` the `OmpEndBlockDirective` node, partial context
information, such as directive source location or legal clause lists,
needs to be reset. The new directive source location should be
`OmpEndBlockDirective`'s `source`. The enumeration `directive`
should not be reset for the END directives that do not accept
clauses because nothing needs to be checked (for example any clause
that is on `END PARALLEL` is illegal).
Original-commit: flang-compiler/f18@e5bd6b7ba0fbe9006f3e431260428b194f2d2616
Reviewed-on: https://github.com/flang-compiler/f18/pull/632
2019-08-10 06:11:20 +08:00
|
|
|
// no clauses are allowed
|
2019-07-13 04:35:22 +08:00
|
|
|
break;
|
|
|
|
}
|
2019-07-12 06:18:09 +08:00
|
|
|
}
|
|
|
|
|
2021-03-13 01:22:21 +08:00
|
|
|
// TODO: Verify the popping of dirContext requirement after nowait
|
|
|
|
// implementation, as there is an implicit barrier at the end of the worksharing
|
|
|
|
// constructs unless a nowait clause is specified. Only OMPD_end_single and
|
|
|
|
// end_workshareare popped as they are pushed while entering the
|
|
|
|
// EndBlockDirective.
|
|
|
|
void OmpStructureChecker::Leave(const parser::OmpEndBlockDirective &x) {
|
|
|
|
if ((GetContext().directive == llvm::omp::Directive::OMPD_end_single) ||
|
|
|
|
(GetContext().directive == llvm::omp::Directive::OMPD_end_workshare)) {
|
|
|
|
dirContext_.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 15:11:39 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
|
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](const auto &someAtomicConstruct) {
|
|
|
|
const auto &dir{std::get<parser::Verbatim>(someAtomicConstruct.t)};
|
|
|
|
PushContextAndClauseSets(
|
|
|
|
dir.source, llvm::omp::Directive::OMPD_atomic);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
x.u);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OpenMPAtomicConstruct &) {
|
|
|
|
dirContext_.pop_back();
|
|
|
|
}
|
|
|
|
|
2020-10-29 02:13:49 +08:00
|
|
|
// Clauses
|
|
|
|
// Mainly categorized as
|
|
|
|
// 1. Checks on 'OmpClauseList' from 'parse-tree.h'.
|
|
|
|
// 2. Checks on clauses which fall under 'struct OmpClause' from parse-tree.h.
|
|
|
|
// 3. Checks on clauses which are not in 'struct OmpClause' from parse-tree.h.
|
|
|
|
|
2019-07-02 04:55:06 +08:00
|
|
|
void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
|
|
|
|
// 2.7 Loop Construct Restriction
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (llvm::omp::doSet.test(GetContext().directive)) {
|
|
|
|
if (auto *clause{FindClause(llvm::omp::Clause::OMPC_schedule)}) {
|
2019-07-02 04:55:06 +08:00
|
|
|
// only one schedule clause is allowed
|
2021-01-19 23:28:09 +08:00
|
|
|
const auto &schedClause{std::get<parser::OmpClause::Schedule>(clause->u)};
|
|
|
|
if (ScheduleModifierHasType(schedClause.v,
|
2019-07-02 04:55:06 +08:00
|
|
|
parser::OmpScheduleModifierType::ModType::Nonmonotonic)) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (FindClause(llvm::omp::Clause::OMPC_ordered)) {
|
2019-07-02 04:55:06 +08:00
|
|
|
context_.Say(clause->source,
|
|
|
|
"The NONMONOTONIC modifier cannot be specified "
|
|
|
|
"if an ORDERED clause is specified"_err_en_US);
|
|
|
|
}
|
2021-01-19 23:28:09 +08:00
|
|
|
if (ScheduleModifierHasType(schedClause.v,
|
2019-07-02 04:55:06 +08:00
|
|
|
parser::OmpScheduleModifierType::ModType::Monotonic)) {
|
|
|
|
context_.Say(clause->source,
|
|
|
|
"The MONOTONIC and NONMONOTONIC modifiers "
|
|
|
|
"cannot be both specified"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (auto *clause{FindClause(llvm::omp::Clause::OMPC_ordered)}) {
|
2019-07-04 05:24:37 +08:00
|
|
|
// only one ordered clause is allowed
|
|
|
|
const auto &orderedClause{
|
|
|
|
std::get<parser::OmpClause::Ordered>(clause->u)};
|
|
|
|
|
2019-11-10 01:29:31 +08:00
|
|
|
if (orderedClause.v) {
|
2020-11-05 16:55:06 +08:00
|
|
|
CheckNotAllowedIfClause(
|
|
|
|
llvm::omp::Clause::OMPC_ordered, {llvm::omp::Clause::OMPC_linear});
|
2019-07-04 05:24:37 +08:00
|
|
|
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (auto *clause2{FindClause(llvm::omp::Clause::OMPC_collapse)}) {
|
2019-07-04 05:24:37 +08:00
|
|
|
const auto &collapseClause{
|
|
|
|
std::get<parser::OmpClause::Collapse>(clause2->u)};
|
|
|
|
// ordered and collapse both have parameters
|
|
|
|
if (const auto orderedValue{GetIntValue(orderedClause.v)}) {
|
|
|
|
if (const auto collapseValue{GetIntValue(collapseClause.v)}) {
|
|
|
|
if (*orderedValue > 0 && *orderedValue < *collapseValue) {
|
|
|
|
context_.Say(clause->source,
|
|
|
|
"The parameter of the ORDERED clause must be "
|
|
|
|
"greater than or equal to "
|
|
|
|
"the parameter of the COLLAPSE clause"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-02 04:55:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: ordered region binding check (requires nesting implementation)
|
|
|
|
}
|
2020-03-29 12:00:16 +08:00
|
|
|
} // doSet
|
2019-07-10 05:08:50 +08:00
|
|
|
|
|
|
|
// 2.8.1 Simd Construct Restriction
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (llvm::omp::simdSet.test(GetContext().directive)) {
|
|
|
|
if (auto *clause{FindClause(llvm::omp::Clause::OMPC_simdlen)}) {
|
|
|
|
if (auto *clause2{FindClause(llvm::omp::Clause::OMPC_safelen)}) {
|
2019-07-10 05:08:50 +08:00
|
|
|
const auto &simdlenClause{
|
|
|
|
std::get<parser::OmpClause::Simdlen>(clause->u)};
|
|
|
|
const auto &safelenClause{
|
|
|
|
std::get<parser::OmpClause::Safelen>(clause2->u)};
|
|
|
|
// simdlen and safelen both have parameters
|
|
|
|
if (const auto simdlenValue{GetIntValue(simdlenClause.v)}) {
|
|
|
|
if (const auto safelenValue{GetIntValue(safelenClause.v)}) {
|
|
|
|
if (*safelenValue > 0 && *simdlenValue > *safelenValue) {
|
|
|
|
context_.Say(clause->source,
|
|
|
|
"The parameter of the SIMDLEN clause must be less than or "
|
|
|
|
"equal to the parameter of the SAFELEN clause"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 21:15:55 +08:00
|
|
|
// A list-item cannot appear in more than one aligned clause
|
2021-03-19 01:26:23 +08:00
|
|
|
semantics::UnorderedSymbolSet alignedVars;
|
2021-03-11 21:15:55 +08:00
|
|
|
auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_aligned);
|
|
|
|
for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
|
|
|
|
const auto &alignedClause{
|
|
|
|
std::get<parser::OmpClause::Aligned>(itr->second->u)};
|
|
|
|
const auto &alignedNameList{
|
|
|
|
std::get<std::list<parser::Name>>(alignedClause.v.t)};
|
|
|
|
for (auto const &var : alignedNameList) {
|
|
|
|
if (alignedVars.count(*(var.symbol)) == 1) {
|
|
|
|
context_.Say(itr->second->source,
|
|
|
|
"List item '%s' present at multiple ALIGNED clauses"_err_en_US,
|
|
|
|
var.ToString());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
alignedVars.insert(*(var.symbol));
|
|
|
|
}
|
|
|
|
}
|
2020-03-29 12:00:16 +08:00
|
|
|
} // SIMD
|
2019-08-02 05:32:33 +08:00
|
|
|
|
|
|
|
// 2.7.3 Single Construct Restriction
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
|
2020-11-05 16:55:06 +08:00
|
|
|
CheckNotAllowedIfClause(
|
|
|
|
llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
|
2019-08-02 05:32:33 +08:00
|
|
|
}
|
2019-09-17 16:53:27 +08:00
|
|
|
|
2021-01-12 03:08:35 +08:00
|
|
|
CheckRequireAtLeastOneOf();
|
2019-07-02 04:55:06 +08:00
|
|
|
}
|
|
|
|
|
2019-06-26 07:18:51 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause &x) {
|
2019-07-02 04:55:06 +08:00
|
|
|
SetContextClause(x);
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
|
|
|
|
2021-02-02 02:33:07 +08:00
|
|
|
// Following clauses do not have a separate node in parse-tree.h.
|
|
|
|
CHECK_SIMPLE_CLAUSE(AcqRel, OMPC_acq_rel)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Acquire, OMPC_acquire)
|
|
|
|
CHECK_SIMPLE_CLAUSE(AtomicDefaultMemOrder, OMPC_atomic_default_mem_order)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Affinity, OMPC_affinity)
|
2020-12-19 02:33:45 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Allocate, OMPC_allocate)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Copyin, OMPC_copyin)
|
2020-12-21 16:40:27 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Device, OMPC_device)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
|
|
|
|
CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
|
|
|
|
CHECK_SIMPLE_CLAUSE(DynamicAllocators, OMPC_dynamic_allocators)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Final, OMPC_final)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(From, OMPC_from)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
|
|
|
|
CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Match, OMPC_match)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Order, OMPC_order)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Read, OMPC_read)
|
|
|
|
CHECK_SIMPLE_CLAUSE(ReverseOffload, OMPC_reverse_offload)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Threadprivate, OMPC_threadprivate)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Threads, OMPC_threads)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Inbranch, OMPC_inbranch)
|
|
|
|
CHECK_SIMPLE_CLAUSE(IsDevicePtr, OMPC_is_device_ptr)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Link, OMPC_link)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Mergeable, OMPC_mergeable)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Nogroup, OMPC_nogroup)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Notinbranch, OMPC_notinbranch)
|
2020-12-21 22:04:12 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Nowait, OMPC_nowait)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(ProcBind, OMPC_proc_bind)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Release, OMPC_release)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Relaxed, OMPC_relaxed)
|
|
|
|
CHECK_SIMPLE_CLAUSE(SeqCst, OMPC_seq_cst)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Simd, OMPC_simd)
|
2021-02-17 04:37:46 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Sizes, OMPC_sizes)
|
2021-01-04 11:17:02 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(TaskReduction, OMPC_task_reduction)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(To, OMPC_to)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(UnifiedAddress, OMPC_unified_address)
|
|
|
|
CHECK_SIMPLE_CLAUSE(UnifiedSharedMemory, OMPC_unified_shared_memory)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Unknown, OMPC_unknown)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Untied, OMPC_untied)
|
|
|
|
CHECK_SIMPLE_CLAUSE(UseDevicePtr, OMPC_use_device_ptr)
|
2021-02-02 02:33:07 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(UsesAllocators, OMPC_uses_allocators)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Update, OMPC_update)
|
|
|
|
CHECK_SIMPLE_CLAUSE(UseDeviceAddr, OMPC_use_device_addr)
|
|
|
|
CHECK_SIMPLE_CLAUSE(Write, OMPC_write)
|
2021-03-16 04:09:46 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Init, OMPC_init)
|
2021-03-18 04:04:08 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Use, OMPC_use)
|
2021-04-01 03:26:47 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Novariants, OMPC_novariants)
|
2021-04-04 02:09:25 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext)
|
2021-04-10 03:00:36 +08:00
|
|
|
CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter)
|
2020-10-29 02:13:49 +08:00
|
|
|
|
2020-10-17 00:36:12 +08:00
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator)
|
2020-10-29 02:13:49 +08:00
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
|
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks)
|
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(NumTeams, OMPC_num_teams)
|
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(NumThreads, OMPC_num_threads)
|
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(Priority, OMPC_priority)
|
|
|
|
CHECK_REQ_SCALAR_INT_CLAUSE(ThreadLimit, OMPC_thread_limit)
|
|
|
|
|
|
|
|
CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Collapse, OMPC_collapse)
|
|
|
|
CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Safelen, OMPC_safelen)
|
|
|
|
CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Simdlen, OMPC_simdlen)
|
|
|
|
|
|
|
|
// Restrictions specific to each clause are implemented apart from the
|
|
|
|
// generalized restrictions.
|
2021-03-13 01:22:21 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
|
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_reduction);
|
|
|
|
if (CheckReductionOperators(x)) {
|
|
|
|
CheckReductionTypeList(x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool OmpStructureChecker::CheckReductionOperators(
|
|
|
|
const parser::OmpClause::Reduction &x) {
|
|
|
|
|
|
|
|
const auto &definedOp{std::get<0>(x.v.t)};
|
|
|
|
bool ok = false;
|
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](const parser::DefinedOperator &dOpr) {
|
|
|
|
const auto &intrinsicOp{
|
|
|
|
std::get<parser::DefinedOperator::IntrinsicOperator>(dOpr.u)};
|
|
|
|
ok = CheckIntrinsicOperator(intrinsicOp);
|
|
|
|
},
|
|
|
|
[&](const parser::ProcedureDesignator &procD) {
|
|
|
|
const parser::Name *name{std::get_if<parser::Name>(&procD.u)};
|
|
|
|
if (name) {
|
|
|
|
if (name->source == "max" || name->source == "min" ||
|
|
|
|
name->source == "iand" || name->source == "ior" ||
|
|
|
|
name->source == "ieor") {
|
|
|
|
ok = true;
|
|
|
|
} else {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Invalid reduction identifier in REDUCTION clause."_err_en_US,
|
|
|
|
ContextDirectiveAsFortran());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
definedOp.u);
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
bool OmpStructureChecker::CheckIntrinsicOperator(
|
|
|
|
const parser::DefinedOperator::IntrinsicOperator &op) {
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::Add:
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::Subtract:
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::Multiply:
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::AND:
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::OR:
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::EQV:
|
|
|
|
case parser::DefinedOperator::IntrinsicOperator::NEQV:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Invalid reduction operator in REDUCTION clause."_err_en_US,
|
|
|
|
ContextDirectiveAsFortran());
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckReductionTypeList(
|
|
|
|
const parser::OmpClause::Reduction &x) {
|
|
|
|
const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
|
|
|
|
CheckIntentInPointerAndDefinable(
|
|
|
|
ompObjectList, llvm::omp::Clause::OMPC_reduction);
|
|
|
|
CheckReductionArraySection(ompObjectList);
|
|
|
|
CheckMultipleAppearanceAcrossContext(ompObjectList);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckIntentInPointerAndDefinable(
|
|
|
|
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
|
|
|
|
for (const auto &ompObject : objectList.v) {
|
|
|
|
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
|
|
|
|
if (const auto *symbol{name->symbol}) {
|
|
|
|
if (IsPointer(symbol->GetUltimate()) &&
|
|
|
|
IsIntentIn(symbol->GetUltimate())) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Pointer '%s' with the INTENT(IN) attribute may not appear "
|
|
|
|
"in a %s clause"_err_en_US,
|
|
|
|
symbol->name(),
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()));
|
|
|
|
}
|
|
|
|
if (auto msg{
|
|
|
|
WhyNotModifiable(*symbol, context_.FindScope(name->source))}) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Variable '%s' on the %s clause is not definable"_err_en_US,
|
|
|
|
symbol->name(),
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckReductionArraySection(
|
|
|
|
const parser::OmpObjectList &ompObjectList) {
|
|
|
|
for (const auto &ompObject : ompObjectList.v) {
|
|
|
|
if (const auto *dataRef{parser::Unwrap<parser::DataRef>(ompObject)}) {
|
|
|
|
if (const auto *arrayElement{
|
|
|
|
parser::Unwrap<parser::ArrayElement>(ompObject)}) {
|
|
|
|
if (arrayElement) {
|
|
|
|
CheckArraySection(*arrayElement, GetLastName(*dataRef),
|
|
|
|
llvm::omp::Clause::OMPC_reduction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckMultipleAppearanceAcrossContext(
|
|
|
|
const parser::OmpObjectList &redObjectList) {
|
|
|
|
// TODO: Verify the assumption here that the immediately enclosing region is
|
|
|
|
// the parallel region to which the worksharing construct having reduction
|
|
|
|
// binds to.
|
|
|
|
if (auto *enclosingContext{GetEnclosingDirContext()}) {
|
|
|
|
for (auto it : enclosingContext->clauseInfo) {
|
|
|
|
llvmOmpClause type = it.first;
|
|
|
|
const auto *clause = it.second;
|
2021-03-14 20:42:30 +08:00
|
|
|
if (llvm::omp::privateReductionSet.test(type)) {
|
|
|
|
if (const auto *objList{GetOmpObjectList(*clause)}) {
|
|
|
|
for (const auto &ompObject : objList->v) {
|
|
|
|
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
|
|
|
|
if (const auto *symbol{name->symbol}) {
|
|
|
|
for (const auto &redOmpObject : redObjectList.v) {
|
|
|
|
if (const auto *rname{
|
|
|
|
parser::Unwrap<parser::Name>(redOmpObject)}) {
|
|
|
|
if (const auto *rsymbol{rname->symbol}) {
|
|
|
|
if (rsymbol->name() == symbol->name()) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"%s variable '%s' is %s in outer context must"
|
|
|
|
" be shared in the parallel regions to which any"
|
|
|
|
" of the worksharing regions arising from the "
|
|
|
|
"worksharing"
|
|
|
|
" construct bind."_err_en_US,
|
|
|
|
parser::ToUpperCaseLetters(
|
|
|
|
getClauseName(llvm::omp::Clause::OMPC_reduction)
|
|
|
|
.str()),
|
|
|
|
symbol->name(),
|
|
|
|
parser::ToUpperCaseLetters(
|
|
|
|
getClauseName(type).str()));
|
|
|
|
}
|
2021-03-13 01:22:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 05:24:37 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_ordered);
|
2019-07-04 05:24:37 +08:00
|
|
|
// the parameter of ordered clause is optional
|
|
|
|
if (const auto &expr{x.v}) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_ordered, *expr);
|
2019-07-12 06:18:09 +08:00
|
|
|
// 2.8.3 Loop SIMD Construct Restriction
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (llvm::omp::doSimdSet.test(GetContext().directive)) {
|
2019-07-12 06:18:09 +08:00
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"No ORDERED clause with a parameter can be specified "
|
|
|
|
"on the %s directive"_err_en_US,
|
|
|
|
ContextDirectiveAsFortran());
|
|
|
|
}
|
2019-07-04 05:24:37 +08:00
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
|
|
|
|
2020-11-22 14:32:00 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Shared &x) {
|
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_shared);
|
2021-04-22 23:45:19 +08:00
|
|
|
CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v);
|
2020-11-22 14:32:00 +08:00
|
|
|
}
|
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
|
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_private);
|
2021-04-22 23:45:19 +08:00
|
|
|
CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v);
|
2020-12-01 00:35:35 +08:00
|
|
|
CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_private);
|
2020-11-22 14:32:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
|
2021-04-22 23:45:19 +08:00
|
|
|
const parser::CharBlock &source, const parser::OmpObjectList &objList) {
|
|
|
|
|
2020-11-22 14:32:00 +08:00
|
|
|
for (const auto &ompObject : objList.v) {
|
2021-04-22 23:45:19 +08:00
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](const parser::Designator &designator) {
|
|
|
|
if (std::get_if<parser::DataRef>(&designator.u)) {
|
|
|
|
if ((parser::Unwrap<parser::StructureComponent>(ompObject)) ||
|
|
|
|
(parser::Unwrap<parser::ArrayElement>(ompObject))) {
|
|
|
|
context_.Say(source,
|
|
|
|
"A variable that is part of another variable (as an "
|
|
|
|
"array or structure element)"
|
|
|
|
" cannot appear in a PRIVATE or SHARED clause or on the ALLOCATE directive."_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[&](const parser::Name &name) {},
|
|
|
|
},
|
|
|
|
ompObject.u);
|
2020-11-22 14:32:00 +08:00
|
|
|
}
|
|
|
|
}
|
2021-04-22 23:45:19 +08:00
|
|
|
|
2021-01-15 13:42:49 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
|
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_firstprivate);
|
|
|
|
CheckIsLoopIvPartOfClause(llvmOmpClause::OMPC_firstprivate, x.v);
|
2021-01-31 00:45:09 +08:00
|
|
|
|
|
|
|
SymbolSourceMap currSymbols;
|
|
|
|
GetSymbolsInObjectList(x.v, currSymbols);
|
|
|
|
|
|
|
|
DirectivesClauseTriple dirClauseTriple;
|
|
|
|
// Check firstprivate variables in worksharing constructs
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_do,
|
|
|
|
std::make_pair(
|
|
|
|
llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_sections,
|
|
|
|
std::make_pair(
|
|
|
|
llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_single,
|
|
|
|
std::make_pair(
|
|
|
|
llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
|
|
|
|
// Check firstprivate variables in distribute construct
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_distribute,
|
|
|
|
std::make_pair(
|
|
|
|
llvm::omp::Directive::OMPD_teams, llvm::omp::privateReductionSet));
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_distribute,
|
|
|
|
std::make_pair(llvm::omp::Directive::OMPD_target_teams,
|
|
|
|
llvm::omp::privateReductionSet));
|
|
|
|
// Check firstprivate variables in task and taskloop constructs
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_task,
|
|
|
|
std::make_pair(llvm::omp::Directive::OMPD_parallel,
|
|
|
|
OmpClauseSet{llvm::omp::Clause::OMPC_reduction}));
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_taskloop,
|
|
|
|
std::make_pair(llvm::omp::Directive::OMPD_parallel,
|
|
|
|
OmpClauseSet{llvm::omp::Clause::OMPC_reduction}));
|
|
|
|
|
|
|
|
CheckPrivateSymbolsInOuterCxt(
|
|
|
|
currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_firstprivate);
|
2021-01-15 13:42:49 +08:00
|
|
|
}
|
2021-01-31 00:45:09 +08:00
|
|
|
|
2021-01-15 13:42:49 +08:00
|
|
|
void OmpStructureChecker::CheckIsLoopIvPartOfClause(
|
|
|
|
llvmOmpClause clause, const parser::OmpObjectList &ompObjectList) {
|
|
|
|
for (const auto &ompObject : ompObjectList.v) {
|
|
|
|
if (const parser::Name * name{parser::Unwrap<parser::Name>(ompObject)}) {
|
|
|
|
if (name->symbol == GetContext().loopIV) {
|
|
|
|
context_.Say(name->source,
|
|
|
|
"DO iteration variable %s is not allowed in %s clause."_err_en_US,
|
|
|
|
name->ToString(),
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-29 02:13:49 +08:00
|
|
|
// Following clauses have a seperate node in parse-tree.h.
|
2020-12-14 15:11:39 +08:00
|
|
|
// Atomic-clause
|
|
|
|
CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicRead, OMPC_read)
|
|
|
|
CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicWrite, OMPC_write)
|
|
|
|
CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicUpdate, OMPC_update)
|
|
|
|
CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicCapture, OMPC_capture)
|
|
|
|
|
|
|
|
void OmpStructureChecker::Leave(const parser::OmpAtomicRead &) {
|
|
|
|
CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_read,
|
|
|
|
{llvm::omp::Clause::OMPC_release, llvm::omp::Clause::OMPC_acq_rel});
|
|
|
|
}
|
|
|
|
void OmpStructureChecker::Leave(const parser::OmpAtomicWrite &) {
|
|
|
|
CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_write,
|
|
|
|
{llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel});
|
|
|
|
}
|
|
|
|
void OmpStructureChecker::Leave(const parser::OmpAtomicUpdate &) {
|
|
|
|
CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_update,
|
|
|
|
{llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel});
|
|
|
|
}
|
|
|
|
// OmpAtomic node represents atomic directive without atomic-clause.
|
|
|
|
// atomic-clause - READ,WRITE,UPDATE,CAPTURE.
|
|
|
|
void OmpStructureChecker::Leave(const parser::OmpAtomic &) {
|
|
|
|
if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acquire)}) {
|
|
|
|
context_.Say(clause->source,
|
|
|
|
"Clause ACQUIRE is not allowed on the ATOMIC directive"_err_en_US);
|
|
|
|
}
|
|
|
|
if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acq_rel)}) {
|
|
|
|
context_.Say(clause->source,
|
|
|
|
"Clause ACQ_REL is not allowed on the ATOMIC directive"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
2020-10-29 02:13:49 +08:00
|
|
|
// Restrictions specific to each clause are implemented apart from the
|
|
|
|
// generalized restrictions.
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Aligned &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_aligned);
|
2019-07-10 05:08:50 +08:00
|
|
|
|
|
|
|
if (const auto &expr{
|
2021-02-02 02:33:07 +08:00
|
|
|
std::get<std::optional<parser::ScalarIntConstantExpr>>(x.v.t)}) {
|
2020-11-05 16:55:06 +08:00
|
|
|
RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_aligned, *expr);
|
2019-07-10 05:08:50 +08:00
|
|
|
}
|
|
|
|
// 2.8.1 TODO: list-item attribute check
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Defaultmap &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_defaultmap);
|
2019-09-10 18:02:17 +08:00
|
|
|
using VariableCategory = parser::OmpDefaultmapClause::VariableCategory;
|
2021-02-02 02:33:07 +08:00
|
|
|
if (!std::get<std::optional<VariableCategory>>(x.v.t)) {
|
2019-09-10 18:02:17 +08:00
|
|
|
context_.Say(GetContext().clauseSource,
|
2019-09-11 18:23:36 +08:00
|
|
|
"The argument TOFROM:SCALAR must be specified on the DEFAULTMAP "
|
2019-09-10 18:02:17 +08:00
|
|
|
"clause"_err_en_US);
|
|
|
|
}
|
2019-09-09 05:52:43 +08:00
|
|
|
}
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_if);
|
2019-09-05 18:15:23 +08:00
|
|
|
using dirNameModifier = parser::OmpIfClause::DirectiveNameModifier;
|
2019-09-06 01:31:34 +08:00
|
|
|
static std::unordered_map<dirNameModifier, OmpDirectiveSet>
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
dirNameModifierMap{{dirNameModifier::Parallel, llvm::omp::parallelSet},
|
|
|
|
{dirNameModifier::Target, llvm::omp::targetSet},
|
|
|
|
{dirNameModifier::TargetEnterData,
|
|
|
|
{llvm::omp::Directive::OMPD_target_enter_data}},
|
|
|
|
{dirNameModifier::TargetExitData,
|
|
|
|
{llvm::omp::Directive::OMPD_target_exit_data}},
|
|
|
|
{dirNameModifier::TargetData,
|
|
|
|
{llvm::omp::Directive::OMPD_target_data}},
|
|
|
|
{dirNameModifier::TargetUpdate,
|
|
|
|
{llvm::omp::Directive::OMPD_target_update}},
|
|
|
|
{dirNameModifier::Task, {llvm::omp::Directive::OMPD_task}},
|
|
|
|
{dirNameModifier::Taskloop, llvm::omp::taskloopSet}};
|
2019-09-05 18:15:23 +08:00
|
|
|
if (const auto &directiveName{
|
2021-02-02 02:33:07 +08:00
|
|
|
std::get<std::optional<dirNameModifier>>(x.v.t)}) {
|
2019-09-05 18:15:23 +08:00
|
|
|
auto search{dirNameModifierMap.find(*directiveName)};
|
|
|
|
if (search == dirNameModifierMap.end() ||
|
2019-09-06 01:31:34 +08:00
|
|
|
!search->second.test(GetContext().directive)) {
|
2019-09-05 18:15:23 +08:00
|
|
|
context_
|
|
|
|
.Say(GetContext().clauseSource,
|
|
|
|
"Unmatched directive name modifier %s on the IF clause"_err_en_US,
|
|
|
|
parser::ToUpperCaseLetters(
|
|
|
|
parser::OmpIfClause::EnumToString(*directiveName)))
|
|
|
|
.Attach(
|
2019-09-06 01:31:34 +08:00
|
|
|
GetContext().directiveSource, "Cannot apply to directive"_en_US);
|
2019-09-05 18:15:23 +08:00
|
|
|
}
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
2019-09-06 00:33:23 +08:00
|
|
|
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_linear);
|
2019-07-02 04:55:06 +08:00
|
|
|
|
|
|
|
// 2.7 Loop Construct Restriction
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if ((llvm::omp::doSet | llvm::omp::simdSet).test(GetContext().directive)) {
|
2021-02-02 02:33:07 +08:00
|
|
|
if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v.u)) {
|
2019-07-02 04:55:06 +08:00
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"A modifier may not be specified in a LINEAR clause "
|
2019-07-12 06:18:09 +08:00
|
|
|
"on the %s directive"_err_en_US,
|
|
|
|
ContextDirectiveAsFortran());
|
2019-07-02 04:55:06 +08:00
|
|
|
}
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
2020-11-05 16:55:06 +08:00
|
|
|
|
|
|
|
void OmpStructureChecker::CheckAllowedMapTypes(
|
|
|
|
const parser::OmpMapType::Type &type,
|
|
|
|
const std::list<parser::OmpMapType::Type> &allowedMapTypeList) {
|
|
|
|
const auto found{std::find(
|
|
|
|
std::begin(allowedMapTypeList), std::end(allowedMapTypeList), type)};
|
|
|
|
if (found == std::end(allowedMapTypeList)) {
|
|
|
|
std::string commaSeperatedMapTypes;
|
|
|
|
llvm::interleave(
|
|
|
|
allowedMapTypeList.begin(), allowedMapTypeList.end(),
|
|
|
|
[&](const parser::OmpMapType::Type &mapType) {
|
|
|
|
commaSeperatedMapTypes.append(parser::ToUpperCaseLetters(
|
|
|
|
parser::OmpMapType::EnumToString(mapType)));
|
|
|
|
},
|
|
|
|
[&] { commaSeperatedMapTypes.append(", "); });
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Only the %s map types are permitted "
|
|
|
|
"for MAP clauses on the %s directive"_err_en_US,
|
|
|
|
commaSeperatedMapTypes, ContextDirectiveAsFortran());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_map);
|
2021-02-02 02:33:07 +08:00
|
|
|
|
|
|
|
if (const auto &maptype{std::get<std::optional<parser::OmpMapType>>(x.v.t)}) {
|
2019-09-13 22:42:19 +08:00
|
|
|
using Type = parser::OmpMapType::Type;
|
2019-09-16 22:44:31 +08:00
|
|
|
const Type &type{std::get<Type>(maptype->t)};
|
2019-09-13 22:42:19 +08:00
|
|
|
switch (GetContext().directive) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
case llvm::omp::Directive::OMPD_target:
|
|
|
|
case llvm::omp::Directive::OMPD_target_teams:
|
|
|
|
case llvm::omp::Directive::OMPD_target_teams_distribute:
|
|
|
|
case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
|
|
|
|
case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
|
|
|
|
case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
|
2020-11-05 16:55:06 +08:00
|
|
|
case llvm::omp::Directive::OMPD_target_data:
|
|
|
|
CheckAllowedMapTypes(
|
|
|
|
type, {Type::To, Type::From, Type::Tofrom, Type::Alloc});
|
|
|
|
break;
|
|
|
|
case llvm::omp::Directive::OMPD_target_enter_data:
|
|
|
|
CheckAllowedMapTypes(type, {Type::To, Type::Alloc});
|
|
|
|
break;
|
|
|
|
case llvm::omp::Directive::OMPD_target_exit_data:
|
|
|
|
CheckAllowedMapTypes(type, {Type::From, Type::Release, Type::Delete});
|
|
|
|
break;
|
2020-03-29 12:00:16 +08:00
|
|
|
default:
|
|
|
|
break;
|
2019-09-13 22:42:19 +08:00
|
|
|
}
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
2019-07-02 04:55:06 +08:00
|
|
|
|
|
|
|
bool OmpStructureChecker::ScheduleModifierHasType(
|
|
|
|
const parser::OmpScheduleClause &x,
|
|
|
|
const parser::OmpScheduleModifierType::ModType &type) {
|
|
|
|
const auto &modifier{
|
|
|
|
std::get<std::optional<parser::OmpScheduleModifier>>(x.t)};
|
2019-11-10 01:29:31 +08:00
|
|
|
if (modifier) {
|
2019-07-02 04:55:06 +08:00
|
|
|
const auto &modType1{
|
|
|
|
std::get<parser::OmpScheduleModifier::Modifier1>(modifier->t)};
|
|
|
|
const auto &modType2{
|
|
|
|
std::get<std::optional<parser::OmpScheduleModifier::Modifier2>>(
|
|
|
|
modifier->t)};
|
2019-11-10 01:29:31 +08:00
|
|
|
if (modType1.v.v == type || (modType2 && modType2->v.v == type)) {
|
2019-07-02 04:55:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Schedule &x) {
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_schedule);
|
2021-02-02 02:33:07 +08:00
|
|
|
const parser::OmpScheduleClause &scheduleClause = x.v;
|
2019-07-02 04:55:06 +08:00
|
|
|
|
|
|
|
// 2.7 Loop Construct Restriction
|
[flang][openmp] Use common Directive and Clause enum from llvm/Frontend
Summary:
This patch is removing the custom enumeration for OpenMP Directives and Clauses and replace them
with the newly tablegen generated one from llvm/Frontend. This is a first patch and some will follow to share the same
infrastructure where possible. The next patch should use the clauses allowance defined in the tablegen file.
Reviewers: jdoerfert, DavidTruby, sscalpone, kiranchandramohan, ichoyjx
Reviewed By: DavidTruby, ichoyjx
Subscribers: jholewinski, cfe-commits, dblaikie, MaskRay, ymandel, ichoyjx, mgorny, yaxunl, guansong, jfb, sstefan1, aaron.ballman, llvm-commits
Tags: #llvm, #flang, #clang
Differential Revision: https://reviews.llvm.org/D82906
2020-07-02 08:57:11 +08:00
|
|
|
if (llvm::omp::doSet.test(GetContext().directive)) {
|
2021-02-02 02:33:07 +08:00
|
|
|
const auto &kind{std::get<1>(scheduleClause.t)};
|
|
|
|
const auto &chunk{std::get<2>(scheduleClause.t)};
|
2019-11-10 01:29:31 +08:00
|
|
|
if (chunk) {
|
2019-07-02 04:55:06 +08:00
|
|
|
if (kind == parser::OmpScheduleClause::ScheduleType::Runtime ||
|
|
|
|
kind == parser::OmpScheduleClause::ScheduleType::Auto) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"When SCHEDULE clause has %s specified, "
|
|
|
|
"it must not have chunk size specified"_err_en_US,
|
|
|
|
parser::ToUpperCaseLetters(
|
|
|
|
parser::OmpScheduleClause::EnumToString(kind)));
|
|
|
|
}
|
2021-02-02 02:33:07 +08:00
|
|
|
if (const auto &chunkExpr{std::get<std::optional<parser::ScalarIntExpr>>(
|
|
|
|
scheduleClause.t)}) {
|
2020-11-11 17:55:19 +08:00
|
|
|
RequiresPositiveParameter(
|
|
|
|
llvm::omp::Clause::OMPC_schedule, *chunkExpr, "chunk size");
|
|
|
|
}
|
2019-07-02 04:55:06 +08:00
|
|
|
}
|
|
|
|
|
2021-02-02 02:33:07 +08:00
|
|
|
if (ScheduleModifierHasType(scheduleClause,
|
|
|
|
parser::OmpScheduleModifierType::ModType::Nonmonotonic)) {
|
2019-07-02 04:55:06 +08:00
|
|
|
if (kind != parser::OmpScheduleClause::ScheduleType::Dynamic &&
|
|
|
|
kind != parser::OmpScheduleClause::ScheduleType::Guided) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"The NONMONOTONIC modifier can only be specified with "
|
|
|
|
"SCHEDULE(DYNAMIC) or SCHEDULE(GUIDED)"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-26 07:18:51 +08:00
|
|
|
}
|
2020-08-06 02:20:26 +08:00
|
|
|
|
2021-02-02 02:33:07 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
|
2020-11-17 01:56:04 +08:00
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_depend);
|
2021-02-02 02:33:07 +08:00
|
|
|
if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.v.u)}) {
|
2020-11-17 01:56:04 +08:00
|
|
|
const auto &designators{std::get<std::list<parser::Designator>>(inOut->t)};
|
|
|
|
for (const auto &ele : designators) {
|
|
|
|
if (const auto *dataRef{std::get_if<parser::DataRef>(&ele.u)}) {
|
|
|
|
CheckDependList(*dataRef);
|
|
|
|
if (const auto *arr{
|
|
|
|
std::get_if<common::Indirection<parser::ArrayElement>>(
|
|
|
|
&dataRef->u)}) {
|
2021-03-13 01:22:21 +08:00
|
|
|
CheckArraySection(arr->value(), GetLastName(*dataRef),
|
|
|
|
llvm::omp::Clause::OMPC_depend);
|
2020-11-17 01:56:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-31 00:45:09 +08:00
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
|
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_copyprivate);
|
|
|
|
CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_copyprivate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
|
|
|
|
CheckAllowed(llvm::omp::Clause::OMPC_lastprivate);
|
|
|
|
|
|
|
|
DirectivesClauseTriple dirClauseTriple;
|
|
|
|
SymbolSourceMap currSymbols;
|
|
|
|
GetSymbolsInObjectList(x.v, currSymbols);
|
2021-03-14 20:42:30 +08:00
|
|
|
CheckDefinableObjects(currSymbols, GetClauseKindForParserClass(x));
|
2021-01-31 00:45:09 +08:00
|
|
|
|
|
|
|
// Check lastprivate variables in worksharing constructs
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_do,
|
|
|
|
std::make_pair(
|
|
|
|
llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
|
|
|
|
dirClauseTriple.emplace(llvm::omp::Directive::OMPD_sections,
|
|
|
|
std::make_pair(
|
|
|
|
llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet));
|
|
|
|
|
|
|
|
CheckPrivateSymbolsInOuterCxt(
|
2021-03-14 20:42:30 +08:00
|
|
|
currSymbols, dirClauseTriple, GetClauseKindForParserClass(x));
|
2021-01-31 00:45:09 +08:00
|
|
|
}
|
|
|
|
|
2020-08-06 02:20:26 +08:00
|
|
|
llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) {
|
|
|
|
return llvm::omp::getOpenMPClauseName(clause);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::StringRef OmpStructureChecker::getDirectiveName(
|
|
|
|
llvm::omp::Directive directive) {
|
|
|
|
return llvm::omp::getOpenMPDirectiveName(directive);
|
|
|
|
}
|
|
|
|
|
2020-11-17 01:56:04 +08:00
|
|
|
void OmpStructureChecker::CheckDependList(const parser::DataRef &d) {
|
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](const common::Indirection<parser::ArrayElement> &elem) {
|
|
|
|
// Check if the base element is valid on Depend Clause
|
|
|
|
CheckDependList(elem.value().base);
|
|
|
|
},
|
|
|
|
[&](const common::Indirection<parser::StructureComponent> &) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"A variable that is part of another variable "
|
|
|
|
"(such as an element of a structure) but is not an array "
|
|
|
|
"element or an array section cannot appear in a DEPEND "
|
|
|
|
"clause"_err_en_US);
|
|
|
|
},
|
|
|
|
[&](const common::Indirection<parser::CoindexedNamedObject> &) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Coarrays are not supported in DEPEND clause"_err_en_US);
|
|
|
|
},
|
|
|
|
[&](const parser::Name &) { return; },
|
|
|
|
},
|
|
|
|
d.u);
|
|
|
|
}
|
|
|
|
|
2021-03-13 01:22:21 +08:00
|
|
|
// Called from both Reduction and Depend clause.
|
|
|
|
void OmpStructureChecker::CheckArraySection(
|
|
|
|
const parser::ArrayElement &arrayElement, const parser::Name &name,
|
|
|
|
const llvm::omp::Clause clause) {
|
|
|
|
if (!arrayElement.subscripts.empty()) {
|
|
|
|
for (const auto &subscript : arrayElement.subscripts) {
|
|
|
|
if (const auto *triplet{
|
|
|
|
std::get_if<parser::SubscriptTriplet>(&subscript.u)}) {
|
|
|
|
if (std::get<0>(triplet->t) && std::get<1>(triplet->t)) {
|
|
|
|
const auto &lower{std::get<0>(triplet->t)};
|
|
|
|
const auto &upper{std::get<1>(triplet->t)};
|
|
|
|
if (lower && upper) {
|
|
|
|
const auto lval{GetIntValue(lower)};
|
|
|
|
const auto uval{GetIntValue(upper)};
|
|
|
|
if (lval && uval && *uval < *lval) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"'%s' in %s clause"
|
|
|
|
" is a zero size array section"_err_en_US,
|
|
|
|
name.ToString(),
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()));
|
|
|
|
break;
|
|
|
|
} else if (std::get<2>(triplet->t)) {
|
|
|
|
const auto &strideExpr{std::get<2>(triplet->t)};
|
|
|
|
if (strideExpr) {
|
|
|
|
if (clause == llvm::omp::Clause::OMPC_depend) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"Stride should not be specified for array section in "
|
|
|
|
"DEPEND "
|
|
|
|
"clause"_err_en_US);
|
|
|
|
}
|
|
|
|
const auto stride{GetIntValue(strideExpr)};
|
|
|
|
if ((stride && stride != 1)) {
|
|
|
|
context_.Say(GetContext().clauseSource,
|
|
|
|
"A list item that appears in a REDUCTION clause"
|
|
|
|
" should have a contiguous storage array section."_err_en_US,
|
|
|
|
ContextDirectiveAsFortran());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-17 01:56:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-01 00:35:35 +08:00
|
|
|
void OmpStructureChecker::CheckIntentInPointer(
|
|
|
|
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
|
2021-01-31 00:45:09 +08:00
|
|
|
SymbolSourceMap symbols;
|
2020-12-01 00:35:35 +08:00
|
|
|
GetSymbolsInObjectList(objectList, symbols);
|
2021-01-31 00:45:09 +08:00
|
|
|
for (auto it{symbols.begin()}; it != symbols.end(); ++it) {
|
|
|
|
const auto *symbol{it->first};
|
|
|
|
const auto source{it->second};
|
2020-12-01 00:35:35 +08:00
|
|
|
if (IsPointer(*symbol) && IsIntentIn(*symbol)) {
|
2021-01-31 00:45:09 +08:00
|
|
|
context_.Say(source,
|
2020-12-01 00:35:35 +08:00
|
|
|
"Pointer '%s' with the INTENT(IN) attribute may not appear "
|
|
|
|
"in a %s clause"_err_en_US,
|
|
|
|
symbol->name(),
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::GetSymbolsInObjectList(
|
2021-01-31 00:45:09 +08:00
|
|
|
const parser::OmpObjectList &objectList, SymbolSourceMap &symbols) {
|
2020-12-01 00:35:35 +08:00
|
|
|
for (const auto &ompObject : objectList.v) {
|
|
|
|
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
|
|
|
|
if (const auto *symbol{name->symbol}) {
|
|
|
|
if (const auto *commonBlockDetails{
|
|
|
|
symbol->detailsIf<CommonBlockDetails>()}) {
|
|
|
|
for (const auto &object : commonBlockDetails->objects()) {
|
2021-01-31 00:45:09 +08:00
|
|
|
symbols.emplace(&object->GetUltimate(), name->source);
|
2020-12-01 00:35:35 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-01-31 00:45:09 +08:00
|
|
|
symbols.emplace(&symbol->GetUltimate(), name->source);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckDefinableObjects(
|
|
|
|
SymbolSourceMap &symbols, const llvm::omp::Clause clause) {
|
|
|
|
for (auto it{symbols.begin()}; it != symbols.end(); ++it) {
|
|
|
|
const auto *symbol{it->first};
|
|
|
|
const auto source{it->second};
|
|
|
|
if (auto msg{WhyNotModifiable(*symbol, context_.FindScope(source))}) {
|
|
|
|
context_
|
|
|
|
.Say(source,
|
|
|
|
"Variable '%s' on the %s clause is not definable"_err_en_US,
|
|
|
|
symbol->name(),
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(clause).str()))
|
|
|
|
.Attach(source, std::move(*msg), symbol->name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OmpStructureChecker::CheckPrivateSymbolsInOuterCxt(
|
|
|
|
SymbolSourceMap &currSymbols, DirectivesClauseTriple &dirClauseTriple,
|
|
|
|
const llvm::omp::Clause currClause) {
|
|
|
|
SymbolSourceMap enclosingSymbols;
|
|
|
|
auto range{dirClauseTriple.equal_range(GetContext().directive)};
|
|
|
|
for (auto dirIter{range.first}; dirIter != range.second; ++dirIter) {
|
|
|
|
auto enclosingDir{dirIter->second.first};
|
|
|
|
auto enclosingClauseSet{dirIter->second.second};
|
|
|
|
if (auto *enclosingContext{GetEnclosingContextWithDir(enclosingDir)}) {
|
|
|
|
for (auto it{enclosingContext->clauseInfo.begin()};
|
|
|
|
it != enclosingContext->clauseInfo.end(); ++it) {
|
2021-03-14 20:42:30 +08:00
|
|
|
if (enclosingClauseSet.test(it->first)) {
|
|
|
|
if (const auto *ompObjectList{GetOmpObjectList(*it->second)}) {
|
|
|
|
GetSymbolsInObjectList(*ompObjectList, enclosingSymbols);
|
|
|
|
}
|
|
|
|
}
|
2021-01-31 00:45:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the symbols in current context are private in outer context
|
|
|
|
for (auto iter{currSymbols.begin()}; iter != currSymbols.end(); ++iter) {
|
|
|
|
const auto *symbol{iter->first};
|
|
|
|
const auto source{iter->second};
|
|
|
|
if (enclosingSymbols.find(symbol) != enclosingSymbols.end()) {
|
|
|
|
context_.Say(source,
|
|
|
|
"%s variable '%s' is PRIVATE in outer context"_err_en_US,
|
|
|
|
parser::ToUpperCaseLetters(getClauseName(currClause).str()),
|
|
|
|
symbol->name());
|
2020-12-01 00:35:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-13 01:22:21 +08:00
|
|
|
void OmpStructureChecker::CheckWorkshareBlockStmts(
|
|
|
|
const parser::Block &block, parser::CharBlock source) {
|
2021-01-19 20:58:44 +08:00
|
|
|
OmpWorkshareBlockChecker ompWorkshareBlockChecker{context_, source};
|
|
|
|
|
|
|
|
for (auto it{block.begin()}; it != block.end(); ++it) {
|
|
|
|
if (parser::Unwrap<parser::AssignmentStmt>(*it) ||
|
|
|
|
parser::Unwrap<parser::ForallStmt>(*it) ||
|
|
|
|
parser::Unwrap<parser::ForallConstruct>(*it) ||
|
|
|
|
parser::Unwrap<parser::WhereStmt>(*it) ||
|
|
|
|
parser::Unwrap<parser::WhereConstruct>(*it)) {
|
|
|
|
parser::Walk(*it, ompWorkshareBlockChecker);
|
|
|
|
} else if (const auto *ompConstruct{
|
|
|
|
parser::Unwrap<parser::OpenMPConstruct>(*it)}) {
|
|
|
|
if (const auto *ompAtomicConstruct{
|
|
|
|
std::get_if<parser::OpenMPAtomicConstruct>(&ompConstruct->u)}) {
|
|
|
|
// Check if assignment statements in the enclosing OpenMP Atomic
|
|
|
|
// construct are allowed in the Workshare construct
|
|
|
|
parser::Walk(*ompAtomicConstruct, ompWorkshareBlockChecker);
|
|
|
|
} else if (const auto *ompCriticalConstruct{
|
|
|
|
std::get_if<parser::OpenMPCriticalConstruct>(
|
|
|
|
&ompConstruct->u)}) {
|
|
|
|
// All the restrictions on the Workshare construct apply to the
|
|
|
|
// statements in the enclosing critical constructs
|
|
|
|
const auto &criticalBlock{
|
|
|
|
std::get<parser::Block>(ompCriticalConstruct->t)};
|
|
|
|
CheckWorkshareBlockStmts(criticalBlock, source);
|
|
|
|
} else {
|
|
|
|
// Check if OpenMP constructs enclosed in the Workshare construct are
|
|
|
|
// 'Parallel' constructs
|
|
|
|
auto currentDir{llvm::omp::Directive::OMPD_unknown};
|
|
|
|
const OmpDirectiveSet parallelDirSet{
|
|
|
|
llvm::omp::Directive::OMPD_parallel,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_do,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_sections,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_workshare,
|
|
|
|
llvm::omp::Directive::OMPD_parallel_do_simd};
|
|
|
|
|
|
|
|
if (const auto *ompBlockConstruct{
|
|
|
|
std::get_if<parser::OpenMPBlockConstruct>(&ompConstruct->u)}) {
|
|
|
|
const auto &beginBlockDir{
|
|
|
|
std::get<parser::OmpBeginBlockDirective>(ompBlockConstruct->t)};
|
|
|
|
const auto &beginDir{
|
|
|
|
std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
|
|
|
|
currentDir = beginDir.v;
|
|
|
|
} else if (const auto *ompLoopConstruct{
|
|
|
|
std::get_if<parser::OpenMPLoopConstruct>(
|
|
|
|
&ompConstruct->u)}) {
|
|
|
|
const auto &beginLoopDir{
|
|
|
|
std::get<parser::OmpBeginLoopDirective>(ompLoopConstruct->t)};
|
|
|
|
const auto &beginDir{
|
|
|
|
std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
|
|
|
currentDir = beginDir.v;
|
|
|
|
} else if (const auto *ompSectionsConstruct{
|
|
|
|
std::get_if<parser::OpenMPSectionsConstruct>(
|
|
|
|
&ompConstruct->u)}) {
|
|
|
|
const auto &beginSectionsDir{
|
|
|
|
std::get<parser::OmpBeginSectionsDirective>(
|
|
|
|
ompSectionsConstruct->t)};
|
|
|
|
const auto &beginDir{
|
|
|
|
std::get<parser::OmpSectionsDirective>(beginSectionsDir.t)};
|
|
|
|
currentDir = beginDir.v;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parallelDirSet.test(currentDir)) {
|
|
|
|
context_.Say(source,
|
|
|
|
"OpenMP constructs enclosed in WORKSHARE construct may consist "
|
|
|
|
"of ATOMIC, CRITICAL or PARALLEL constructs only"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
context_.Say(source,
|
|
|
|
"The structured block in a WORKSHARE construct may consist of only "
|
|
|
|
"SCALAR or ARRAY assignments, FORALL or WHERE statements, "
|
|
|
|
"FORALL, WHERE, ATOMIC, CRITICAL or PARALLEL constructs"_err_en_US);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 20:42:30 +08:00
|
|
|
const parser::OmpObjectList *OmpStructureChecker::GetOmpObjectList(
|
|
|
|
const parser::OmpClause &clause) {
|
|
|
|
|
|
|
|
// Clauses with OmpObjectList as its data member
|
|
|
|
using MemberObjectListClauses = std::tuple<parser::OmpClause::Copyprivate,
|
|
|
|
parser::OmpClause::Copyin, parser::OmpClause::Firstprivate,
|
|
|
|
parser::OmpClause::From, parser::OmpClause::Lastprivate,
|
|
|
|
parser::OmpClause::Link, parser::OmpClause::Private,
|
|
|
|
parser::OmpClause::Shared, parser::OmpClause::To>;
|
|
|
|
|
|
|
|
// Clauses with OmpObjectList in the tuple
|
|
|
|
using TupleObjectListClauses = std::tuple<parser::OmpClause::Allocate,
|
|
|
|
parser::OmpClause::Map, parser::OmpClause::Reduction>;
|
|
|
|
|
|
|
|
// TODO:: Generate the tuples using TableGen.
|
|
|
|
// Handle other constructs with OmpObjectList such as OpenMPThreadprivate.
|
|
|
|
return std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](const auto &x) -> const parser::OmpObjectList * {
|
|
|
|
using Ty = std::decay_t<decltype(x)>;
|
|
|
|
if constexpr (common::HasMember<Ty, MemberObjectListClauses>) {
|
|
|
|
return &x.v;
|
|
|
|
} else if constexpr (common::HasMember<Ty,
|
|
|
|
TupleObjectListClauses>) {
|
|
|
|
return &(std::get<parser::OmpObjectList>(x.v.t));
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
clause.u);
|
|
|
|
}
|
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
} // namespace Fortran::semantics
|