brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.5 KiB · ab2ed06 Raw
232 lines · cpp
1//===-- flang/Parser/openmp-utils.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// Common OpenMP utilities.10//11//===----------------------------------------------------------------------===//12 13#include "flang/Parser/openmp-utils.h"14 15#include "flang/Common/indirection.h"16#include "flang/Common/template.h"17#include "flang/Common/visit.h"18#include "flang/Parser/tools.h"19 20#include <tuple>21#include <type_traits>22#include <variant>23 24namespace Fortran::parser::omp {25 26const OpenMPDeclarativeConstruct *GetOmp(const DeclarationConstruct &x) {27  if (auto *y = std::get_if<SpecificationConstruct>(&x.u)) {28    if (auto *z{std::get_if<common::Indirection<OpenMPDeclarativeConstruct>>(29            &y->u)}) {30      return &z->value();31    }32  }33  return nullptr;34}35 36const OpenMPConstruct *GetOmp(const ExecutionPartConstruct &x) {37  if (auto *y{std::get_if<ExecutableConstruct>(&x.u)}) {38    if (auto *z{std::get_if<common::Indirection<OpenMPConstruct>>(&y->u)}) {39      return &z->value();40    }41  }42  return nullptr;43}44 45const OpenMPLoopConstruct *GetOmpLoop(const ExecutionPartConstruct &x) {46  if (auto *construct{GetOmp(x)}) {47    if (auto *omp{std::get_if<OpenMPLoopConstruct>(&construct->u)}) {48      return omp;49    }50  }51  return nullptr;52}53const DoConstruct *GetDoConstruct(const ExecutionPartConstruct &x) {54  if (auto *y{std::get_if<ExecutableConstruct>(&x.u)}) {55    if (auto *z{std::get_if<common::Indirection<DoConstruct>>(&y->u)}) {56      return &z->value();57    }58  }59  return nullptr;60}61 62// Get the Label from a Statement<...> contained in an ExecutionPartConstruct,63// or std::nullopt, if there is no Statement<...> contained in there.64template <typename T>65static std::optional<Label> GetStatementLabelHelper(const T &stmt) {66  if constexpr (IsStatement<T>::value) {67    return stmt.label;68  } else if constexpr (WrapperTrait<T>) {69    return GetStatementLabelHelper(stmt.v);70  } else if constexpr (UnionTrait<T>) {71    return common::visit(72        [&](auto &&s) { return GetStatementLabelHelper(s); }, stmt.u);73  }74  return std::nullopt;75}76 77std::optional<Label> GetStatementLabel(const ExecutionPartConstruct &x) {78  return GetStatementLabelHelper(x);79}80 81static std::optional<Label> GetFinalLabel(const Block &x) {82  if (!x.empty()) {83    const ExecutionPartConstruct &last{x.back()};84    if (auto *omp{Unwrap<OpenMPConstruct>(last)}) {85      return GetFinalLabel(*omp);86    } else if (auto *doLoop{Unwrap<DoConstruct>(last)}) {87      return GetFinalLabel(std::get<Block>(doLoop->t));88    } else {89      return GetStatementLabel(x.back());90    }91  } else {92    return std::nullopt;93  }94}95 96std::optional<Label> GetFinalLabel(const OpenMPConstruct &x) {97  return common::visit(98      [](auto &&s) -> std::optional<Label> {99        using TypeS = llvm::remove_cvref_t<decltype(s)>;100        if constexpr (std::is_same_v<TypeS, OpenMPSectionsConstruct>) {101          auto &list{std::get<std::list<OpenMPConstruct>>(s.t)};102          if (!list.empty()) {103            return GetFinalLabel(list.back());104          } else {105            return std::nullopt;106          }107        } else if constexpr ( //108            std::is_same_v<TypeS, OpenMPLoopConstruct> ||109            std::is_same_v<TypeS, OpenMPSectionConstruct> ||110            std::is_base_of_v<OmpBlockConstruct, TypeS>) {111          return GetFinalLabel(std::get<Block>(s.t));112        } else {113          return std::nullopt;114        }115      },116      x.u);117}118 119const OmpObjectList *GetOmpObjectList(const OmpClause &clause) {120  // Clauses with OmpObjectList as its data member121  using MemberObjectListClauses = std::tuple<OmpClause::Copyin,122      OmpClause::Copyprivate, OmpClause::Exclusive, OmpClause::Firstprivate,123      OmpClause::HasDeviceAddr, OmpClause::Inclusive, OmpClause::IsDevicePtr,124      OmpClause::Link, OmpClause::Private, OmpClause::Shared,125      OmpClause::UseDeviceAddr, OmpClause::UseDevicePtr>;126 127  // Clauses with OmpObjectList in the tuple128  using TupleObjectListClauses = std::tuple<OmpClause::AdjustArgs,129      OmpClause::Affinity, OmpClause::Aligned, OmpClause::Allocate,130      OmpClause::Enter, OmpClause::From, OmpClause::InReduction,131      OmpClause::Lastprivate, OmpClause::Linear, OmpClause::Map,132      OmpClause::Reduction, OmpClause::TaskReduction, OmpClause::To>;133 134  // TODO:: Generate the tuples using TableGen.135  return common::visit(136      common::visitors{137          [&](const OmpClause::Depend &x) -> const OmpObjectList * {138            if (auto *taskDep{std::get_if<OmpDependClause::TaskDep>(&x.v.u)}) {139              return &std::get<OmpObjectList>(taskDep->t);140            } else {141              return nullptr;142            }143          },144          [&](const auto &x) -> const OmpObjectList * {145            using Ty = std::decay_t<decltype(x)>;146            if constexpr (common::HasMember<Ty, MemberObjectListClauses>) {147              return &x.v;148            } else if constexpr (common::HasMember<Ty,149                                     TupleObjectListClauses>) {150              return &std::get<OmpObjectList>(x.v.t);151            } else {152              return nullptr;153            }154          },155      },156      clause.u);157}158 159const BlockConstruct *GetFortranBlockConstruct(160    const ExecutionPartConstruct &epc) {161  // ExecutionPartConstruct -> ExecutableConstruct162  //   -> Indirection<BlockConstruct>163  if (auto *ec{std::get_if<ExecutableConstruct>(&epc.u)}) {164    if (auto *ind{std::get_if<common::Indirection<BlockConstruct>>(&ec->u)}) {165      return &ind->value();166    }167  }168  return nullptr;169}170 171/// parser::Block is a list of executable constructs, parser::BlockConstruct172/// is Fortran's BLOCK/ENDBLOCK construct.173/// Strip the outermost BlockConstructs, return the reference to the Block174/// in the executable part of the innermost of the stripped constructs.175/// Specifically, if the given `block` has a single entry (it's a list), and176/// the entry is a BlockConstruct, get the Block contained within. Repeat177/// this step as many times as possible.178const Block &GetInnermostExecPart(const Block &block) {179  const Block *iter{&block};180  while (iter->size() == 1) {181    const ExecutionPartConstruct &ep{iter->front()};182    if (auto *bc{GetFortranBlockConstruct(ep)}) {183      iter = &std::get<Block>(bc->t);184    } else {185      break;186    }187  }188  return *iter;189}190 191bool IsStrictlyStructuredBlock(const Block &block) {192  if (block.size() == 1) {193    return GetFortranBlockConstruct(block.front()) != nullptr;194  } else {195    return false;196  }197}198 199const OmpCombinerExpression *GetCombinerExpr(200    const OmpReductionSpecifier &rspec) {201  return addr_if(std::get<std::optional<OmpCombinerExpression>>(rspec.t));202}203 204const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init) {205  if (auto *wrapped{std::get_if<OmpClause::Initializer>(&init.u)}) {206    return &wrapped->v.v;207  }208  return nullptr;209}210 211static void SplitOmpAllocateHelper(212    OmpAllocateInfo &n, const OmpAllocateDirective &x) {213  n.dirs.push_back(&x);214  const Block &body{std::get<Block>(x.t)};215  if (!body.empty()) {216    if (auto *omp{GetOmp(body.front())}) {217      if (auto *ad{std::get_if<OmpAllocateDirective>(&omp->u)}) {218        return SplitOmpAllocateHelper(n, *ad);219      }220    }221    n.body = &body.front();222  }223}224 225OmpAllocateInfo SplitOmpAllocate(const OmpAllocateDirective &x) {226  OmpAllocateInfo info;227  SplitOmpAllocateHelper(info, x);228  return info;229}230 231} // namespace Fortran::parser::omp232