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