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 | #include "llvm/Frontend/OpenMP/OMP.h" |
12 | |
13 | namespace Fortran { |
14 | namespace parser { |
15 | bool operator<(const ClauseInfo &a, const ClauseInfo &b) { |
16 | return a.clause < b.clause; |
17 | } |
18 | bool operator==(const ClauseInfo &a, const ClauseInfo &b) { |
19 | return a.clause == b.clause && a.clauseDetails == b.clauseDetails; |
20 | } |
21 | bool operator!=(const ClauseInfo &a, const ClauseInfo &b) { return !(a == b); } |
22 | |
23 | bool operator==(const LogRecord &a, const LogRecord &b) { |
24 | return a.file == b.file && a.line == b.line && a.construct == b.construct && |
25 | a.clauses == b.clauses; |
26 | } |
27 | bool operator!=(const LogRecord &a, const LogRecord &b) { return !(a == b); } |
28 | |
29 | std::string OpenMPCounterVisitor::normalize_construct_name(std::string s) { |
30 | std::transform(first: s.begin(), last: s.end(), result: s.begin(), |
31 | unary_op: [](unsigned char c) { return llvm::toLower(x: c); }); |
32 | return s; |
33 | } |
34 | ClauseInfo OpenMPCounterVisitor::normalize_clause_name( |
35 | const llvm::StringRef s) { |
36 | std::size_t start = s.find(C: '('); |
37 | std::size_t end = s.find(C: ')'); |
38 | std::string clauseName; |
39 | if (start != llvm::StringRef::npos && end != llvm::StringRef::npos) { |
40 | clauseName = s.substr(Start: 0, N: start); |
41 | clauseDetails = s.substr(Start: start + 1, N: end - start - 1); |
42 | } else { |
43 | clauseName = s; |
44 | } |
45 | std::transform(first: clauseName.begin(), last: clauseName.end(), result: clauseName.begin(), |
46 | unary_op: [](unsigned char c) { return llvm::toLower(x: c); }); |
47 | std::transform(first: clauseDetails.begin(), last: clauseDetails.end(), |
48 | result: clauseDetails.begin(), unary_op: [](unsigned char c) { return llvm::toLower(x: c); }); |
49 | return ClauseInfo{clauseName, clauseDetails}; |
50 | } |
51 | SourcePosition OpenMPCounterVisitor::getLocation(const OmpWrapperType &w) { |
52 | if (auto *val = std::get_if<const OpenMPConstruct *>(&w)) { |
53 | const OpenMPConstruct *o{*val}; |
54 | return getLocation(*o); |
55 | } |
56 | return getLocation(*std::get<const OpenMPDeclarativeConstruct *>(w)); |
57 | } |
58 | SourcePosition OpenMPCounterVisitor::getLocation( |
59 | const OpenMPDeclarativeConstruct &c) { |
60 | return std::visit( |
61 | [&](const auto &o) -> SourcePosition { |
62 | return parsing->allCooked().GetSourcePositionRange(o.source)->first; |
63 | }, |
64 | c.u); |
65 | } |
66 | SourcePosition OpenMPCounterVisitor::getLocation(const OpenMPConstruct &c) { |
67 | return std::visit( |
68 | Fortran::common::visitors{ |
69 | [&](const OpenMPStandaloneConstruct &c) -> SourcePosition { |
70 | return parsing->allCooked().GetSourcePositionRange(c.source)->first; |
71 | }, |
72 | // OpenMPSectionsConstruct, OpenMPLoopConstruct, |
73 | // OpenMPBlockConstruct, OpenMPCriticalConstruct Get the source from |
74 | // the directive field. |
75 | [&](const auto &c) -> SourcePosition { |
76 | const CharBlock &source{std::get<0>(c.t).source}; |
77 | return parsing->allCooked().GetSourcePositionRange(source)->first; |
78 | }, |
79 | [&](const OpenMPAtomicConstruct &c) -> SourcePosition { |
80 | const CharBlock &source{c.source}; |
81 | return parsing->allCooked().GetSourcePositionRange(source)->first; |
82 | }, |
83 | [&](const OpenMPSectionConstruct &c) -> SourcePosition { |
84 | const CharBlock &source{c.source}; |
85 | return parsing->allCooked().GetSourcePositionRange(source)->first; |
86 | }, |
87 | [&](const OpenMPUtilityConstruct &c) -> SourcePosition { |
88 | const CharBlock &source{c.source}; |
89 | return parsing->allCooked().GetSourcePositionRange(source)->first; |
90 | }, |
91 | }, |
92 | c.u); |
93 | } |
94 | |
95 | std::string OpenMPCounterVisitor::getName(const OmpWrapperType &w) { |
96 | if (auto *val = std::get_if<const OpenMPConstruct *>(&w)) { |
97 | const OpenMPConstruct *o{*val}; |
98 | return getName(*o); |
99 | } |
100 | return getName(*std::get<const OpenMPDeclarativeConstruct *>(w)); |
101 | } |
102 | std::string OpenMPCounterVisitor::getName(const OpenMPDeclarativeConstruct &c) { |
103 | return std::visit( // |
104 | Fortran::common::visitors{ |
105 | [&](const OpenMPUtilityConstruct &o) -> std::string { |
106 | const CharBlock &source{o.source}; |
107 | return normalize_construct_name(source.ToString()); |
108 | }, |
109 | [&](const OmpMetadirectiveDirective &o) -> std::string { |
110 | const CharBlock &source{o.source}; |
111 | return normalize_construct_name(source.ToString()); |
112 | }, |
113 | [&](const auto &o) -> std::string { |
114 | const CharBlock &source{std::get<Verbatim>(o.t).source}; |
115 | return normalize_construct_name(source.ToString()); |
116 | }, |
117 | }, |
118 | c.u); |
119 | } |
120 | std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) { |
121 | return std::visit( |
122 | Fortran::common::visitors{ |
123 | [&](const OpenMPStandaloneConstruct &c) -> std::string { |
124 | return common::visit( |
125 | common::visitors{ |
126 | [&](const OmpMetadirectiveDirective &d) { |
127 | return normalize_construct_name(d.source.ToString()); |
128 | }, |
129 | [&](auto &&d) { |
130 | const CharBlock &source{ |
131 | std::get<OmpDirectiveName>(d.v.t).source}; |
132 | return normalize_construct_name(source.ToString()); |
133 | }, |
134 | }, |
135 | c.u); |
136 | }, |
137 | [&](const OpenMPExecutableAllocate &c) -> std::string { |
138 | const CharBlock &source{std::get<0>(c.t).source}; |
139 | return normalize_construct_name(source.ToString()); |
140 | }, |
141 | [&](const OpenMPDeclarativeAllocate &c) -> std::string { |
142 | const CharBlock &source{std::get<0>(c.t).source}; |
143 | return normalize_construct_name(source.ToString()); |
144 | }, |
145 | [&](const OpenMPAssumeConstruct &c) -> std::string { |
146 | const CharBlock &source{std::get<0>(c.t).source}; |
147 | return normalize_construct_name(source.ToString()); |
148 | }, |
149 | [&](const OpenMPAllocatorsConstruct &c) -> std::string { |
150 | const CharBlock &source{std::get<0>(c.t).source}; |
151 | return normalize_construct_name(source.ToString()); |
152 | }, |
153 | [&](const OpenMPAtomicConstruct &c) -> std::string { |
154 | auto &dirSpec = std::get<OmpDirectiveSpecification>(c.t); |
155 | auto &dirName = std::get<OmpDirectiveName>(dirSpec.t); |
156 | return normalize_construct_name(dirName.source.ToString()); |
157 | }, |
158 | [&](const OpenMPUtilityConstruct &c) -> std::string { |
159 | const CharBlock &source{c.source}; |
160 | return normalize_construct_name(source.ToString()); |
161 | }, |
162 | [&](const OpenMPSectionConstruct &c) -> std::string { |
163 | return "section" ; |
164 | }, |
165 | // OpenMPSectionsConstruct, OpenMPLoopConstruct, |
166 | // OpenMPBlockConstruct, OpenMPCriticalConstruct Get the source from |
167 | // the directive field of the begin directive or from the verbatim |
168 | // field of the begin directive in Critical |
169 | [&](const auto &c) -> std::string { |
170 | const CharBlock &source{std::get<0>(std::get<0>(c.t).t).source}; |
171 | return normalize_construct_name(source.ToString()); |
172 | }, |
173 | }, |
174 | c.u); |
175 | } |
176 | |
177 | bool OpenMPCounterVisitor::Pre(const OpenMPDeclarativeConstruct &c) { |
178 | OmpWrapperType *ow{new OmpWrapperType(&c)}; |
179 | ompWrapperStack.push_back(ow); |
180 | return true; |
181 | } |
182 | bool OpenMPCounterVisitor::Pre(const OpenMPConstruct &c) { |
183 | OmpWrapperType *ow{new OmpWrapperType(&c)}; |
184 | ompWrapperStack.push_back(ow); |
185 | return true; |
186 | } |
187 | |
188 | void OpenMPCounterVisitor::Post(const OpenMPDeclarativeConstruct &) { |
189 | PostConstructsCommon(); |
190 | } |
191 | void OpenMPCounterVisitor::Post(const OpenMPConstruct &) { |
192 | PostConstructsCommon(); |
193 | } |
194 | void OpenMPCounterVisitor::PostConstructsCommon() { |
195 | OmpWrapperType *curConstruct = ompWrapperStack.back(); |
196 | std::sort( |
197 | clauseStrings[curConstruct].begin(), clauseStrings[curConstruct].end()); |
198 | |
199 | SourcePosition s{getLocation(*curConstruct)}; |
200 | LogRecord r{ |
201 | s.path, s.line, getName(*curConstruct), clauseStrings[curConstruct]}; |
202 | constructClauses.push_back(Elt: r); |
203 | |
204 | auto it = clauseStrings.find(curConstruct); |
205 | clauseStrings.erase(it); |
206 | ompWrapperStack.pop_back(); |
207 | delete curConstruct; |
208 | } |
209 | |
210 | void OpenMPCounterVisitor::Post(const OmpProcBindClause::AffinityPolicy &c) { |
211 | clauseDetails += |
212 | "type=" + std::string{OmpProcBindClause::EnumToString(c)} + ";" ; |
213 | } |
214 | void OpenMPCounterVisitor::Post( |
215 | const OmpDefaultClause::DataSharingAttribute &c) { |
216 | clauseDetails += |
217 | "type=" + std::string{OmpDefaultClause::EnumToString(c)} + ";" ; |
218 | } |
219 | void OpenMPCounterVisitor::Post( |
220 | const OmpDeviceTypeClause::DeviceTypeDescription &c) { |
221 | clauseDetails += |
222 | "type=" + std::string{OmpDeviceTypeClause::EnumToString(c)} + ";" ; |
223 | } |
224 | void OpenMPCounterVisitor::Post( |
225 | const OmpDefaultmapClause::ImplicitBehavior &c) { |
226 | clauseDetails += |
227 | "implicit_behavior=" + std::string{OmpDefaultmapClause::EnumToString(c)} + |
228 | ";" ; |
229 | } |
230 | void OpenMPCounterVisitor::Post(const OmpVariableCategory::Value &c) { |
231 | clauseDetails += |
232 | "variable_category=" + std::string{OmpVariableCategory::EnumToString(c)} + |
233 | ";" ; |
234 | } |
235 | void OpenMPCounterVisitor::Post(const OmpChunkModifier::Value &c) { |
236 | clauseDetails += |
237 | "modifier=" + std::string{OmpChunkModifier::EnumToString(c)} + ";" ; |
238 | } |
239 | void OpenMPCounterVisitor::Post(const OmpLinearModifier::Value &c) { |
240 | clauseDetails += |
241 | "modifier=" + std::string{OmpLinearModifier::EnumToString(c)} + ";" ; |
242 | } |
243 | void OpenMPCounterVisitor::Post(const OmpOrderingModifier::Value &c) { |
244 | clauseDetails += |
245 | "modifier=" + std::string{OmpOrderingModifier::EnumToString(c)} + ";" ; |
246 | } |
247 | void OpenMPCounterVisitor::Post(const OmpTaskDependenceType::Value &c) { |
248 | clauseDetails += |
249 | "type=" + std::string{OmpTaskDependenceType::EnumToString(c)} + ";" ; |
250 | } |
251 | void OpenMPCounterVisitor::Post(const OmpMapType::Value &c) { |
252 | clauseDetails += "type=" + std::string{OmpMapType::EnumToString(c)} + ";" ; |
253 | } |
254 | void OpenMPCounterVisitor::Post(const OmpScheduleClause::Kind &c) { |
255 | clauseDetails += |
256 | "type=" + std::string{OmpScheduleClause::EnumToString(c)} + ";" ; |
257 | } |
258 | void OpenMPCounterVisitor::Post(const OmpDirectiveNameModifier &c) { |
259 | clauseDetails += "name_modifier=" + |
260 | llvm::omp::getOpenMPDirectiveName(c.v, llvm::omp::FallbackVersion).str() + |
261 | ";" ; |
262 | } |
263 | void OpenMPCounterVisitor::Post(const OmpClause &c) { |
264 | PostClauseCommon(ci: normalize_clause_name(s: c.source.ToString())); |
265 | clauseDetails.clear(); |
266 | } |
267 | void OpenMPCounterVisitor::PostClauseCommon(const ClauseInfo &ci) { |
268 | assert( |
269 | !ompWrapperStack.empty() && "Construct should be visited before clause" ); |
270 | clauseStrings[ompWrapperStack.back()].push_back(ci); |
271 | } |
272 | } // namespace parser |
273 | } // namespace Fortran |
274 | |