1 //===-- examples/flang-omp-report-plugin/flang-omp-report-visitor.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 "FlangOmpReportVisitor.h"
10 #include "llvm/ADT/StringExtras.h"
11 
12 namespace Fortran {
13 namespace parser {
14 bool operator<(const ClauseInfo &a, const ClauseInfo &b) {
15   return a.clause < b.clause;
16 }
17 bool operator==(const ClauseInfo &a, const ClauseInfo &b) {
18   return a.clause == b.clause && a.clauseDetails == b.clauseDetails;
19 }
20 bool operator!=(const ClauseInfo &a, const ClauseInfo &b) { return !(a == b); }
21 
22 bool operator==(const LogRecord &a, const LogRecord &b) {
23   return a.file == b.file && a.line == b.line && a.construct == b.construct &&
24       a.clauses == b.clauses;
25 }
26 bool operator!=(const LogRecord &a, const LogRecord &b) { return !(a == b); }
27 
28 std::string OpenMPCounterVisitor::normalize_construct_name(std::string s) {
29   std::transform(s.begin(), s.end(), s.begin(),
30       [](unsigned char c) { return llvm::toLower(c); });
31   return s;
32 }
33 ClauseInfo OpenMPCounterVisitor::normalize_clause_name(
34     const llvm::StringRef s) {
35   std::size_t start = s.find('(');
36   std::size_t end = s.find(')');
37   std::string clauseName;
38   if (start != llvm::StringRef::npos && end != llvm::StringRef::npos) {
39     clauseName = s.substr(0, start);
40     clauseDetails = s.substr(start + 1, end - start - 1);
41   } else {
42     clauseName = s;
43   }
44   std::transform(clauseName.begin(), clauseName.end(), clauseName.begin(),
45       [](unsigned char c) { return llvm::toLower(c); });
46   std::transform(clauseDetails.begin(), clauseDetails.end(),
47       clauseDetails.begin(), [](unsigned char c) { return llvm::toLower(c); });
48   return ClauseInfo{clauseName, clauseDetails};
49 }
50 SourcePosition OpenMPCounterVisitor::getLocation(const OmpWrapperType &w) {
51   if (auto *val = std::get_if<const OpenMPConstruct *>(&w)) {
52     const OpenMPConstruct *o{*val};
53     return getLocation(*o);
54   }
55   return getLocation(*std::get<const OpenMPDeclarativeConstruct *>(w));
56 }
57 SourcePosition OpenMPCounterVisitor::getLocation(
58     const OpenMPDeclarativeConstruct &c) {
59   return std::visit(
60       [&](const auto &o) -> SourcePosition {
61         return parsing->allCooked().GetSourcePositionRange(o.source)->first;
62       },
63       c.u);
64 }
65 SourcePosition OpenMPCounterVisitor::getLocation(const OpenMPConstruct &c) {
66   return std::visit(
67       Fortran::common::visitors{
68           [&](const OpenMPStandaloneConstruct &c) -> SourcePosition {
69             return parsing->allCooked().GetSourcePositionRange(c.source)->first;
70           },
71           // OpenMPSectionsConstruct, OpenMPLoopConstruct,
72           // OpenMPBlockConstruct, OpenMPCriticalConstruct Get the source from
73           // the directive field.
74           [&](const auto &c) -> SourcePosition {
75             const CharBlock &source{std::get<0>(c.t).source};
76             return (parsing->allCooked().GetSourcePositionRange(source))->first;
77           },
78           [&](const OpenMPAtomicConstruct &c) -> SourcePosition {
79             return std::visit(
80                 [&](const auto &o) -> SourcePosition {
81                   const CharBlock &source{std::get<Verbatim>(o.t).source};
82                   return parsing->allCooked()
83                       .GetSourcePositionRange(source)
84                       ->first;
85                 },
86                 c.u);
87           },
88       },
89       c.u);
90 }
91 
92 std::string OpenMPCounterVisitor::getName(const OmpWrapperType &w) {
93   if (auto *val = std::get_if<const OpenMPConstruct *>(&w)) {
94     const OpenMPConstruct *o{*val};
95     return getName(*o);
96   }
97   return getName(*std::get<const OpenMPDeclarativeConstruct *>(w));
98 }
99 std::string OpenMPCounterVisitor::getName(const OpenMPDeclarativeConstruct &c) {
100   return std::visit(
101       [&](const auto &o) -> std::string {
102         const CharBlock &source{std::get<Verbatim>(o.t).source};
103         return normalize_construct_name(source.ToString());
104       },
105       c.u);
106 }
107 std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) {
108   return std::visit(
109       Fortran::common::visitors{
110           [&](const OpenMPStandaloneConstruct &c) -> std::string {
111             return std::visit(
112                 [&](const auto &c) {
113                   // Get source from the directive or verbatim fields
114                   const CharBlock &source{std::get<0>(c.t).source};
115                   return normalize_construct_name(source.ToString());
116                 },
117                 c.u);
118           },
119           [&](const OpenMPExecutableAllocate &c) -> std::string {
120             const CharBlock &source{std::get<0>(c.t).source};
121             return normalize_construct_name(source.ToString());
122           },
123           [&](const OpenMPDeclarativeAllocate &c) -> std::string {
124             const CharBlock &source{std::get<0>(c.t).source};
125             return normalize_construct_name(source.ToString());
126           },
127           [&](const OpenMPAtomicConstruct &c) -> std::string {
128             return std::visit(
129                 [&](const auto &c) {
130                   // Get source from the verbatim fields
131                   const CharBlock &source{std::get<Verbatim>(c.t).source};
132                   return "atomic-" +
133                       normalize_construct_name(source.ToString());
134                 },
135                 c.u);
136           },
137           // OpenMPSectionsConstruct, OpenMPLoopConstruct,
138           // OpenMPBlockConstruct, OpenMPCriticalConstruct Get the source from
139           // the directive field of the begin directive or from the verbatim
140           // field of the begin directive in Critical
141           [&](const auto &c) -> std::string {
142             const CharBlock &source{std::get<0>(std::get<0>(c.t).t).source};
143             return normalize_construct_name(source.ToString());
144           },
145       },
146       c.u);
147 }
148 
149 bool OpenMPCounterVisitor::Pre(const OpenMPDeclarativeConstruct &c) {
150   OmpWrapperType *ow{new OmpWrapperType(&c)};
151   ompWrapperStack.push_back(ow);
152   return true;
153 }
154 bool OpenMPCounterVisitor::Pre(const OpenMPConstruct &c) {
155   OmpWrapperType *ow{new OmpWrapperType(&c)};
156   ompWrapperStack.push_back(ow);
157   return true;
158 }
159 
160 void OpenMPCounterVisitor::Post(const OpenMPDeclarativeConstruct &) {
161   PostConstructsCommon();
162 }
163 void OpenMPCounterVisitor::Post(const OpenMPConstruct &) {
164   PostConstructsCommon();
165 }
166 void OpenMPCounterVisitor::PostConstructsCommon() {
167   OmpWrapperType *curConstruct = ompWrapperStack.back();
168   std::sort(
169       clauseStrings[curConstruct].begin(), clauseStrings[curConstruct].end());
170 
171   SourcePosition s{getLocation(*curConstruct)};
172   LogRecord r{s.file.path(), s.line, getName(*curConstruct),
173       clauseStrings[curConstruct]};
174   constructClauses.push_back(r);
175 
176   auto it = clauseStrings.find(curConstruct);
177   clauseStrings.erase(it);
178   ompWrapperStack.pop_back();
179   delete curConstruct;
180 }
181 
182 void OpenMPCounterVisitor::Post(const OmpProcBindClause::Type &c) {
183   clauseDetails += "type=" + OmpProcBindClause::EnumToString(c) + ";";
184 }
185 void OpenMPCounterVisitor::Post(const OmpDefaultClause::Type &c) {
186   clauseDetails += "type=" + OmpDefaultClause::EnumToString(c) + ";";
187 }
188 void OpenMPCounterVisitor::Post(
189     const OmpDefaultmapClause::ImplicitBehavior &c) {
190   clauseDetails +=
191       "implicit_behavior=" + OmpDefaultmapClause::EnumToString(c) + ";";
192 }
193 void OpenMPCounterVisitor::Post(
194     const OmpDefaultmapClause::VariableCategory &c) {
195   clauseDetails +=
196       "variable_category=" + OmpDefaultmapClause::EnumToString(c) + ";";
197 }
198 void OpenMPCounterVisitor::Post(const OmpScheduleModifierType::ModType &c) {
199   clauseDetails += "modifier=" + OmpScheduleModifierType::EnumToString(c) + ";";
200 }
201 void OpenMPCounterVisitor::Post(const OmpLinearModifier::Type &c) {
202   clauseDetails += "modifier=" + OmpLinearModifier::EnumToString(c) + ";";
203 }
204 void OpenMPCounterVisitor::Post(const OmpDependenceType::Type &c) {
205   clauseDetails += "type=" + OmpDependenceType::EnumToString(c) + ";";
206 }
207 void OpenMPCounterVisitor::Post(const OmpMapType::Type &c) {
208   clauseDetails += "type=" + OmpMapType::EnumToString(c) + ";";
209 }
210 void OpenMPCounterVisitor::Post(const OmpScheduleClause::ScheduleType &c) {
211   clauseDetails += "type=" + OmpScheduleClause::EnumToString(c) + ";";
212 }
213 void OpenMPCounterVisitor::Post(const OmpIfClause::DirectiveNameModifier &c) {
214   clauseDetails += "name_modifier=" + OmpIfClause::EnumToString(c) + ";";
215 }
216 void OpenMPCounterVisitor::Post(const OmpCancelType::Type &c) {
217   clauseDetails += "type=" + OmpCancelType::EnumToString(c) + ";";
218 }
219 void OpenMPCounterVisitor::Post(const OmpClause &c) {
220   PostClauseCommon(normalize_clause_name(c.source.ToString()));
221   clauseDetails.clear();
222 }
223 void OpenMPCounterVisitor::PostClauseCommon(const ClauseInfo &ci) {
224   assert(
225       !ompWrapperStack.empty() && "Construct should be visited before clause");
226   clauseStrings[ompWrapperStack.back()].push_back(ci);
227 }
228 } // namespace parser
229 } // namespace Fortran
230