blob: 98b6c8e452dfad617f668a03e78cb0bc4799df75 [file] [edit]
//===-- lib/Semantics/check-omp-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
//
//===----------------------------------------------------------------------===//
// OpenMP structure validity check list
// 1. invalid clauses on directive
// 2. invalid repeated clauses on directive
// 3. TODO: invalid nesting of regions
#ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
#define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
#include "check-directive-structure.h"
#include "flang/Common/enum-set.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/openmp-directive-sets.h"
#include "flang/Semantics/semantics.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Frontend/OpenMP/OMP.h"
#include <cstddef>
#include <functional>
#include <list>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <variant>
#include <vector>
#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
#include "llvm/Frontend/OpenMP/OMP.inc"
namespace llvm::omp {
static ClauseSet privateSet{
Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
static ClauseSet privateReductionSet{
ClauseSet{Clause::OMPC_reduction} | privateSet};
} // namespace llvm::omp
namespace Fortran::semantics {
struct AnalyzedCondStmt;
namespace omp {
struct LoopSequence;
}
// Mapping from 'Symbol' to 'Source' to keep track of the variables
// used in multiple clauses
using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
std::pair<llvm::omp::Directive, const llvm::omp::ClauseSet>>;
using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive,
llvm::omp::Clause, parser::OmpClause, llvm::omp::ClauseSet>;
template <>
void IterateOverMembers(const llvm::omp::ClauseSet &set,
std::function<void(llvm::omp::Clause)> func);
class OmpStructureChecker : public OmpStructureCheckerBase {
public:
using Base = OmpStructureCheckerBase;
OmpStructureChecker(SemanticsContext &context);
void Enter(const parser::ProgramUnit &);
void Leave(const parser::ProgramUnit &);
void Enter(const parser::MainProgram &);
void Leave(const parser::MainProgram &);
void Enter(const parser::BlockData &);
void Leave(const parser::BlockData &);
void Enter(const parser::Module &);
void Leave(const parser::Module &);
void Enter(const parser::Submodule &);
void Leave(const parser::Submodule &);
void Enter(const parser::SubroutineStmt &);
void Enter(const parser::EndSubroutineStmt &);
void Enter(const parser::FunctionStmt &);
void Enter(const parser::EndFunctionStmt &);
void Enter(const parser::MpSubprogramStmt &);
void Enter(const parser::EndMpSubprogramStmt &);
void Enter(const parser::Block &);
void Leave(const parser::Block &);
void Enter(const parser::BlockConstruct &);
void Leave(const parser::BlockConstruct &);
void Enter(const parser::InternalSubprogram &);
void Enter(const parser::ModuleSubprogram &);
void Enter(const parser::ModuleSubprogramPart &);
void Enter(const parser::InterfaceBody &);
void Leave(const parser::InterfaceBody &);
void Enter(const parser::SpecificationPart &);
void Leave(const parser::SpecificationPart &);
void Enter(const parser::ExecutionPart &);
void Leave(const parser::ExecutionPart &);
void Enter(const parser::OpenMPConstruct &);
void Leave(const parser::OpenMPConstruct &);
void Enter(const parser::OpenMPDeclarativeConstruct &);
void Leave(const parser::OpenMPDeclarativeConstruct &);
void Enter(const parser::OpenMPMisplacedEndDirective &);
void Leave(const parser::OpenMPMisplacedEndDirective &);
void Enter(const parser::OpenMPInvalidDirective &);
void Leave(const parser::OpenMPInvalidDirective &);
void Enter(const parser::OpenMPLoopConstruct &);
void Leave(const parser::OpenMPLoopConstruct &);
void Enter(const parser::OpenMPInteropConstruct &);
void Enter(const parser::OmpBlockConstruct &);
void Leave(const parser::OmpBlockConstruct &);
void Enter(const parser::OmpBeginDirective &);
void Leave(const parser::OmpBeginDirective &);
void Enter(const parser::OpenMPSectionsConstruct &);
void Enter(const parser::OmpDeclareVariantDirective &);
void Enter(const parser::OmpDeclareSimdDirective &);
void Enter(const parser::OmpAllocateDirective &);
void Leave(const parser::OmpAllocateDirective &);
void Enter(const parser::OmpDeclareMapperDirective &);
void Enter(const parser::OmpDeclareReductionDirective &);
void Enter(const parser::OmpDeclareTargetDirective &);
void Leave(const parser::OmpDeclareTargetDirective &);
void Enter(const parser::OpenMPDepobjConstruct &);
void Enter(const parser::OpenMPDispatchConstruct &);
void Enter(const parser::OpenMPAllocatorsConstruct &);
void Enter(const parser::OmpRequiresDirective &);
void Enter(const parser::OmpGroupprivateDirective &);
void Leave(const parser::OmpThreadprivateDirective &);
void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
void Leave(const parser::OpenMPFlushConstruct &);
void Enter(const parser::OpenMPCancelConstruct &);
void Enter(const parser::OpenMPCancellationPointConstruct &);
void Enter(const parser::OpenMPCriticalConstruct &);
void Enter(const parser::OpenMPAtomicConstruct &);
void Enter(const parser::OmpClauseList &);
void Leave(const parser::OmpClauseList &);
void Enter(const parser::OmpClause &);
void Enter(const parser::DoConstruct &);
void Leave(const parser::DoConstruct &);
void Enter(const parser::OmpDirectiveSpecification &);
void Leave(const parser::OmpDirectiveSpecification &);
void Enter(const parser::OmpErrorDirective &);
void Enter(const parser::OmpMetadirectiveDirective &);
void Leave(const parser::OmpMetadirectiveDirective &);
void Enter(const parser::ExecutionPartConstruct &);
void Leave(const parser::OmpClause::When &);
void Enter(const parser::OmpContextSelector &);
void Leave(const parser::OmpContextSelector &);
void Enter(const parser::OmpLoopModifier &);
void Enter(const parser::OmpClause::Apply &);
void Leave(const parser::OmpClause::Apply &);
template <typename A> void Enter(const parser::Statement<A> &);
void Leave(const parser::GotoStmt &);
void Leave(const parser::ComputedGotoStmt &);
void Leave(const parser::ArithmeticIfStmt &);
void Leave(const parser::AssignedGotoStmt &);
void Leave(const parser::AltReturnSpec &);
void Leave(const parser::ErrLabel &);
void Leave(const parser::EndLabel &);
void Leave(const parser::EorLabel &);
void Enter(const parser::OmpClause::Affinity &x);
void Enter(const parser::OmpClause::Align &x);
void Enter(const parser::OmpClause::Aligned &x);
void Enter(const parser::OmpClause::Allocate &x);
void Enter(const parser::OmpClause::Allocator &x);
void Enter(const parser::OmpClause::At &x);
void Enter(const parser::OmpClause::AtomicDefaultMemOrder &x);
void Enter(const parser::OmpClause::CancellationConstructType &x);
void Enter(const parser::OmpClause::Collapse &x);
void Enter(const parser::OmpClause::Copyin &x);
void Enter(const parser::OmpClause::Copyprivate &x);
void Enter(const parser::OmpClause::Defaultmap &x);
void Enter(const parser::OmpClause::Depend &x);
void Enter(const parser::OmpClause::Depth &x);
void Enter(const parser::OmpClause::Destroy &x);
void Enter(const parser::OmpClause::Detach &x);
void Enter(const parser::OmpClause::DeviceSafesync &x);
void Enter(const parser::OmpClause::Device &x);
void Enter(const parser::OmpClause::Doacross &x);
void Enter(const parser::OmpClause::DynamicAllocators &x);
void Enter(const parser::OmpClause::DynGroupprivate &x);
void Enter(const parser::OmpClause::Enter &x);
void Enter(const parser::OmpClause::Firstprivate &x);
void Enter(const parser::OmpClause::From &x);
void Enter(const parser::OmpClause::HasDeviceAddr &x);
void Enter(const parser::OmpClause::Hint &x);
void Enter(const parser::OmpClause::If &x);
void Enter(const parser::OmpClause::InReduction &x);
void Enter(const parser::OmpClause::IsDevicePtr &x);
void Enter(const parser::OmpClause::Lastprivate &x);
void Enter(const parser::OmpClause::Linear &x);
void Enter(const parser::OmpClause::Looprange &x);
void Enter(const parser::OmpClause::Map &x);
void Enter(const parser::OmpClause::Message &x);
void Enter(const parser::OmpClause::NumTeams &x);
void Enter(const parser::OmpClause::NumThreads &x);
void Enter(const parser::OmpClause::OmpxBare &x);
void Enter(const parser::OmpClause::OmpxDynCgroupMem &x);
void Enter(const parser::OmpClause::Ordered &x);
void Enter(const parser::OmpClause::Permutation &x);
void Enter(const parser::OmpClause::Priority &x);
void Enter(const parser::OmpClause::Private &x);
void Enter(const parser::OmpClause::Reduction &x);
void Enter(const parser::OmpClause::ReverseOffload &x);
void Enter(const parser::OmpClause::Safelen &x);
void Enter(const parser::OmpClause::Schedule &x);
void Enter(const parser::OmpClause::SelfMaps &x);
void Enter(const parser::OmpClause::Shared &x);
void Enter(const parser::OmpClause::Simdlen &x);
void Enter(const parser::OmpClause::Sizes &x);
void Enter(const parser::OmpClause::TaskReduction &x);
void Enter(const parser::OmpClause::ThreadLimit &x);
void Enter(const parser::OmpClause::To &x);
void Enter(const parser::OmpClause::UnifiedAddress &x);
void Enter(const parser::OmpClause::UnifiedSharedMemory &x);
void Enter(const parser::OmpClause::UpdateDependObjects &x);
void Enter(const parser::OmpClause::UseDeviceAddr &x);
void Enter(const parser::OmpClause::UseDevicePtr &x);
void Enter(const parser::OmpClause::UsesAllocators &x);
void Enter(const parser::OmpClause::When &x);
private:
using LoopOrConstruct = std::variant<const parser::DoConstruct *,
const parser::OpenMPConstruct *>;
// Most of these functions are defined in check-omp-structure.cpp, but
// some groups have their own files.
// check-omp-atomic.cpp
void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>>, parser::CharBlock);
void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
std::string_view name, bool checkTypeOnPointer = true);
void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
parser::CharBlock, bool checkTypeOnPointer = true);
std::pair<const parser::ExecutionPartConstruct *,
const parser::ExecutionPartConstruct *>
CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
const parser::ExecutionPartConstruct *ec2, parser::CharBlock source);
void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
const SomeExpr &atom, parser::CharBlock source);
void CheckAtomicReadAssignment(
const evaluate::Assignment &read, parser::CharBlock source);
void CheckAtomicWriteAssignment(
const evaluate::Assignment &write, parser::CharBlock source);
std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
const evaluate::Assignment &update, parser::CharBlock source);
std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
parser::CharBlock condSource, const evaluate::Assignment &assign,
parser::CharBlock assignSource);
void CheckAtomicConditionalUpdateStmt(
const AnalyzedCondStmt &update, parser::CharBlock source);
void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
const parser::Block &body, parser::CharBlock source);
void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
const parser::Block &body, parser::CharBlock source);
void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
const parser::Block &body, parser::CharBlock source);
void CheckAtomicConditionalUpdateCapture(
const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
parser::CharBlock source);
void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
// check-omp-loop.cpp
void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
void CheckSIMDNest(const parser::OpenMPConstruct &x);
void CheckRectangularNest(const parser::OmpDirectiveSpecification &spec,
const omp::LoopSequence &nest);
void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
const parser::Name GetLoopIndex(const parser::DoConstruct *x);
void CheckIterationVariables(const parser::OpenMPLoopConstruct &x);
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
void CheckScanModifier(const parser::OmpClause::Reduction &x);
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
void CheckUnrollFullTripCount(const parser::OpenMPLoopConstruct &x);
void BeginMetadirectiveVariantScope();
void EndMetadirectiveVariantScope();
// check-omp-variant.cpp
void CheckMetadirectiveVariantsWithoutLoop(std::size_t firstVariant = 0);
void CheckOmpDeclareVariantDirective(
const parser::OmpDeclareVariantDirective &);
void CheckDeclareVariantUserConditions(const parser::OmpContextSelector &);
const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
const parser::OmpTraitSelector &);
std::optional<llvm::omp::Clause> GetClauseFromProperty(
const parser::OmpTraitProperty &);
void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
void CheckContextSelectorSpecification(const parser::OmpContextSelector &);
void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
void CheckTraitScore(const parser::OmpTraitScore &);
bool VerifyTraitPropertyLists(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
void CheckTraitSelector(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
void CheckTraitADMO(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
void CheckTraitCondition(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
void CheckTraitDeviceNum(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
void CheckTraitRequires(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
void CheckTraitSimd(
const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
// check-omp-structure.cpp
using ClauseIterator =
decltype(std::declval<const parser::OmpClauseList>().v.begin());
bool IsAllowedClause(llvm::omp::Clause clauseId);
bool CheckAllowedClause(llvm::omp::Clause clauseId,
parser::CharBlock clauseSource, llvm::omp::Directive dirId);
void CheckArgumentObjectKind(const parser::OmpClause &x);
void CheckDirectiveSpelling(
parser::CharBlock spelling, llvm::omp::Directive id);
void CheckDirectiveDeprecation(const parser::OpenMPConstruct &x);
void CheckDirectiveInPureProcedure(
parser::CharBlock source, llvm::omp::Directive id);
void CheckClauses(parser::OmpDirectiveName dirName,
llvm::iterator_range<ClauseIterator> beginClauses,
llvm::iterator_range<ClauseIterator> endClauses);
void AnalyzeObject(const parser::OmpObject &object);
std::pair<const parser::OmpClause *, const parser::OmpClause *>
FindMutuallyExclusiveClauses(llvm::omp::ClauseSet exclusive,
const std::vector<const parser::OmpClause *> &clauses);
const parser::OpenMPConstruct *GetCurrentConstruct() const;
void CheckSourceLabel(const parser::Label &);
void CheckLabelContext(const parser::CharBlock, const parser::CharBlock,
const parser::OpenMPConstruct *, const parser::OpenMPConstruct *);
void ClearLabels();
void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
const std::list<parser::Name> &nameList, const parser::CharBlock &item,
const std::string &clauseName);
void CheckMultListItems();
void CheckStructureComponent(
const parser::OmpObject &object, llvm::omp::Clause clauseId);
void CheckStructureComponent(
const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
bool HasInvalidWorksharingNesting(
const parser::OmpDirectiveName &name, const llvm::omp::DirectiveSet &);
bool IsCloselyNestedRegion(const llvm::omp::DirectiveSet &set);
bool IsNestedInDirective(llvm::omp::Directive directive);
bool IsCombinedParallelWorksharing(llvm::omp::Directive directive) const;
bool InTargetRegion();
void HasInvalidTeamsNesting(
const llvm::omp::Directive &dir, const parser::CharBlock &source);
bool HasRequires(llvm::omp::Clause req);
void CheckAllowedMapTypes(
parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
template < //
typename LessTy, typename RangeTy,
typename IterTy = decltype(std::declval<RangeTy>().begin())>
std::optional<IterTy> FindDuplicate(RangeTy &&);
void CheckDependList(const parser::DataRef &);
void CheckDoacross(
const parser::OmpDoacross &doa, llvm::omp::Clause clauseId);
void CheckDimsModifier(parser::CharBlock source, size_t numValues,
const parser::OmpDimsModifier &x);
void CheckTypeParamInquiry(const parser::CharBlock &source,
const parser::OmpObject &object, llvm::omp::Directive dirId);
void CheckTypeParamInquiry(const parser::CharBlock &source,
const parser::OmpObject &object, llvm::omp::Clause clauseId);
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
const parser::OmpObject &object, llvm::StringRef clause = "");
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
const parser::OmpObjectList &objList, llvm::StringRef clause = "");
void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);
void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
void CheckCrayPointee(const parser::OmpObjectList &objectList,
llvm::StringRef clause, bool suggestToUseCrayPointer = true);
void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
void CheckDefaultNoneInAssociatedLoop(
const parser::OmpDirectiveSpecification &, const parser::DoConstruct &,
UnorderedSymbolSet &diagnosed);
void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
void CheckCopyingPolymorphicAllocatable(
SymbolSourceMap &, const llvm::omp::Clause);
void CheckPrivateSymbolsInOuterCxt(
SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
bool CheckTargetBlockOnlyTeams(const parser::Block &);
void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
void CheckIndividualAllocateDirective(
const parser::OmpAllocateDirective &x, bool isExecutable);
void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
void CheckUsesAllocatorsSpec(
const parser::OmpUsesAllocatorsClause::AllocatorSpec &spec);
void CheckUsesAllocatorsTraits(
const parser::OmpTraitsArray &traits, parser::CharBlock source);
void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
void CheckIteratorModifier(const parser::OmpIterator &x);
void CheckTargetNest(const parser::OpenMPConstruct &x);
void CheckTargetUpdate();
void CheckTaskgraph(const parser::OmpBlockConstruct &x);
void CheckDependenceType(const parser::OmpDependenceType::Value &x);
void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
std::optional<llvm::omp::Directive> GetCancelType(
llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
const std::optional<parser::OmpClauseList> &maybeClauses);
void CheckCancellationNest(
const parser::CharBlock &source, llvm::omp::Directive type);
void CheckReductionObjects(
const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
parser::CharBlock source, llvm::omp::Clause clauseId);
void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
const parser::OmpReductionIdentifier &ident);
void CheckReductionModifier(const parser::OmpReductionModifier &);
void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
void CheckSingleConstruct(const parser::OmpBlockConstruct &x);
void CheckMasterNesting(const parser::OmpBlockConstruct &x);
void ChecksOnOrderedAsBlock();
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
void ChecksOnOrderedAsStandalone();
void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
void CheckReductionArraySection(
const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
void CheckArraySection(const parser::ArrayElement &arrayElement,
const parser::Name &name, const llvm::omp::Clause clause);
void CheckLastPartRefForArraySection(
const parser::Designator &designator, llvm::omp::Clause clauseId);
void CheckSharedBindingInOuterContext(
const parser::OmpObjectList &ompObjectList);
void CheckIfContiguous(const parser::OmpObject &object);
const parser::Name *GetObjectName(const parser::OmpObject &object);
void CheckInitOnDepobj(const parser::OpenMPDepobjConstruct &depobj,
const parser::OmpClause &initClause);
void CheckAllowedRequiresClause(llvm::omp::Clause clause);
void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
void CheckTempDescriptorMappings();
void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
int GetDirectiveNest(const int index) { return directiveNest_[index]; }
bool deviceConstructFound_{false};
enum directiveNestType : int {
ApplyNest,
SIMDNest,
TargetBlockOnlyTeams,
TargetNest,
DeclarativeNest,
ContextSelectorNest,
MetadirectiveNest,
LastType = MetadirectiveNest,
};
int directiveNest_[LastType + 1] = {0};
std::set<std::pair<const Symbol *, const Symbol *>> declareVariantPairs_;
// For each variant procedure: its construct-selector-set as an ordered list
// of elements (a leaf construct directive plus a normalized rendering of any
// properties), and the source of the DECLARE VARIANT directive that first
// established the set.
std::map<const Symbol *,
std::pair<
llvm::SmallVector<std::pair<llvm::omp::Directive, std::string>, 4>,
parser::CharBlock>>
declareVariantConstructSets_;
// Tracks the procedures that appear as a base in DECLARE VARIANT.
std::set<const Symbol *> declareVariantBases_;
int allocateDirectiveLevel_{0};
parser::CharBlock visitedAtomicSource_;
// Mapping of directive-name-modifier constituents to the sources of the
// IF clauses that referenced them. If there was no modifier, the entire
// directive is assumed to be listed.
std::map<llvm::omp::Directive, parser::CharBlock> ifLeafs_;
// Track symbols with temporary stack descriptors mapped in TARGET ENTER DATA
// and symbols mapped in TARGET EXIT DATA within the current function scope.
// Used to warn about potential issues with mapping temporary descriptors.
std::multimap<const Symbol *, parser::CharBlock> tempDescriptorEnterMaps_;
std::set<const Symbol *> tempDescriptorExitMaps_;
// Stack of nested DO loops and OpenMP constructs.
// This is used to verify DO loop nest for DOACROSS, and branches into
// and out of OpenMP constructs.
std::vector<LoopOrConstruct> constructStack_;
// Scopes for scoping units.
std::vector<const Scope *> scopeStack_;
// Stack of directive specifications (except for SECTION).
// This is to allow visitor functions to see all specified clauses, since
// they are only recorded in DirectiveContext as they are processed.
std::vector<const parser::OmpDirectiveSpecification *> dirStack_;
enum class PartKind : int {
// There are also other "parts", such as internal-subprogram-part, etc,
// but we're keeping track of these two for now.
SpecificationPart,
ExecutionPart,
};
std::vector<PartKind> partStack_;
struct MetadirectiveLoopVariant {
const parser::traits::OmpContextSelectorSpecification *selector;
const parser::OmpDirectiveSpecification *spec;
bool checkDefaultNoneInAssociatedLoop;
};
std::vector<MetadirectiveLoopVariant> metadirectiveLoopVariants_;
std::vector<std::size_t> metadirectiveVariantScopeStarts_;
const parser::traits::OmpContextSelectorSpecification *currentWhenSelector_{
nullptr};
std::multimap<const parser::Label,
std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
sourceLabels_;
std::map<const parser::Label,
std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
targetLabels_;
parser::CharBlock currentStatementSource_;
};
template <typename A>
void OmpStructureChecker::Enter(const parser::Statement<A> &statement) {
currentStatementSource_ = statement.source;
// Keep track of the labels in all the labelled statements
if (statement.label) {
auto label{statement.label.value()};
// Get the context to check if the labelled statement is in an
// enclosing OpenMP construct
auto *thisConstruct{GetCurrentConstruct()};
targetLabels_.emplace(
label, std::make_pair(currentStatementSource_, thisConstruct));
// Check if a statement that causes a jump to the 'label'
// has already been encountered
auto range{sourceLabels_.equal_range(label)};
for (auto it{range.first}; it != range.second; ++it) {
// Check if both the statement with 'label' and the statement that
// causes a jump to the 'label' are in the same scope
CheckLabelContext(it->second.first, currentStatementSource_,
it->second.second, thisConstruct);
}
}
}
/// Find a duplicate entry in the range, and return an iterator to it.
/// If there are no duplicate entries, return nullopt.
template <typename LessTy, typename RangeTy, typename IterTy>
std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
// Deal with iterators, since the actual elements may be rvalues (i.e.
// have no addresses), for example with custom-constructed ranges that
// are not simple c.begin()..c.end().
std::set<IterTy, LessTy> uniq;
for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
if (!uniq.insert(it).second) {
return it;
}
}
return std::nullopt;
}
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_