| 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 | |