brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.3 KiB · 53d4e4e Raw
496 lines · cpp
1//===-- lib/Parser/parse-tree.cpp -----------------------------------------===//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#include "flang/Parser/parse-tree.h"10 11#include "flang/Common/idioms.h"12#include "flang/Common/indirection.h"13#include "flang/Parser/openmp-utils.h"14#include "flang/Parser/tools.h"15#include "flang/Parser/user-state.h"16#include "llvm/ADT/ArrayRef.h"17#include "llvm/Frontend/OpenMP/OMP.h"18#include "llvm/Support/raw_ostream.h"19#include <algorithm>20 21namespace Fortran::parser {22 23// R86724ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)25    : kind{k}, names(std::move(n)) {26  CHECK(kind == common::ImportKind::Default ||27      kind == common::ImportKind::Only || names.empty());28}29 30// R87331CommonStmt::CommonStmt(std::optional<Name> &&name,32    std::list<CommonBlockObject> &&objects, std::list<Block> &&others) {33  blocks.emplace_front(std::move(name), std::move(objects));34  blocks.splice(blocks.end(), std::move(others));35}36 37// R901 designator38bool Designator::EndsInBareName() const {39  return common::visit(40      common::visitors{41          [](const DataRef &dr) {42            return std::holds_alternative<Name>(dr.u) ||43                std::holds_alternative<common::Indirection<StructureComponent>>(44                    dr.u);45          },46          [](const Substring &) { return false; },47      },48      u);49}50 51// R911 data-ref -> part-ref [% part-ref]...52DataRef::DataRef(std::list<PartRef> &&prl) : u{std::move(prl.front().name)} {53  for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {54    PartRef &pr{prl.front()};55    if (!first) {56      u = common::Indirection<StructureComponent>::Make(57          std::move(*this), std::move(pr.name));58    }59    if (!pr.subscripts.empty()) {60      u = common::Indirection<ArrayElement>::Make(61          std::move(*this), std::move(pr.subscripts));62    }63    if (pr.imageSelector) {64      u = common::Indirection<CoindexedNamedObject>::Make(65          std::move(*this), std::move(*pr.imageSelector));66    }67  }68}69 70// R1001 - R1022 expression71Expr::Expr(Designator &&x)72    : u{common::Indirection<Designator>::Make(std::move(x))} {}73Expr::Expr(FunctionReference &&x)74    : u{common::Indirection<FunctionReference>::Make(std::move(x))} {}75 76const std::optional<LoopControl> &DoConstruct::GetLoopControl() const {77  const NonLabelDoStmt &doStmt{78      std::get<Statement<NonLabelDoStmt>>(t).statement};79  const std::optional<LoopControl> &control{80      std::get<std::optional<LoopControl>>(doStmt.t)};81  return control;82}83 84bool DoConstruct::IsDoNormal() const {85  const std::optional<LoopControl> &control{GetLoopControl()};86  return control && std::holds_alternative<LoopControl::Bounds>(control->u);87}88 89bool DoConstruct::IsDoWhile() const {90  const std::optional<LoopControl> &control{GetLoopControl()};91  return control && std::holds_alternative<ScalarLogicalExpr>(control->u);92}93 94bool DoConstruct::IsDoConcurrent() const {95  const std::optional<LoopControl> &control{GetLoopControl()};96  return control && std::holds_alternative<LoopControl::Concurrent>(control->u);97}98 99static Designator MakeArrayElementRef(100    const Name &name, std::list<Expr> &&subscripts) {101  ArrayElement arrayElement{DataRef{Name{name}}, std::list<SectionSubscript>{}};102  for (Expr &expr : subscripts) {103    arrayElement.subscripts.push_back(104        SectionSubscript{Integer{common::Indirection{std::move(expr)}}});105  }106  return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};107}108 109static Designator MakeArrayElementRef(110    StructureComponent &&sc, std::list<Expr> &&subscripts) {111  ArrayElement arrayElement{DataRef{common::Indirection{std::move(sc)}},112      std::list<SectionSubscript>{}};113  for (Expr &expr : subscripts) {114    arrayElement.subscripts.push_back(115        SectionSubscript{Integer{common::Indirection{std::move(expr)}}});116  }117  return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};118}119 120// Set source in any type of node that has it.121template <typename T> T WithSource(CharBlock source, T &&x) {122  x.source = source;123  return std::move(x);124}125 126static Expr ActualArgToExpr(ActualArgSpec &arg) {127  return common::visit(128      common::visitors{129          [&](common::Indirection<Expr> &y) { return std::move(y.value()); },130          [&](common::Indirection<Variable> &y) {131            return common::visit(132                common::visitors{133                    [&](common::Indirection<Designator> &z) {134                      return WithSource(135                          z.value().source, Expr{std::move(z.value())});136                    },137                    [&](common::Indirection<FunctionReference> &z) {138                      return WithSource(139                          z.value().source, Expr{std::move(z.value())});140                    },141                },142                y.value().u);143          },144          [&](auto &) -> Expr { common::die("unexpected type"); },145      },146      std::get<ActualArg>(arg.t).u);147}148 149Designator FunctionReference::ConvertToArrayElementRef() {150  std::list<Expr> args;151  for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {152    args.emplace_back(ActualArgToExpr(arg));153  }154  return common::visit(155      common::visitors{156          [&](const Name &name) {157            return WithSource(158                source, MakeArrayElementRef(name, std::move(args)));159          },160          [&](ProcComponentRef &pcr) {161            return WithSource(source,162                MakeArrayElementRef(std::move(pcr.v.thing), std::move(args)));163          },164      },165      std::get<ProcedureDesignator>(v.t).u);166}167 168StructureConstructor FunctionReference::ConvertToStructureConstructor(169    const semantics::DerivedTypeSpec &derived) {170  Name name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};171  std::list<ComponentSpec> components;172  for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {173    std::optional<Keyword> keyword;174    if (auto &kw{std::get<std::optional<Keyword>>(arg.t)}) {175      keyword.emplace(Keyword{Name{kw->v}});176    }177    components.emplace_back(178        std::move(keyword), ComponentDataSource{ActualArgToExpr(arg)});179  }180  DerivedTypeSpec spec{std::move(name), std::list<TypeParamSpec>{}};181  spec.derivedTypeSpec = &derived;182  return StructureConstructor{std::move(spec), std::move(components)};183}184 185StructureConstructor ArrayElement::ConvertToStructureConstructor(186    const semantics::DerivedTypeSpec &derived) {187  Name name{std::get<parser::Name>(base.u)};188  std::list<ComponentSpec> components;189  for (auto &subscript : subscripts) {190    components.emplace_back(std::optional<Keyword>{},191        ComponentDataSource{std::move(UnwrapRef<Expr>(subscript))});192  }193  DerivedTypeSpec spec{std::move(name), std::list<TypeParamSpec>{}};194  spec.derivedTypeSpec = &derived;195  return StructureConstructor{std::move(spec), std::move(components)};196}197 198Substring ArrayElement::ConvertToSubstring() {199  auto iter{subscripts.begin()};200  CHECK(iter != subscripts.end());201  auto &triplet{std::get<SubscriptTriplet>(iter->u)};202  CHECK(!std::get<2>(triplet.t));203  CHECK(++iter == subscripts.end());204  return Substring{std::move(base),205      SubstringRange{std::get<0>(std::move(triplet.t)),206          std::get<1>(std::move(triplet.t))}};207}208 209// R1544 stmt-function-stmt210// Convert this stmt-function-stmt to an assignment to the result of a211// pointer-valued function call -- which itself will be converted to a212// much more likely array element assignment statement if it needs213// to be.214Statement<ActionStmt> StmtFunctionStmt::ConvertToAssignment() {215  auto &funcName{std::get<Name>(t)};216  auto &funcArgs{std::get<std::list<Name>>(t)};217  auto &funcExpr{std::get<Scalar<Expr>>(t).thing};218  CharBlock source{funcName.source};219  // Extend source to include closing parenthesis220  if (funcArgs.empty()) {221    CHECK(*source.end() == '(');222    source = CharBlock{source.begin(), source.end() + 1};223  }224  std::list<ActualArgSpec> actuals;225  for (const Name &arg : funcArgs) {226    actuals.emplace_back(std::optional<Keyword>{},227        ActualArg{Expr{WithSource(228            arg.source, Designator{DataRef{Name{arg.source, arg.symbol}}})}});229    source.ExtendToCover(arg.source);230  }231  CHECK(*source.end() == ')');232  source = CharBlock{source.begin(), source.end() + 1};233  FunctionReference funcRef{234      Call{ProcedureDesignator{Name{funcName.source, funcName.symbol}},235          std::move(actuals)}};236  funcRef.source = source;237  auto variable{Variable{common::Indirection{std::move(funcRef)}}};238  return Statement{std::nullopt,239      ActionStmt{common::Indirection{240          AssignmentStmt{std::move(variable), std::move(funcExpr)}}}};241}242 243CharBlock Variable::GetSource() const {244  return common::visit(245      common::visitors{246          [&](const common::Indirection<Designator> &des) {247            return des.value().source;248          },249          [&](const common::Indirection<parser::FunctionReference> &call) {250            return call.value().source;251          },252      },253      u);254}255 256llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) {257  return os << x.ToString();258}259 260OmpDirectiveName::OmpDirectiveName(const Verbatim &name) {261  std::string_view nameView{name.source.begin(), name.source.size()};262  std::string nameLower{ToLowerCaseLetters(nameView)};263  // The function getOpenMPDirectiveKind will return OMPD_unknown in two cases:264  // (1) if the given string doesn't match any actual directive, or265  // (2) if the given string was "unknown".266  // The Verbatim(<token>) parser will succeed as long as the given token267  // matches the source.268  // Since using "construct<OmpDirectiveName>(verbatim(...))" will succeed269  // if the verbatim parser succeeds, in order to get OMPD_unknown the270  // token given to Verbatim must be invalid. Because it's an internal issue271  // asserting is ok.272  v = llvm::omp::getOpenMPDirectiveKind(nameLower);273  assert(v != llvm::omp::Directive::OMPD_unknown && "Invalid directive name");274  source = name.source;275}276 277OmpDependenceType::Value OmpDoacross::GetDepType() const {278  return common::visit( //279      common::visitors{280          [](const OmpDoacross::Sink &) {281            return OmpDependenceType::Value::Sink;282          },283          [](const OmpDoacross::Source &) {284            return OmpDependenceType::Value::Source;285          },286      },287      u);288}289 290OmpTaskDependenceType::Value OmpDependClause::TaskDep::GetTaskDepType() const {291  using Modifier = OmpDependClause::TaskDep::Modifier;292  auto &modifiers{std::get<std::optional<std::list<Modifier>>>(t)};293  if (modifiers) {294    for (auto &m : *modifiers) {295      if (auto *dep{std::get_if<OmpTaskDependenceType>(&m.u)}) {296        return dep->v;297      }298    }299    llvm_unreachable("expecting OmpTaskDependenceType in TaskDep");300  } else {301    llvm_unreachable("expecting modifiers on OmpDependClause::TaskDep");302  }303}304 305std::string OmpTraitSelectorName::ToString() const {306  return common::visit( //307      common::visitors{308          [&](Value v) { //309            return std::string(EnumToString(v));310          },311          [&](llvm::omp::Directive d) {312            return llvm::omp::getOpenMPDirectiveName(313                d, llvm::omp::FallbackVersion)314                .str();315          },316          [&](const std::string &s) { //317            return s;318          },319      },320      u);321}322 323std::string OmpTraitSetSelectorName::ToString() const {324  return std::string(EnumToString(v));325}326 327llvm::omp::Clause OpenMPAtomicConstruct::GetKind() const {328  const OmpDirectiveSpecification &dirSpec{std::get<OmpBeginDirective>(t)};329  for (auto &clause : dirSpec.Clauses().v) {330    switch (clause.Id()) {331    case llvm::omp::Clause::OMPC_read:332    case llvm::omp::Clause::OMPC_write:333    case llvm::omp::Clause::OMPC_update:334      return clause.Id();335    default:336      break;337    }338  }339  return llvm::omp::Clause::OMPC_update;340}341 342bool OpenMPAtomicConstruct::IsCapture() const {343  const OmpDirectiveSpecification &dirSpec{std::get<OmpBeginDirective>(t)};344  return llvm::any_of(dirSpec.Clauses().v, [](auto &clause) {345    return clause.Id() == llvm::omp::Clause::OMPC_capture;346  });347}348 349bool OpenMPAtomicConstruct::IsCompare() const {350  const OmpDirectiveSpecification &dirSpec{std::get<OmpBeginDirective>(t)};351  return llvm::any_of(dirSpec.Clauses().v, [](auto &clause) {352    return clause.Id() == llvm::omp::Clause::OMPC_compare;353  });354}355} // namespace Fortran::parser356 357template <typename C> static llvm::omp::Clause getClauseIdForClass(C &&) {358  using namespace Fortran;359  using A = llvm::remove_cvref_t<C>; // A is referenced in OMP.inc360  // The code included below contains a sequence of checks like the following361  // for each OpenMP clause362  //   if constexpr (std::is_same_v<A, parser::OmpClause::AcqRel>)363  //     return llvm::omp::Clause::OMPC_acq_rel;364  //   [...]365#define GEN_FLANG_CLAUSE_PARSER_KIND_MAP366#include "llvm/Frontend/OpenMP/OMP.inc"367}368 369namespace Fortran::parser {370llvm::omp::Clause OmpClause::Id() const {371  return std::visit([](auto &&s) { return getClauseIdForClass(s); }, u);372}373 374bool OmpDirectiveName::IsExecutionPart() const {375  // Can the directive appear in the execution part of the program.376  llvm::omp::Directive id{v};377  switch (llvm::omp::getDirectiveCategory(id)) {378  case llvm::omp::Category::Executable:379    return true;380  case llvm::omp::Category::Declarative:381    switch (id) {382    case llvm::omp::Directive::OMPD_allocate:383      return true;384    default:385      return false;386    }387    break;388  case llvm::omp::Category::Informational:389    switch (id) {390    case llvm::omp::Directive::OMPD_assume:391      return true;392    default:393      return false;394    }395    break;396  case llvm::omp::Category::Meta:397    return true;398  case llvm::omp::Category::Subsidiary:399    switch (id) {400    // TODO: case llvm::omp::Directive::OMPD_task_iteration:401    case llvm::omp::Directive::OMPD_section:402    case llvm::omp::Directive::OMPD_scan:403      return true;404    default:405      return false;406    }407    break;408  case llvm::omp::Category::Utility:409    switch (id) {410    case llvm::omp::Directive::OMPD_error:411    case llvm::omp::Directive::OMPD_nothing:412      return true;413    default:414      return false;415    }416    break;417  }418  return false;419}420 421const OmpArgumentList &OmpDirectiveSpecification::Arguments() const {422  static OmpArgumentList empty{decltype(OmpArgumentList::v){}};423  if (auto &arguments = std::get<std::optional<OmpArgumentList>>(t)) {424    return *arguments;425  }426  return empty;427}428 429const OmpClauseList &OmpDirectiveSpecification::Clauses() const {430  static OmpClauseList empty{decltype(OmpClauseList::v){}};431  if (auto &clauses = std::get<std::optional<OmpClauseList>>(t)) {432    return *clauses;433  }434  return empty;435}436 437const DoConstruct *OpenMPLoopConstruct::GetNestedLoop() const {438  auto getFromBlock{[](const Block &body, auto self) -> const DoConstruct * {439    for (auto &stmt : body) {440      if (auto *block{Unwrap<BlockConstruct>(&stmt)}) {441        return self(std::get<Block>(block->t), self);442      }443      if (auto *loop{Unwrap<DoConstruct>(&stmt)}) {444        return loop;445      }446    }447    return nullptr;448  }};449 450  return getFromBlock(std::get<Block>(t), getFromBlock);451}452 453const OpenMPLoopConstruct *OpenMPLoopConstruct::GetNestedConstruct() const {454  auto getFromBlock{455      [](const Block &body, auto self) -> const OpenMPLoopConstruct * {456        for (auto &stmt : body) {457          if (auto *block{Unwrap<BlockConstruct>(&stmt)}) {458            return self(std::get<Block>(block->t), self);459          }460          if (auto *omp{Unwrap<OpenMPLoopConstruct>(&stmt)}) {461            return omp;462          }463        }464        return nullptr;465      }};466 467  return getFromBlock(std::get<Block>(t), getFromBlock);468}469 470static bool InitCharBlocksFromStrings(llvm::MutableArrayRef<CharBlock> blocks,471    llvm::ArrayRef<std::string> strings) {472  for (auto [i, n] : llvm::enumerate(strings)) {473    blocks[i] = CharBlock(n);474  }475  return true;476}477 478// The names should have static storage duration. Keep these names479// in a sigle place.480llvm::ArrayRef<CharBlock> OmpCombinerExpression::Variables() {481  static std::string names[]{"omp_in", "omp_out"};482  static CharBlock vars[std::size(names)];483 484  [[maybe_unused]] static bool init = InitCharBlocksFromStrings(vars, names);485  return vars;486}487 488llvm::ArrayRef<CharBlock> OmpInitializerExpression::Variables() {489  static std::string names[]{"omp_orig", "omp_priv"};490  static CharBlock vars[std::size(names)];491 492  [[maybe_unused]] static bool init = InitCharBlocksFromStrings(vars, names);493  return vars;494}495} // namespace Fortran::parser496