llvm-project

Форк
0
/
canonicalize-acc.cpp 
189 строк · 7.3 Кб
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-exception
6
//
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 OpenACC
14
// Constructs more structured which provide explicit scopes for later
15
// structural checks and semantic analysis.
16
//   1. move structured DoConstruct into
17
//      OpenACCLoopConstruct. Compilation will not proceed in case of errors
18
//      after this pass.
19
//   2. move structured DoConstruct into OpenACCCombinedConstruct. Move
20
//      AccEndCombinedConstruct into OpenACCCombinedConstruct if present.
21
//      Compilation will not proceed in case of errors after this pass.
22
namespace Fortran::semantics {
23

24
using namespace parser::literals;
25

26
class CanonicalizationOfAcc {
27
public:
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 AccEndCombinedDirective
42
        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 list
48
  }
49

50
private:
51
  // Check constraint in 2.9.7
52
  // If there are n tile sizes in the list, the loop construct must be
53
  // 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 CONCURRENT
69
        }
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.9
89
  // A tile and collapse clause may not appear on loop that is associated with
90
  // 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
  void RewriteOpenACCLoopConstruct(parser::OpenACCLoopConstruct &x,
111
      parser::Block &block, parser::Block::iterator it) {
112
    parser::Block::iterator nextIt;
113
    auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
114
    auto &dir{std::get<parser::AccLoopDirective>(beginDir.t)};
115
    auto &nestedDo{std::get<std::optional<parser::DoConstruct>>(x.t)};
116

117
    if (!nestedDo) {
118
      nextIt = it;
119
      if (++nextIt != block.end()) {
120
        if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
121
          nestedDo = std::move(*doCons);
122
          nextIt = block.erase(nextIt);
123
        }
124
      }
125
    }
126

127
    if (nestedDo) {
128
      if (!nestedDo->GetLoopControl()) {
129
        messages_.Say(dir.source,
130
            "DO loop after the %s directive must have loop control"_err_en_US,
131
            parser::ToUpperCaseLetters(dir.source.ToString()));
132
        return;
133
      }
134
      CheckDoConcurrentClauseRestriction<parser::OpenACCLoopConstruct,
135
          parser::AccBeginLoopDirective>(x, *nestedDo);
136
      CheckTileClauseRestriction<parser::OpenACCLoopConstruct,
137
          parser::AccBeginLoopDirective>(x, *nestedDo);
138
      return;
139
    }
140
    messages_.Say(dir.source,
141
        "A DO loop must follow the %s directive"_err_en_US,
142
        parser::ToUpperCaseLetters(dir.source.ToString()));
143
  }
144

145
  void RewriteOpenACCCombinedConstruct(parser::OpenACCCombinedConstruct &x,
146
      parser::Block &block, parser::Block::iterator it) {
147
    // Check the sequence of DoConstruct in the same iteration.
148
    parser::Block::iterator nextIt;
149
    auto &beginDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
150
    auto &dir{std::get<parser::AccCombinedDirective>(beginDir.t)};
151
    auto &nestedDo{std::get<std::optional<parser::DoConstruct>>(x.t)};
152

153
    if (!nestedDo) {
154
      nextIt = it;
155
      if (++nextIt != block.end()) {
156
        if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
157
          nestedDo = std::move(*doCons);
158
          nextIt = block.erase(nextIt);
159
        }
160
      }
161
    }
162

163
    if (nestedDo) {
164
      CheckDoConcurrentClauseRestriction<parser::OpenACCCombinedConstruct,
165
          parser::AccBeginCombinedDirective>(x, *nestedDo);
166
      CheckTileClauseRestriction<parser::OpenACCCombinedConstruct,
167
          parser::AccBeginCombinedDirective>(x, *nestedDo);
168
      if (!nestedDo->GetLoopControl()) {
169
        messages_.Say(dir.source,
170
            "DO loop after the %s directive must have loop control"_err_en_US,
171
            parser::ToUpperCaseLetters(dir.source.ToString()));
172
        return;
173
      }
174
      return;
175
    }
176
    messages_.Say(dir.source,
177
        "A DO loop must follow the %s directive"_err_en_US,
178
        parser::ToUpperCaseLetters(dir.source.ToString()));
179
  }
180

181
  parser::Messages &messages_;
182
};
183

184
bool CanonicalizeAcc(parser::Messages &messages, parser::Program &program) {
185
  CanonicalizationOfAcc acc{messages};
186
  Walk(program, acc);
187
  return !messages.AnyFatalError();
188
}
189
} // namespace Fortran::semantics
190

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.