The parser will accept a wide variety of illegal attempts at forming an ATOMIC construct, leaving it to the semantic analysis to diagnose any issues. This consolidates the analysis into one place and allows us to produce more informative diagnostics. The parser's outcome will be parser::OpenMPAtomicConstruct object holding the directive, parser::Body, and an optional end-directive. The prior variety of OmpAtomicXyz classes, as well as OmpAtomicClause have been removed. READ, WRITE, etc. are now proper clauses. The semantic analysis consistently operates on "evaluation" representations, mainly evaluate::Expr (as SomeExpr) and evaluate::Assignment. The results of the semantic analysis are stored in a mutable member of the OpenMPAtomicConstruct node. This follows a precedent of having `typedExpr` member in parser::Expr, for example. This allows the lowering code to avoid duplicated handling of AST nodes. Using a BLOCK construct containing multiple statements for an ATOMIC construct that requires multiple statements is now allowed. In fact, any nesting of such BLOCK constructs is allowed. This implementation will parse, and perform semantic checks for both conditional-update and conditional-update-capture, although no MLIR will be generated for those. Instead, a TODO error will be issues prior to lowering. The allowed forms of the ATOMIC construct were based on the OpenMP 6.0 spec.
274 lines
11 KiB
C++
274 lines
11 KiB
C++
//===-- examples/flang-omp-report-plugin/flang-omp-report-visitor.cpp -----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FlangOmpReportVisitor.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Frontend/OpenMP/OMP.h"
|
|
|
|
namespace Fortran {
|
|
namespace parser {
|
|
bool operator<(const ClauseInfo &a, const ClauseInfo &b) {
|
|
return a.clause < b.clause;
|
|
}
|
|
bool operator==(const ClauseInfo &a, const ClauseInfo &b) {
|
|
return a.clause == b.clause && a.clauseDetails == b.clauseDetails;
|
|
}
|
|
bool operator!=(const ClauseInfo &a, const ClauseInfo &b) { return !(a == b); }
|
|
|
|
bool operator==(const LogRecord &a, const LogRecord &b) {
|
|
return a.file == b.file && a.line == b.line && a.construct == b.construct &&
|
|
a.clauses == b.clauses;
|
|
}
|
|
bool operator!=(const LogRecord &a, const LogRecord &b) { return !(a == b); }
|
|
|
|
std::string OpenMPCounterVisitor::normalize_construct_name(std::string s) {
|
|
std::transform(s.begin(), s.end(), s.begin(),
|
|
[](unsigned char c) { return llvm::toLower(c); });
|
|
return s;
|
|
}
|
|
ClauseInfo OpenMPCounterVisitor::normalize_clause_name(
|
|
const llvm::StringRef s) {
|
|
std::size_t start = s.find('(');
|
|
std::size_t end = s.find(')');
|
|
std::string clauseName;
|
|
if (start != llvm::StringRef::npos && end != llvm::StringRef::npos) {
|
|
clauseName = s.substr(0, start);
|
|
clauseDetails = s.substr(start + 1, end - start - 1);
|
|
} else {
|
|
clauseName = s;
|
|
}
|
|
std::transform(clauseName.begin(), clauseName.end(), clauseName.begin(),
|
|
[](unsigned char c) { return llvm::toLower(c); });
|
|
std::transform(clauseDetails.begin(), clauseDetails.end(),
|
|
clauseDetails.begin(), [](unsigned char c) { return llvm::toLower(c); });
|
|
return ClauseInfo{clauseName, clauseDetails};
|
|
}
|
|
SourcePosition OpenMPCounterVisitor::getLocation(const OmpWrapperType &w) {
|
|
if (auto *val = std::get_if<const OpenMPConstruct *>(&w)) {
|
|
const OpenMPConstruct *o{*val};
|
|
return getLocation(*o);
|
|
}
|
|
return getLocation(*std::get<const OpenMPDeclarativeConstruct *>(w));
|
|
}
|
|
SourcePosition OpenMPCounterVisitor::getLocation(
|
|
const OpenMPDeclarativeConstruct &c) {
|
|
return std::visit(
|
|
[&](const auto &o) -> SourcePosition {
|
|
return parsing->allCooked().GetSourcePositionRange(o.source)->first;
|
|
},
|
|
c.u);
|
|
}
|
|
SourcePosition OpenMPCounterVisitor::getLocation(const OpenMPConstruct &c) {
|
|
return std::visit(
|
|
Fortran::common::visitors{
|
|
[&](const OpenMPStandaloneConstruct &c) -> SourcePosition {
|
|
return parsing->allCooked().GetSourcePositionRange(c.source)->first;
|
|
},
|
|
// OpenMPSectionsConstruct, OpenMPLoopConstruct,
|
|
// OpenMPBlockConstruct, OpenMPCriticalConstruct Get the source from
|
|
// the directive field.
|
|
[&](const auto &c) -> SourcePosition {
|
|
const CharBlock &source{std::get<0>(c.t).source};
|
|
return parsing->allCooked().GetSourcePositionRange(source)->first;
|
|
},
|
|
[&](const OpenMPAtomicConstruct &c) -> SourcePosition {
|
|
const CharBlock &source{c.source};
|
|
return parsing->allCooked().GetSourcePositionRange(source)->first;
|
|
},
|
|
[&](const OpenMPSectionConstruct &c) -> SourcePosition {
|
|
const CharBlock &source{c.source};
|
|
return parsing->allCooked().GetSourcePositionRange(source)->first;
|
|
},
|
|
[&](const OpenMPUtilityConstruct &c) -> SourcePosition {
|
|
const CharBlock &source{c.source};
|
|
return parsing->allCooked().GetSourcePositionRange(source)->first;
|
|
},
|
|
},
|
|
c.u);
|
|
}
|
|
|
|
std::string OpenMPCounterVisitor::getName(const OmpWrapperType &w) {
|
|
if (auto *val = std::get_if<const OpenMPConstruct *>(&w)) {
|
|
const OpenMPConstruct *o{*val};
|
|
return getName(*o);
|
|
}
|
|
return getName(*std::get<const OpenMPDeclarativeConstruct *>(w));
|
|
}
|
|
std::string OpenMPCounterVisitor::getName(const OpenMPDeclarativeConstruct &c) {
|
|
return std::visit( //
|
|
Fortran::common::visitors{
|
|
[&](const OpenMPUtilityConstruct &o) -> std::string {
|
|
const CharBlock &source{o.source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const OmpMetadirectiveDirective &o) -> std::string {
|
|
const CharBlock &source{o.source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const auto &o) -> std::string {
|
|
const CharBlock &source{std::get<Verbatim>(o.t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
},
|
|
c.u);
|
|
}
|
|
std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) {
|
|
return std::visit(
|
|
Fortran::common::visitors{
|
|
[&](const OpenMPStandaloneConstruct &c) -> std::string {
|
|
return common::visit(
|
|
common::visitors{
|
|
[&](const OmpMetadirectiveDirective &d) {
|
|
return normalize_construct_name(d.source.ToString());
|
|
},
|
|
[&](auto &&d) {
|
|
const CharBlock &source{
|
|
std::get<OmpDirectiveName>(d.v.t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
},
|
|
c.u);
|
|
},
|
|
[&](const OpenMPExecutableAllocate &c) -> std::string {
|
|
const CharBlock &source{std::get<0>(c.t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const OpenMPDeclarativeAllocate &c) -> std::string {
|
|
const CharBlock &source{std::get<0>(c.t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const OpenMPAssumeConstruct &c) -> std::string {
|
|
const CharBlock &source{std::get<0>(c.t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const OpenMPAllocatorsConstruct &c) -> std::string {
|
|
const CharBlock &source{std::get<0>(c.t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const OpenMPAtomicConstruct &c) -> std::string {
|
|
auto &dirSpec = std::get<OmpDirectiveSpecification>(c.t);
|
|
auto &dirName = std::get<OmpDirectiveName>(dirSpec.t);
|
|
return normalize_construct_name(dirName.source.ToString());
|
|
},
|
|
[&](const OpenMPUtilityConstruct &c) -> std::string {
|
|
const CharBlock &source{c.source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
[&](const OpenMPSectionConstruct &c) -> std::string {
|
|
return "section";
|
|
},
|
|
// OpenMPSectionsConstruct, OpenMPLoopConstruct,
|
|
// OpenMPBlockConstruct, OpenMPCriticalConstruct Get the source from
|
|
// the directive field of the begin directive or from the verbatim
|
|
// field of the begin directive in Critical
|
|
[&](const auto &c) -> std::string {
|
|
const CharBlock &source{std::get<0>(std::get<0>(c.t).t).source};
|
|
return normalize_construct_name(source.ToString());
|
|
},
|
|
},
|
|
c.u);
|
|
}
|
|
|
|
bool OpenMPCounterVisitor::Pre(const OpenMPDeclarativeConstruct &c) {
|
|
OmpWrapperType *ow{new OmpWrapperType(&c)};
|
|
ompWrapperStack.push_back(ow);
|
|
return true;
|
|
}
|
|
bool OpenMPCounterVisitor::Pre(const OpenMPConstruct &c) {
|
|
OmpWrapperType *ow{new OmpWrapperType(&c)};
|
|
ompWrapperStack.push_back(ow);
|
|
return true;
|
|
}
|
|
|
|
void OpenMPCounterVisitor::Post(const OpenMPDeclarativeConstruct &) {
|
|
PostConstructsCommon();
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OpenMPConstruct &) {
|
|
PostConstructsCommon();
|
|
}
|
|
void OpenMPCounterVisitor::PostConstructsCommon() {
|
|
OmpWrapperType *curConstruct = ompWrapperStack.back();
|
|
std::sort(
|
|
clauseStrings[curConstruct].begin(), clauseStrings[curConstruct].end());
|
|
|
|
SourcePosition s{getLocation(*curConstruct)};
|
|
LogRecord r{
|
|
s.path, s.line, getName(*curConstruct), clauseStrings[curConstruct]};
|
|
constructClauses.push_back(r);
|
|
|
|
auto it = clauseStrings.find(curConstruct);
|
|
clauseStrings.erase(it);
|
|
ompWrapperStack.pop_back();
|
|
delete curConstruct;
|
|
}
|
|
|
|
void OpenMPCounterVisitor::Post(const OmpProcBindClause::AffinityPolicy &c) {
|
|
clauseDetails +=
|
|
"type=" + std::string{OmpProcBindClause::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(
|
|
const OmpDefaultClause::DataSharingAttribute &c) {
|
|
clauseDetails +=
|
|
"type=" + std::string{OmpDefaultClause::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(
|
|
const OmpDeviceTypeClause::DeviceTypeDescription &c) {
|
|
clauseDetails +=
|
|
"type=" + std::string{OmpDeviceTypeClause::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(
|
|
const OmpDefaultmapClause::ImplicitBehavior &c) {
|
|
clauseDetails +=
|
|
"implicit_behavior=" + std::string{OmpDefaultmapClause::EnumToString(c)} +
|
|
";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpVariableCategory::Value &c) {
|
|
clauseDetails +=
|
|
"variable_category=" + std::string{OmpVariableCategory::EnumToString(c)} +
|
|
";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpChunkModifier::Value &c) {
|
|
clauseDetails +=
|
|
"modifier=" + std::string{OmpChunkModifier::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpLinearModifier::Value &c) {
|
|
clauseDetails +=
|
|
"modifier=" + std::string{OmpLinearModifier::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpOrderingModifier::Value &c) {
|
|
clauseDetails +=
|
|
"modifier=" + std::string{OmpOrderingModifier::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpTaskDependenceType::Value &c) {
|
|
clauseDetails +=
|
|
"type=" + std::string{OmpTaskDependenceType::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpMapType::Value &c) {
|
|
clauseDetails += "type=" + std::string{OmpMapType::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpScheduleClause::Kind &c) {
|
|
clauseDetails +=
|
|
"type=" + std::string{OmpScheduleClause::EnumToString(c)} + ";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpDirectiveNameModifier &c) {
|
|
clauseDetails += "name_modifier=" +
|
|
llvm::omp::getOpenMPDirectiveName(c.v, llvm::omp::FallbackVersion).str() +
|
|
";";
|
|
}
|
|
void OpenMPCounterVisitor::Post(const OmpClause &c) {
|
|
PostClauseCommon(normalize_clause_name(c.source.ToString()));
|
|
clauseDetails.clear();
|
|
}
|
|
void OpenMPCounterVisitor::PostClauseCommon(const ClauseInfo &ci) {
|
|
assert(
|
|
!ompWrapperStack.empty() && "Construct should be visited before clause");
|
|
clauseStrings[ompWrapperStack.back()].push_back(ci);
|
|
}
|
|
} // namespace parser
|
|
} // namespace Fortran
|