brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · 108fd33 Raw
206 lines · cpp
1//===-- lib/Semantics/canonicalize-acc.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 "canonicalize-acc.h"10#include "flang/Parser/parse-tree-visitor.h"11#include "flang/Semantics/tools.h"12 13// After Loop Canonicalization, rewrite OpenACC parse tree to make OpenACC14// Constructs more structured which provide explicit scopes for later15// structural checks and semantic analysis.16//   1. move structured DoConstruct into17//      OpenACCLoopConstruct. Compilation will not proceed in case of errors18//      after this pass.19//   2. move structured DoConstruct into OpenACCCombinedConstruct. Move20//      AccEndCombinedConstruct into OpenACCCombinedConstruct if present.21//      Compilation will not proceed in case of errors after this pass.22namespace Fortran::semantics {23 24using namespace parser::literals;25 26class CanonicalizationOfAcc {27public:28  template <typename T> bool Pre(T &) { return true; }29  template <typename T> void Post(T &) {}30  CanonicalizationOfAcc(parser::Messages &messages) : messages_{messages} {}31 32  void Post(parser::Block &block) {33    for (auto it{block.begin()}; it != block.end(); ++it) {34      if (auto *accLoop{parser::Unwrap<parser::OpenACCLoopConstruct>(*it)}) {35        RewriteOpenACCLoopConstruct(*accLoop, block, it);36      } else if (auto *accCombined{37                     parser::Unwrap<parser::OpenACCCombinedConstruct>(*it)}) {38        RewriteOpenACCCombinedConstruct(*accCombined, block, it);39      } else if (auto *endDir{40                     parser::Unwrap<parser::AccEndCombinedDirective>(*it)}) {41        // Unmatched AccEndCombinedDirective42        messages_.Say(endDir->v.source,43            "The %s directive must follow the DO loop associated with the "44            "loop construct"_err_en_US,45            parser::ToUpperCaseLetters(endDir->v.source.ToString()));46      }47    } // Block list48  }49 50private:51  // Check constraint in 2.9.752  // If there are n tile sizes in the list, the loop construct must be53  // immediately followed by n tightly-nested loops.54  template <typename C, typename D>55  void CheckTileClauseRestriction(56      const C &x, const parser::DoConstruct &outer) {57    const auto &beginLoopDirective = std::get<D>(x.t);58    const auto &accClauseList =59        std::get<parser::AccClauseList>(beginLoopDirective.t);60    for (const auto &clause : accClauseList.v) {61      if (const auto *tileClause =62              std::get_if<parser::AccClause::Tile>(&clause.u)) {63        const parser::AccTileExprList &tileExprList = tileClause->v;64        const std::list<parser::AccTileExpr> &listTileExpr = tileExprList.v;65        std::size_t tileArgNb = listTileExpr.size();66 67        if (outer.IsDoConcurrent()) {68          return; // Tile is not allowed on DO CONCURRENT69        }70        for (const parser::DoConstruct *loop{&outer}; loop && tileArgNb > 0;71             --tileArgNb) {72          const auto &block{std::get<parser::Block>(loop->t)};73          const auto it{block.begin()};74          loop = it != block.end() ? parser::Unwrap<parser::DoConstruct>(*it)75                                   : nullptr;76        }77 78        if (tileArgNb > 0) {79          messages_.Say(beginLoopDirective.source,80              "The loop construct with the TILE clause must be followed by %d "81              "tightly-nested loops"_err_en_US,82              listTileExpr.size());83        }84      }85    }86  }87 88  // Check constraint on line 1835 in Section 2.989  // A tile and collapse clause may not appear on loop that is associated with90  // do concurrent.91  template <typename C, typename D>92  void CheckDoConcurrentClauseRestriction(93      const C &x, const parser::DoConstruct &doCons) {94    if (!doCons.IsDoConcurrent()) {95      return;96    }97    const auto &beginLoopDirective = std::get<D>(x.t);98    const auto &accClauseList =99        std::get<parser::AccClauseList>(beginLoopDirective.t);100    for (const auto &clause : accClauseList.v) {101      if (std::holds_alternative<parser::AccClause::Collapse>(clause.u) ||102          std::holds_alternative<parser::AccClause::Tile>(clause.u)) {103        messages_.Say(beginLoopDirective.source,104            "TILE and COLLAPSE clause may not appear on loop construct "105            "associated with DO CONCURRENT"_err_en_US);106      }107    }108  }109 110  // Utility to move all parser::CompilerDirective right after it to right111  // before it.  This allows preserving loop directives $DIR that may lie112  // between an $acc directive and loop and leave lowering decide if it should113  // ignore them or lower/apply them to the acc loops.114  void moveCompilerDirectivesBefore(115      parser::Block &block, parser::Block::iterator it) {116    parser::Block::iterator nextIt = std::next(it);117    while (nextIt != block.end() &&118        parser::Unwrap<parser::CompilerDirective>(*nextIt)) {119      block.emplace(it, std::move(*nextIt));120      nextIt = block.erase(nextIt);121    }122  }123 124  void RewriteOpenACCLoopConstruct(parser::OpenACCLoopConstruct &x,125      parser::Block &block, parser::Block::iterator it) {126    parser::Block::iterator nextIt;127    auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};128    auto &dir{std::get<parser::AccLoopDirective>(beginDir.t)};129    auto &nestedDo{std::get<std::optional<parser::DoConstruct>>(x.t)};130 131    if (!nestedDo) {132      moveCompilerDirectivesBefore(block, it);133      nextIt = it;134      if (++nextIt != block.end()) {135        if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {136          nestedDo = std::move(*doCons);137          nextIt = block.erase(nextIt);138        }139      }140    }141 142    if (nestedDo) {143      if (!nestedDo->GetLoopControl()) {144        messages_.Say(dir.source,145            "DO loop after the %s directive must have loop control"_err_en_US,146            parser::ToUpperCaseLetters(dir.source.ToString()));147        return;148      }149      CheckDoConcurrentClauseRestriction<parser::OpenACCLoopConstruct,150          parser::AccBeginLoopDirective>(x, *nestedDo);151      CheckTileClauseRestriction<parser::OpenACCLoopConstruct,152          parser::AccBeginLoopDirective>(x, *nestedDo);153      return;154    }155    messages_.Say(dir.source,156        "A DO loop must follow the %s directive"_err_en_US,157        parser::ToUpperCaseLetters(dir.source.ToString()));158  }159 160  void RewriteOpenACCCombinedConstruct(parser::OpenACCCombinedConstruct &x,161      parser::Block &block, parser::Block::iterator it) {162    // Check the sequence of DoConstruct in the same iteration.163    parser::Block::iterator nextIt;164    auto &beginDir{std::get<parser::AccBeginCombinedDirective>(x.t)};165    auto &dir{std::get<parser::AccCombinedDirective>(beginDir.t)};166    auto &nestedDo{std::get<std::optional<parser::DoConstruct>>(x.t)};167 168    if (!nestedDo) {169      moveCompilerDirectivesBefore(block, it);170      nextIt = it;171      if (++nextIt != block.end()) {172        if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {173          nestedDo = std::move(*doCons);174          nextIt = block.erase(nextIt);175        }176      }177    }178 179    if (nestedDo) {180      CheckDoConcurrentClauseRestriction<parser::OpenACCCombinedConstruct,181          parser::AccBeginCombinedDirective>(x, *nestedDo);182      CheckTileClauseRestriction<parser::OpenACCCombinedConstruct,183          parser::AccBeginCombinedDirective>(x, *nestedDo);184      if (!nestedDo->GetLoopControl()) {185        messages_.Say(dir.source,186            "DO loop after the %s directive must have loop control"_err_en_US,187            parser::ToUpperCaseLetters(dir.source.ToString()));188        return;189      }190      return;191    }192    messages_.Say(dir.source,193        "A DO loop must follow the %s directive"_err_en_US,194        parser::ToUpperCaseLetters(dir.source.ToString()));195  }196 197  parser::Messages &messages_;198};199 200bool CanonicalizeAcc(parser::Messages &messages, parser::Program &program) {201  CanonicalizationOfAcc acc{messages};202  Walk(program, acc);203  return !messages.AnyFatalError();204}205} // namespace Fortran::semantics206