brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.7 KiB · a99d7c3 Raw
427 lines · c
1//===-- lib/Semantics/check-omp-structure.h ---------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// OpenMP structure validity check list10//    1. invalid clauses on directive11//    2. invalid repeated clauses on directive12//    3. TODO: invalid nesting of regions13 14#ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_15#define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_16 17#include "check-directive-structure.h"18#include "flang/Common/enum-set.h"19#include "flang/Parser/parse-tree.h"20#include "flang/Semantics/openmp-directive-sets.h"21#include "flang/Semantics/semantics.h"22 23using OmpClauseSet =24    Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;25 26#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS27#include "llvm/Frontend/OpenMP/OMP.inc"28 29namespace llvm {30namespace omp {31static OmpClauseSet privateSet{32    Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};33static OmpClauseSet privateReductionSet{34    OmpClauseSet{Clause::OMPC_reduction} | privateSet};35// omp.td cannot differentiate allowed/not allowed clause list for few36// directives for fortran. nowait is not allowed on begin directive clause list37// for below list of directives. Directives with conflicting list of clauses are38// included in below list.39static const OmpDirectiveSet noWaitClauseNotAllowedSet{40    Directive::OMPD_do,41    Directive::OMPD_do_simd,42    Directive::OMPD_sections,43    Directive::OMPD_single,44    Directive::OMPD_workshare,45};46} // namespace omp47} // namespace llvm48 49namespace Fortran::semantics {50struct AnalyzedCondStmt;51 52// Mapping from 'Symbol' to 'Source' to keep track of the variables53// used in multiple clauses54using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;55// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>56using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,57    std::pair<llvm::omp::Directive, const OmpClauseSet>>;58 59using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive,60    llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;61 62class OmpStructureChecker : public OmpStructureCheckerBase {63public:64  using Base = OmpStructureCheckerBase;65 66  OmpStructureChecker(SemanticsContext &context);67 68  using llvmOmpClause = const llvm::omp::Clause;69 70  bool Enter(const parser::MainProgram &);71  void Leave(const parser::MainProgram &);72  bool Enter(const parser::BlockData &);73  void Leave(const parser::BlockData &);74  bool Enter(const parser::Module &);75  void Leave(const parser::Module &);76  bool Enter(const parser::Submodule &);77  void Leave(const parser::Submodule &);78  bool Enter(const parser::SubroutineStmt &);79  bool Enter(const parser::EndSubroutineStmt &);80  bool Enter(const parser::FunctionStmt &);81  bool Enter(const parser::EndFunctionStmt &);82  bool Enter(const parser::BlockConstruct &);83  void Leave(const parser::BlockConstruct &);84 85  void Enter(const parser::SpecificationPart &);86  void Leave(const parser::SpecificationPart &);87  void Enter(const parser::ExecutionPart &);88  void Leave(const parser::ExecutionPart &);89 90  void Enter(const parser::OpenMPConstruct &);91  void Leave(const parser::OpenMPConstruct &);92  void Enter(const parser::OpenMPInteropConstruct &);93  void Leave(const parser::OpenMPInteropConstruct &);94  void Enter(const parser::OpenMPDeclarativeConstruct &);95  void Leave(const parser::OpenMPDeclarativeConstruct &);96 97  void Enter(const parser::OpenMPMisplacedEndDirective &);98  void Leave(const parser::OpenMPMisplacedEndDirective &);99  void Enter(const parser::OpenMPInvalidDirective &);100  void Leave(const parser::OpenMPInvalidDirective &);101 102  void Enter(const parser::OpenMPLoopConstruct &);103  void Leave(const parser::OpenMPLoopConstruct &);104  void Enter(const parser::OmpEndLoopDirective &);105  void Leave(const parser::OmpEndLoopDirective &);106 107  void Enter(const parser::OpenMPAssumeConstruct &);108  void Leave(const parser::OpenMPAssumeConstruct &);109  void Enter(const parser::OpenMPDeclarativeAssumes &);110  void Leave(const parser::OpenMPDeclarativeAssumes &);111  void Enter(const parser::OmpBlockConstruct &);112  void Leave(const parser::OmpBlockConstruct &);113  void Leave(const parser::OmpBeginDirective &);114  void Enter(const parser::OmpEndDirective &);115  void Leave(const parser::OmpEndDirective &);116 117  void Enter(const parser::OpenMPSectionsConstruct &);118  void Leave(const parser::OpenMPSectionsConstruct &);119  void Enter(const parser::OmpEndSectionsDirective &);120  void Leave(const parser::OmpEndSectionsDirective &);121 122  void Enter(const parser::OmpDeclareVariantDirective &);123  void Leave(const parser::OmpDeclareVariantDirective &);124  void Enter(const parser::OpenMPDeclareSimdConstruct &);125  void Leave(const parser::OpenMPDeclareSimdConstruct &);126  void Enter(const parser::OmpAllocateDirective &);127  void Leave(const parser::OmpAllocateDirective &);128  void Enter(const parser::OpenMPDeclareMapperConstruct &);129  void Leave(const parser::OpenMPDeclareMapperConstruct &);130  void Enter(const parser::OpenMPDeclareReductionConstruct &);131  void Leave(const parser::OpenMPDeclareReductionConstruct &);132  void Enter(const parser::OpenMPDeclareTargetConstruct &);133  void Leave(const parser::OpenMPDeclareTargetConstruct &);134  void Enter(const parser::OpenMPDepobjConstruct &);135  void Leave(const parser::OpenMPDepobjConstruct &);136  void Enter(const parser::OpenMPDispatchConstruct &);137  void Leave(const parser::OpenMPDispatchConstruct &);138  void Enter(const parser::OmpErrorDirective &);139  void Leave(const parser::OmpErrorDirective &);140  void Enter(const parser::OmpNothingDirective &);141  void Leave(const parser::OmpNothingDirective &);142  void Enter(const parser::OpenMPAllocatorsConstruct &);143  void Leave(const parser::OpenMPAllocatorsConstruct &);144  void Enter(const parser::OpenMPRequiresConstruct &);145  void Leave(const parser::OpenMPRequiresConstruct &);146  void Enter(const parser::OpenMPGroupprivate &);147  void Leave(const parser::OpenMPGroupprivate &);148  void Enter(const parser::OpenMPThreadprivate &);149  void Leave(const parser::OpenMPThreadprivate &);150 151  void Enter(const parser::OpenMPSimpleStandaloneConstruct &);152  void Leave(const parser::OpenMPSimpleStandaloneConstruct &);153  void Enter(const parser::OpenMPFlushConstruct &);154  void Leave(const parser::OpenMPFlushConstruct &);155  void Enter(const parser::OpenMPCancelConstruct &);156  void Leave(const parser::OpenMPCancelConstruct &);157  void Enter(const parser::OpenMPCancellationPointConstruct &);158  void Leave(const parser::OpenMPCancellationPointConstruct &);159  void Enter(const parser::OpenMPCriticalConstruct &);160  void Leave(const parser::OpenMPCriticalConstruct &);161  void Enter(const parser::OpenMPAtomicConstruct &);162  void Leave(const parser::OpenMPAtomicConstruct &);163 164  void Leave(const parser::OmpClauseList &);165  void Enter(const parser::OmpClause &);166 167  void Enter(const parser::DoConstruct &);168  void Leave(const parser::DoConstruct &);169 170  void Enter(const parser::OmpDirectiveSpecification &);171  void Leave(const parser::OmpDirectiveSpecification &);172 173  void Enter(const parser::OmpMetadirectiveDirective &);174  void Leave(const parser::OmpMetadirectiveDirective &);175 176  void Enter(const parser::OmpContextSelector &);177  void Leave(const parser::OmpContextSelector &);178 179#define GEN_FLANG_CLAUSE_CHECK_ENTER180#include "llvm/Frontend/OpenMP/OMP.inc"181 182private:183  bool CheckAllowedClause(llvmOmpClause clause);184  void CheckVariableListItem(const SymbolSourceMap &symbols);185  void CheckDirectiveSpelling(186      parser::CharBlock spelling, llvm::omp::Directive id);187  void AnalyzeObject(const parser::OmpObject &object);188  void AnalyzeObjects(const parser::OmpObjectList &objects);189  void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,190      const std::list<parser::Name> &nameList, const parser::CharBlock &item,191      const std::string &clauseName);192  void CheckMultListItems();193  void CheckStructureComponent(194      const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);195  bool HasInvalidWorksharingNesting(196      const parser::CharBlock &, const OmpDirectiveSet &);197  bool IsCloselyNestedRegion(const OmpDirectiveSet &set);198  bool IsNestedInDirective(llvm::omp::Directive directive);199  bool InTargetRegion();200  void HasInvalidTeamsNesting(201      const llvm::omp::Directive &dir, const parser::CharBlock &source);202  void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);203  void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);204  bool HasRequires(llvm::omp::Clause req);205  // specific clause related206  void CheckAllowedMapTypes(207      parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);208 209  const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(210      const parser::OmpTraitSelector &);211  std::optional<llvm::omp::Clause> GetClauseFromProperty(212      const parser::OmpTraitProperty &);213 214  void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);215  void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);216  void CheckTraitScore(const parser::OmpTraitScore &);217  bool VerifyTraitPropertyLists(218      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);219  void CheckTraitSelector(220      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);221  void CheckTraitADMO(222      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);223  void CheckTraitCondition(224      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);225  void CheckTraitDeviceNum(226      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);227  void CheckTraitRequires(228      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);229  void CheckTraitSimd(230      const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);231 232  llvm::StringRef getClauseName(llvm::omp::Clause clause) override;233  llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;234 235  template < //236      typename LessTy, typename RangeTy,237      typename IterTy = decltype(std::declval<RangeTy>().begin())>238  std::optional<IterTy> FindDuplicate(RangeTy &&);239 240  void CheckDependList(const parser::DataRef &);241  void CheckDependArraySection(242      const common::Indirection<parser::ArrayElement> &, const parser::Name &);243  void CheckDoacross(const parser::OmpDoacross &doa);244  bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);245  void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,246      const parser::OmpObject &obj, llvm::StringRef clause = "");247  void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,248      const parser::OmpObjectList &objList, llvm::StringRef clause = "");249  void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);250  void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);251  void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);252  void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);253  void CheckSymbolName(254      const parser::CharBlock &source, const parser::OmpObject &object);255  void CheckSymbolNames(256      const parser::CharBlock &source, const parser::OmpObjectList &objList);257  void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);258  void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);259  void CheckCrayPointee(const parser::OmpObjectList &objectList,260      llvm::StringRef clause, bool suggestToUseCrayPointer = true);261  void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);262  void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);263  void CheckCopyingPolymorphicAllocatable(264      SymbolSourceMap &, const llvm::omp::Clause);265  void CheckPrivateSymbolsInOuterCxt(266      SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);267  const parser::Name GetLoopIndex(const parser::DoConstruct *x);268  void SetLoopInfo(const parser::OpenMPLoopConstruct &x);269  void CheckIsLoopIvPartOfClause(270      llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);271  bool CheckTargetBlockOnlyTeams(const parser::Block &);272  void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);273  void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);274  void CheckIndividualAllocateDirective(275      const parser::OmpAllocateDirective &x, bool isExecutable);276  void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);277 278  void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);279  void CheckIteratorModifier(const parser::OmpIterator &x);280  void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);281  void CheckDoWhile(const parser::OpenMPLoopConstruct &x);282  void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);283  template <typename T, typename D> bool IsOperatorValid(const T &, const D &);284 285  void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,286      llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>>, parser::CharBlock);287  void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);288  void CheckAtomicType(SymbolRef sym, parser::CharBlock source,289      std::string_view name, bool checkTypeOnPointer = true);290  void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,291      parser::CharBlock, bool checkTypeOnPointer = true);292  std::pair<const parser::ExecutionPartConstruct *,293      const parser::ExecutionPartConstruct *>294  CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,295      const parser::ExecutionPartConstruct *ec2, parser::CharBlock source);296  void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,297      const SomeExpr &atom, parser::CharBlock source);298  void CheckAtomicReadAssignment(299      const evaluate::Assignment &read, parser::CharBlock source);300  void CheckAtomicWriteAssignment(301      const evaluate::Assignment &write, parser::CharBlock source);302  std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(303      const evaluate::Assignment &update, parser::CharBlock source);304  std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,305      const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);306  void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,307      parser::CharBlock condSource, const evaluate::Assignment &assign,308      parser::CharBlock assignSource);309  void CheckAtomicConditionalUpdateStmt(310      const AnalyzedCondStmt &update, parser::CharBlock source);311  void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,312      const parser::Block &body, parser::CharBlock source);313  void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,314      const parser::Block &body, parser::CharBlock source);315  void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,316      const parser::Block &body, parser::CharBlock source);317  void CheckAtomicConditionalUpdateCapture(318      const parser::OpenMPAtomicConstruct &x, const parser::Block &body,319      parser::CharBlock source);320  void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);321  void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);322  void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);323 324  void CheckLooprangeBounds(const parser::OpenMPLoopConstruct &x);325  void CheckNestedFuse(const parser::OpenMPLoopConstruct &x);326  void CheckDistLinear(const parser::OpenMPLoopConstruct &x);327  void CheckSIMDNest(const parser::OpenMPConstruct &x);328  void CheckNestedBlock(const parser::OpenMPLoopConstruct &x,329      const parser::Block &body, size_t &nestedCount);330  void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);331  void CheckFullUnroll(const parser::OpenMPLoopConstruct &x);332  void CheckTargetNest(const parser::OpenMPConstruct &x);333  void CheckTargetUpdate();334  void CheckTaskgraph(const parser::OmpBlockConstruct &x);335  void CheckDependenceType(const parser::OmpDependenceType::Value &x);336  void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);337  std::optional<llvm::omp::Directive> GetCancelType(338      llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,339      const std::optional<parser::OmpClauseList> &maybeClauses);340  void CheckCancellationNest(341      const parser::CharBlock &source, llvm::omp::Directive type);342  std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);343  void CheckReductionObjects(344      const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);345  bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,346      parser::CharBlock source, llvm::omp::Clause clauseId);347  void CheckReductionObjectTypes(const parser::OmpObjectList &objects,348      const parser::OmpReductionIdentifier &ident);349  void CheckReductionModifier(const parser::OmpReductionModifier &);350  void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);351  void CheckMasterNesting(const parser::OmpBlockConstruct &x);352  void ChecksOnOrderedAsBlock();353  void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);354  void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);355  void ChecksOnOrderedAsStandalone();356  void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);357  void CheckReductionArraySection(358      const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);359  void CheckArraySection(const parser::ArrayElement &arrayElement,360      const parser::Name &name, const llvm::omp::Clause clause);361  void CheckSharedBindingInOuterContext(362      const parser::OmpObjectList &ompObjectList);363  void CheckIfContiguous(const parser::OmpObject &object);364  const parser::Name *GetObjectName(const parser::OmpObject &object);365 366  void CheckAllowedRequiresClause(llvmOmpClause clause);367  bool deviceConstructFound_{false};368 369  void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);370 371  void EnterDirectiveNest(const int index) { directiveNest_[index]++; }372  void ExitDirectiveNest(const int index) { directiveNest_[index]--; }373  int GetDirectiveNest(const int index) { return directiveNest_[index]; }374  inline void ErrIfAllocatableVariable(const parser::Variable &);375  inline void ErrIfLHSAndRHSSymbolsMatch(376      const parser::Variable &, const parser::Expr &);377  inline void ErrIfNonScalarAssignmentStmt(378      const parser::Variable &, const parser::Expr &);379  enum directiveNestType : int {380    SIMDNest,381    TargetBlockOnlyTeams,382    TargetNest,383    DeclarativeNest,384    ContextSelectorNest,385    MetadirectiveNest,386    LastType = MetadirectiveNest,387  };388  int directiveNest_[LastType + 1] = {0};389 390  int allocateDirectiveLevel{0};391  parser::CharBlock visitedAtomicSource_;392  SymbolSourceMap deferredNonVariables_;393 394  using LoopConstruct = std::variant<const parser::DoConstruct *,395      const parser::OpenMPLoopConstruct *>;396  std::vector<LoopConstruct> loopStack_;397  // Scopes for scoping units.398  std::vector<const Scope *> scopeStack_;399 400  enum class PartKind : int {401    // There are also other "parts", such as internal-subprogram-part, etc,402    // but we're keeping track of these two for now.403    SpecificationPart,404    ExecutionPart,405  };406  std::vector<PartKind> partStack_;407};408 409/// Find a duplicate entry in the range, and return an iterator to it.410/// If there are no duplicate entries, return nullopt.411template <typename LessTy, typename RangeTy, typename IterTy>412std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {413  // Deal with iterators, since the actual elements may be rvalues (i.e.414  // have no addresses), for example with custom-constructed ranges that415  // are not simple c.begin()..c.end().416  std::set<IterTy, LessTy> uniq;417  for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {418    if (!uniq.insert(it).second) {419      return it;420    }421  }422  return std::nullopt;423}424 425} // namespace Fortran::semantics426#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_427