1 //===-- lib/Semantics/unparse-with-symbols.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 "flang/Semantics/unparse-with-symbols.h" 10 #include "mod-file.h" 11 #include "flang/Parser/parse-tree-visitor.h" 12 #include "flang/Parser/parse-tree.h" 13 #include "flang/Parser/unparse.h" 14 #include "flang/Semantics/symbol.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include <map> 17 #include <set> 18 19 namespace Fortran::semantics { 20 21 // Walk the parse tree and collection information about which statements 22 // reference symbols. Then PrintSymbols outputs information by statement. 23 // The first reference to a symbol is treated as its definition and more 24 // information is included. 25 class SymbolDumpVisitor { 26 public: 27 // Write out symbols referenced at this statement. 28 void PrintSymbols(const parser::CharBlock &, llvm::raw_ostream &, int); 29 30 template <typename T> bool Pre(const T &) { return true; } 31 template <typename T> void Post(const T &) {} 32 template <typename T> bool Pre(const parser::Statement<T> &stmt) { 33 currStmt_ = stmt.source; 34 return true; 35 } 36 template <typename T> void Post(const parser::Statement<T> &) { 37 currStmt_ = std::nullopt; 38 } 39 bool Pre(const parser::AccClause &clause) { 40 currStmt_ = clause.source; 41 return true; 42 } 43 void Post(const parser::AccClause &) { currStmt_ = std::nullopt; } 44 bool Pre(const parser::OmpClause &clause) { 45 currStmt_ = clause.source; 46 return true; 47 } 48 void Post(const parser::OmpClause &) { currStmt_ = std::nullopt; } 49 bool Pre(const parser::OpenMPThreadprivate &dir) { 50 currStmt_ = dir.source; 51 return true; 52 } 53 void Post(const parser::OpenMPThreadprivate &) { currStmt_ = std::nullopt; } 54 void Post(const parser::Name &name); 55 56 bool Pre(const parser::OpenMPDeclareMapperConstruct &x) { 57 currStmt_ = x.source; 58 return true; 59 } 60 void Post(const parser::OpenMPDeclareMapperConstruct &) { 61 currStmt_ = std::nullopt; 62 } 63 64 private: 65 std::optional<SourceName> currStmt_; // current statement we are processing 66 std::multimap<const char *, const Symbol *> symbols_; // location to symbol 67 std::set<const Symbol *> symbolsDefined_; // symbols that have been processed 68 void Indent(llvm::raw_ostream &, int) const; 69 }; 70 71 void SymbolDumpVisitor::PrintSymbols( 72 const parser::CharBlock &location, llvm::raw_ostream &out, int indent) { 73 std::set<const Symbol *> done; // prevent duplicates on this line 74 auto range{symbols_.equal_range(location.begin())}; 75 for (auto it{range.first}; it != range.second; ++it) { 76 const auto *symbol{it->second}; 77 if (done.insert(symbol).second) { 78 bool firstTime{symbolsDefined_.insert(symbol).second}; 79 Indent(out, indent); 80 out << '!' << (firstTime ? "DEF"s : "REF"s) << ": "; 81 DumpForUnparse(out, *symbol, firstTime); 82 out << '\n'; 83 } 84 } 85 } 86 87 void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const { 88 for (int i{0}; i < indent; ++i) { 89 out << ' '; 90 } 91 } 92 93 void SymbolDumpVisitor::Post(const parser::Name &name) { 94 if (const auto *symbol{name.symbol}) { 95 if (!symbol->has<MiscDetails>()) { 96 symbols_.emplace(currStmt_.value().begin(), symbol); 97 } 98 } 99 } 100 101 void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program, 102 parser::Encoding encoding) { 103 SymbolDumpVisitor visitor; 104 parser::Walk(program, visitor); 105 parser::preStatementType preStatement{ 106 [&](const parser::CharBlock &location, llvm::raw_ostream &out, 107 int indent) { visitor.PrintSymbols(location, out, indent); }}; 108 parser::Unparse(out, program, encoding, false, true, &preStatement); 109 } 110 111 // UnparseWithModules() 112 113 class UsedModuleVisitor { 114 public: 115 UnorderedSymbolSet &modulesUsed() { return modulesUsed_; } 116 UnorderedSymbolSet &modulesDefined() { return modulesDefined_; } 117 template <typename T> bool Pre(const T &) { return true; } 118 template <typename T> void Post(const T &) {} 119 void Post(const parser::ModuleStmt &module) { 120 if (module.v.symbol) { 121 modulesDefined_.insert(*module.v.symbol); 122 } 123 } 124 void Post(const parser::UseStmt &use) { 125 if (use.moduleName.symbol) { 126 modulesUsed_.insert(*use.moduleName.symbol); 127 } 128 } 129 130 private: 131 UnorderedSymbolSet modulesUsed_; 132 UnorderedSymbolSet modulesDefined_; 133 }; 134 135 void UnparseWithModules(llvm::raw_ostream &out, SemanticsContext &context, 136 const parser::Program &program, parser::Encoding encoding) { 137 UsedModuleVisitor visitor; 138 parser::Walk(program, visitor); 139 UnorderedSymbolSet nonIntrinsicModulesWritten{ 140 std::move(visitor.modulesDefined())}; 141 ModFileWriter writer{context}; 142 for (SymbolRef moduleRef : visitor.modulesUsed()) { 143 writer.WriteClosure(out, *moduleRef, nonIntrinsicModulesWritten); 144 } 145 parser::Unparse(out, program, encoding, false, true); 146 } 147 } // namespace Fortran::semantics 148