llvm-project/flang/lib/Semantics/check-acc-structure.h
khaki3 8470027f25
[flang][acc] Add a semantic check for the validity of nested parallelism (#152225)
This PR implements a semantic checker to ensure the legality of nested
OpenACC parallelism. The following are quotes from Spec 3.3. We need to
disallow loops from having parallelism at the same level as or at a
sub-level of child loops.

>**2.9.2 gang clause**
>[2064] <ins>When the parent compute construct is a parallel
construct</ins>, or on an orphaned loop construct, the gang clause
behaves as follows. (...) The associated dimension is the value of the
dim argument, if it appears, or is dimension one. The dim argument must
be a constant positive integer with value 1, 2, or 3.
>[2112] The region of a loop with a gang(dim:d) clause may not contain a
loop construct with a gang(dim:e) clause where e >= d unless it appears
within a nested compute region.

>[2074] <ins>When the parent compute construct is a kernels
construct</ins>, the gang clause behaves as follows. (...)
>[2148] The region of a loop with the gang clause may not contain
another loop with a gang clause unless within a nested compute region.

>**2.9.3 worker clause**
>[2122]/[2129] The region of a loop with the worker clause may not
contain a loop with the gang or worker clause unless within a nested
compute region.

>**2.9.4 vector clause**
>[2141]/[2148] The region of a loop with the vector clause may not
contain a loop with a gang, worker, or vector clause unless within a
nested compute region.

https://openacc.org/sites/default/files/inline-images/Specification/OpenACC-3.3-final.pdf
2025-08-05 18:21:31 -07:00

123 lines
4.9 KiB
C++

//===-- lib/Semantics/check-acc-structure.h ---------------------*- C++ -*-===//
//
// 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
//
// OpenACC 3.3 structure validity check list
// 1. invalid clauses on directive
// 2. invalid repeated clauses on directive
// 3. invalid nesting of regions
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
#define FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
#include "check-directive-structure.h"
#include "flang/Common/enum-set.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/semantics.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Frontend/OpenACC/ACC.h.inc"
using AccDirectiveSet = Fortran::common::EnumSet<llvm::acc::Directive,
llvm::acc::Directive_enumSize>;
using AccClauseSet =
Fortran::common::EnumSet<llvm::acc::Clause, llvm::acc::Clause_enumSize>;
#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
#include "llvm/Frontend/OpenACC/ACC.inc"
namespace Fortran::semantics {
class AccStructureChecker
: public DirectiveStructureChecker<llvm::acc::Directive, llvm::acc::Clause,
parser::AccClause, llvm::acc::Clause_enumSize> {
public:
AccStructureChecker(SemanticsContext &context)
: DirectiveStructureChecker(context,
#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
#include "llvm/Frontend/OpenACC/ACC.inc"
) {
}
// Construct and directives
void Enter(const parser::OpenACCBlockConstruct &);
void Leave(const parser::OpenACCBlockConstruct &);
void Enter(const parser::OpenACCCombinedConstruct &);
void Leave(const parser::OpenACCCombinedConstruct &);
void Enter(const parser::OpenACCLoopConstruct &);
void Leave(const parser::OpenACCLoopConstruct &);
void Enter(const parser::OpenACCRoutineConstruct &);
void Leave(const parser::OpenACCRoutineConstruct &);
void Enter(const parser::OpenACCStandaloneConstruct &);
void Leave(const parser::OpenACCStandaloneConstruct &);
void Enter(const parser::OpenACCStandaloneDeclarativeConstruct &);
void Leave(const parser::OpenACCStandaloneDeclarativeConstruct &);
void Enter(const parser::OpenACCWaitConstruct &);
void Leave(const parser::OpenACCWaitConstruct &);
void Enter(const parser::OpenACCAtomicConstruct &);
void Leave(const parser::OpenACCAtomicConstruct &);
void Enter(const parser::OpenACCCacheConstruct &);
void Leave(const parser::OpenACCCacheConstruct &);
void Enter(const parser::AccAtomicUpdate &);
void Enter(const parser::AccAtomicCapture &);
void Enter(const parser::AccAtomicWrite &);
void Enter(const parser::AccAtomicRead &);
void Enter(const parser::OpenACCEndConstruct &);
// Clauses
void Leave(const parser::AccClauseList &);
void Enter(const parser::AccClause &);
void Enter(const parser::Module &);
void Enter(const parser::SubroutineSubprogram &);
void Enter(const parser::FunctionSubprogram &);
void Enter(const parser::SeparateModuleSubprogram &);
void Enter(const parser::DoConstruct &);
void Leave(const parser::DoConstruct &);
#define GEN_FLANG_CLAUSE_CHECK_ENTER
#include "llvm/Frontend/OpenACC/ACC.inc"
private:
void CheckAtomicStmt(
const parser::AssignmentStmt &assign, const std::string &construct);
void CheckAtomicUpdateStmt(const parser::AssignmentStmt &assign,
const SomeExpr &updateVar, const SomeExpr *captureVar);
void CheckAtomicCaptureStmt(const parser::AssignmentStmt &assign,
const SomeExpr *updateVar, const SomeExpr &captureVar);
void CheckAtomicWriteStmt(const parser::AssignmentStmt &assign,
const SomeExpr &updateVar, const SomeExpr *captureVar);
void CheckAtomicUpdateVariable(
const parser::Variable &updateVar, const parser::Variable &captureVar);
void CheckAtomicCaptureVariable(
const parser::Variable &captureVar, const parser::Variable &updateVar);
bool CheckAllowedModifier(llvm::acc::Clause clause);
bool IsComputeConstruct(llvm::acc::Directive directive) const;
bool IsLoopConstruct(llvm::acc::Directive directive) const;
std::optional<llvm::acc::Directive> getParentComputeConstruct() const;
bool IsInsideComputeConstruct() const;
bool IsInsideParallelConstruct() const;
void CheckNotInComputeConstruct();
std::optional<std::int64_t> getGangDimensionSize(
DirectiveContext &dirContext);
void CheckNotInSameOrSubLevelLoopConstruct();
void CheckMultipleOccurrenceInDeclare(
const parser::AccObjectList &, llvm::acc::Clause);
void CheckMultipleOccurrenceInDeclare(
const parser::AccObjectListWithModifier &, llvm::acc::Clause);
llvm::StringRef getClauseName(llvm::acc::Clause clause) override;
llvm::StringRef getDirectiveName(llvm::acc::Directive directive) override;
llvm::SmallDenseMap<Symbol *, llvm::acc::Clause> declareSymbols;
unsigned loopNestLevel = 0;
};
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_