2020-02-25 23:11:52 +08:00
|
|
|
//===-- lib/Semantics/unparse-with-symbols.cpp ----------------------------===//
|
2018-06-27 06:01:42 +08:00
|
|
|
//
|
2019-12-21 04:52:07 +08:00
|
|
|
// 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
|
2018-06-27 06:01:42 +08:00
|
|
|
//
|
2020-01-11 04:12:03 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2018-06-27 06:01:42 +08:00
|
|
|
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Semantics/unparse-with-symbols.h"
|
|
|
|
#include "flang/Parser/parse-tree-visitor.h"
|
|
|
|
#include "flang/Parser/parse-tree.h"
|
|
|
|
#include "flang/Parser/unparse.h"
|
|
|
|
#include "flang/Semantics/symbol.h"
|
2020-02-28 23:11:03 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-06-27 06:01:42 +08:00
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
|
|
|
|
// Walk the parse tree and collection information about which statements
|
2018-10-16 05:44:01 +08:00
|
|
|
// reference symbols. Then PrintSymbols outputs information by statement.
|
|
|
|
// The first reference to a symbol is treated as its definition and more
|
|
|
|
// information is included.
|
2018-06-27 06:01:42 +08:00
|
|
|
class SymbolDumpVisitor {
|
|
|
|
public:
|
2018-10-16 05:44:01 +08:00
|
|
|
// Write out symbols referenced at this statement.
|
2020-02-28 23:11:03 +08:00
|
|
|
void PrintSymbols(const parser::CharBlock &, llvm::raw_ostream &, int);
|
2018-06-27 06:01:42 +08:00
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T> bool Pre(const T &) { return true; }
|
|
|
|
template <typename T> void Post(const T &) {}
|
|
|
|
template <typename T> bool Pre(const parser::Statement<T> &stmt) {
|
2019-08-21 20:33:03 +08:00
|
|
|
currStmt_ = stmt.source;
|
2018-06-27 06:01:42 +08:00
|
|
|
return true;
|
|
|
|
}
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T> void Post(const parser::Statement<T> &) {
|
2019-08-21 20:33:03 +08:00
|
|
|
currStmt_ = std::nullopt;
|
2018-06-27 06:01:42 +08:00
|
|
|
}
|
2020-07-27 08:00:49 +08:00
|
|
|
bool Pre(const parser::AccClause &clause) {
|
|
|
|
currStmt_ = clause.source;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void Post(const parser::AccClause &) { currStmt_ = std::nullopt; }
|
[flang] [OpenMP] OmpVisitor framework for Name Resolution
This is a preliminary framework to do the name resolution for
data references on the OpenMP clauses. Unlike data references
in the OpenMP region, clauses determining the data-sharing or
data-mapping attributes are straightforward and the resolution
process could be extended to do the name resolution in the OpenMP
region. It is hard to determine what kind of checks can be done
in this visitor and what checks should be done later after name
resolution. But the guide line is that `After the completion of
this phase, every Name corresponds to a Symbol with proper OpenMP
attribute(s) determined unless an error occurred.`
1. Take data-sharing clauses as example, create new symbol for
variable that require private access within the OpenMP region.
Declare the entity implicitly if necessary. The new symbol has
`HostAssocDetails`, which is mentioned in the `OpenMP-semantics.md`.
2. For `Shared` or `ThreadPrivate`, no symbol needs to be created.
OpenMP attribute Flag `OmpThreadprivate` needs to be marked for
`Threadprivate` because the `threadprivate` attribute remains the
same whenever these variables are referenced in the program.
`Names` in `Shared` clause need to be resolved to associate the
symbols in the clause enclosing scope (contains the OpenMP directive)
but `OmpShared` does not need to be marked. Declare the entity
implicitly if necessary.
3. For `COMMON block`, when a named common block appears in a list,
it has the same meaning as if every explicit member of the common
block appeared in the list. Also, a common block name specified in
a data-sharing attribute clause must be declared to be a common
block in the same scoping unit in which the data-sharing attribute
clause appears. So, if a named common block appears on a `PRIVATE`
clause, all its members should have new symbols created within the
OpenMP region (scope). For later Semantic checks and CG, a new
symbol is also created for common block name with `HostAssocDetails`.
There are many things are still on the TODO list:
- Better error/warning messages with directive/clause source provenance
- Resolve variables referenced in the OpenMP region, for example,
`private(tt%a)` is not allowed but `tt%a = 1` is allowed in the
OpenMP region and a private version of `tt` maybe created for
the region. The functions created in the `OmpVisitor` should be
able to handle the name resolution on the statement too (more
data structures may be introduced). This is a big portion and may
require some interface changes to distinguish a reference is on
`OpenMP directive/clause` or `statements within OpenMP region`.
- Same data reference appears on multiple data-sharing clauses.
- Take association into consideration for example Pointer association,
`ASSOCIATE` construct, and etc.
- Handle `Array Sections` and `Array or Structure Element`.
- Handle all the name resolution for directives/clauses that have
`parser::Name`.
- More tests
Original-commit: flang-compiler/f18@b2ea520885eceb6e118f690b95e1846183fe378b
2019-09-12 05:42:51 +08:00
|
|
|
bool Pre(const parser::OmpClause &clause) {
|
|
|
|
currStmt_ = clause.source;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void Post(const parser::OmpClause &) { currStmt_ = std::nullopt; }
|
|
|
|
bool Pre(const parser::OpenMPThreadprivate &dir) {
|
|
|
|
currStmt_ = dir.source;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void Post(const parser::OpenMPThreadprivate &) { currStmt_ = std::nullopt; }
|
2018-10-16 05:44:01 +08:00
|
|
|
void Post(const parser::Name &name);
|
2018-06-27 06:01:42 +08:00
|
|
|
|
|
|
|
private:
|
2020-03-29 12:00:16 +08:00
|
|
|
std::optional<SourceName> currStmt_; // current statement we are processing
|
|
|
|
std::multimap<const char *, const Symbol *> symbols_; // location to symbol
|
|
|
|
std::set<const Symbol *> symbolsDefined_; // symbols that have been processed
|
2020-02-28 23:11:03 +08:00
|
|
|
void Indent(llvm::raw_ostream &, int) const;
|
2018-06-27 06:01:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void SymbolDumpVisitor::PrintSymbols(
|
2020-02-28 23:11:03 +08:00
|
|
|
const parser::CharBlock &location, llvm::raw_ostream &out, int indent) {
|
2020-03-29 12:00:16 +08:00
|
|
|
std::set<const Symbol *> done; // prevent duplicates on this line
|
2018-10-16 05:44:01 +08:00
|
|
|
auto range{symbols_.equal_range(location.begin())};
|
2018-06-27 06:01:42 +08:00
|
|
|
for (auto it{range.first}; it != range.second; ++it) {
|
2018-10-16 05:44:01 +08:00
|
|
|
const auto *symbol{it->second};
|
2018-06-27 06:01:42 +08:00
|
|
|
if (done.insert(symbol).second) {
|
2018-10-16 05:44:01 +08:00
|
|
|
bool firstTime{symbolsDefined_.insert(symbol).second};
|
2018-06-27 06:01:42 +08:00
|
|
|
Indent(out, indent);
|
2018-10-16 05:44:01 +08:00
|
|
|
out << '!' << (firstTime ? "DEF"s : "REF"s) << ": ";
|
|
|
|
DumpForUnparse(out, *symbol, firstTime);
|
2018-06-27 06:01:42 +08:00
|
|
|
out << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-10-16 05:44:01 +08:00
|
|
|
|
2020-02-28 23:11:03 +08:00
|
|
|
void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const {
|
2018-06-27 06:01:42 +08:00
|
|
|
for (int i{0}; i < indent; ++i) {
|
|
|
|
out << ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 05:44:01 +08:00
|
|
|
void SymbolDumpVisitor::Post(const parser::Name &name) {
|
2018-06-27 06:01:42 +08:00
|
|
|
if (const auto *symbol{name.symbol}) {
|
2018-11-17 04:43:08 +08:00
|
|
|
if (!symbol->has<MiscDetails>()) {
|
2019-08-21 20:33:03 +08:00
|
|
|
symbols_.emplace(currStmt_.value().begin(), symbol);
|
2018-11-17 04:43:08 +08:00
|
|
|
}
|
2018-06-27 06:01:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-28 23:11:03 +08:00
|
|
|
void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program,
|
2018-06-27 06:01:42 +08:00
|
|
|
parser::Encoding encoding) {
|
|
|
|
SymbolDumpVisitor visitor;
|
|
|
|
parser::Walk(program, visitor);
|
|
|
|
parser::preStatementType preStatement{
|
2020-02-28 23:11:03 +08:00
|
|
|
[&](const parser::CharBlock &location, llvm::raw_ostream &out,
|
|
|
|
int indent) { visitor.PrintSymbols(location, out, indent); }};
|
2018-07-20 06:35:55 +08:00
|
|
|
parser::Unparse(out, program, encoding, false, true, &preStatement);
|
2018-06-27 06:01:42 +08:00
|
|
|
}
|
2020-03-29 12:00:16 +08:00
|
|
|
} // namespace Fortran::semantics
|