1*06c3fb27SDimitry Andric //===-- Logger.cpp --------------------------------------------------------===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric 9*06c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Logger.h" 10*06c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/ControlFlowContext.h" 11*06c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" 12*06c3fb27SDimitry Andric #include "llvm/Support/WithColor.h" 13*06c3fb27SDimitry Andric 14*06c3fb27SDimitry Andric namespace clang::dataflow { 15*06c3fb27SDimitry Andric 16*06c3fb27SDimitry Andric Logger &Logger::null() { 17*06c3fb27SDimitry Andric struct NullLogger final : Logger {}; 18*06c3fb27SDimitry Andric static auto *Instance = new NullLogger(); 19*06c3fb27SDimitry Andric return *Instance; 20*06c3fb27SDimitry Andric } 21*06c3fb27SDimitry Andric 22*06c3fb27SDimitry Andric namespace { 23*06c3fb27SDimitry Andric struct TextualLogger final : Logger { 24*06c3fb27SDimitry Andric llvm::raw_ostream &OS; 25*06c3fb27SDimitry Andric const CFG *CurrentCFG; 26*06c3fb27SDimitry Andric const CFGBlock *CurrentBlock; 27*06c3fb27SDimitry Andric const CFGElement *CurrentElement; 28*06c3fb27SDimitry Andric unsigned CurrentElementIndex; 29*06c3fb27SDimitry Andric bool ShowColors; 30*06c3fb27SDimitry Andric llvm::DenseMap<const CFGBlock *, unsigned> VisitCount; 31*06c3fb27SDimitry Andric TypeErasedDataflowAnalysis *CurrentAnalysis; 32*06c3fb27SDimitry Andric 33*06c3fb27SDimitry Andric TextualLogger(llvm::raw_ostream &OS) 34*06c3fb27SDimitry Andric : OS(OS), ShowColors(llvm::WithColor::defaultAutoDetectFunction()(OS)) {} 35*06c3fb27SDimitry Andric 36*06c3fb27SDimitry Andric virtual void beginAnalysis(const ControlFlowContext &CFG, 37*06c3fb27SDimitry Andric TypeErasedDataflowAnalysis &Analysis) override { 38*06c3fb27SDimitry Andric { 39*06c3fb27SDimitry Andric llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); 40*06c3fb27SDimitry Andric OS << "=== Beginning data flow analysis ===\n"; 41*06c3fb27SDimitry Andric } 42*06c3fb27SDimitry Andric if (auto *D = CFG.getDecl()) { 43*06c3fb27SDimitry Andric D->print(OS); 44*06c3fb27SDimitry Andric OS << "\n"; 45*06c3fb27SDimitry Andric D->dump(OS); 46*06c3fb27SDimitry Andric } 47*06c3fb27SDimitry Andric CurrentCFG = &CFG.getCFG(); 48*06c3fb27SDimitry Andric CurrentCFG->print(OS, Analysis.getASTContext().getLangOpts(), ShowColors); 49*06c3fb27SDimitry Andric CurrentAnalysis = &Analysis; 50*06c3fb27SDimitry Andric } 51*06c3fb27SDimitry Andric virtual void endAnalysis() override { 52*06c3fb27SDimitry Andric llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); 53*06c3fb27SDimitry Andric unsigned Blocks = 0, Steps = 0; 54*06c3fb27SDimitry Andric for (const auto &E : VisitCount) { 55*06c3fb27SDimitry Andric ++Blocks; 56*06c3fb27SDimitry Andric Steps += E.second; 57*06c3fb27SDimitry Andric } 58*06c3fb27SDimitry Andric llvm::errs() << "=== Finished analysis: " << Blocks << " blocks in " 59*06c3fb27SDimitry Andric << Steps << " total steps ===\n"; 60*06c3fb27SDimitry Andric } 61*06c3fb27SDimitry Andric virtual void enterBlock(const CFGBlock &Block) override { 62*06c3fb27SDimitry Andric unsigned Count = ++VisitCount[&Block]; 63*06c3fb27SDimitry Andric { 64*06c3fb27SDimitry Andric llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); 65*06c3fb27SDimitry Andric OS << "=== Entering block B" << Block.getBlockID() << " (iteration " 66*06c3fb27SDimitry Andric << Count << ") ===\n"; 67*06c3fb27SDimitry Andric } 68*06c3fb27SDimitry Andric Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(), 69*06c3fb27SDimitry Andric ShowColors); 70*06c3fb27SDimitry Andric CurrentBlock = &Block; 71*06c3fb27SDimitry Andric CurrentElement = nullptr; 72*06c3fb27SDimitry Andric CurrentElementIndex = 0; 73*06c3fb27SDimitry Andric } 74*06c3fb27SDimitry Andric virtual void enterElement(const CFGElement &Element) override { 75*06c3fb27SDimitry Andric ++CurrentElementIndex; 76*06c3fb27SDimitry Andric CurrentElement = ∈ 77*06c3fb27SDimitry Andric { 78*06c3fb27SDimitry Andric llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN, 79*06c3fb27SDimitry Andric /*Bold=*/true); 80*06c3fb27SDimitry Andric OS << "Processing element B" << CurrentBlock->getBlockID() << "." 81*06c3fb27SDimitry Andric << CurrentElementIndex << ": "; 82*06c3fb27SDimitry Andric Element.dumpToStream(OS); 83*06c3fb27SDimitry Andric } 84*06c3fb27SDimitry Andric } 85*06c3fb27SDimitry Andric void recordState(TypeErasedDataflowAnalysisState &State) override { 86*06c3fb27SDimitry Andric { 87*06c3fb27SDimitry Andric llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN, 88*06c3fb27SDimitry Andric /*Bold=*/true); 89*06c3fb27SDimitry Andric OS << "Computed state for B" << CurrentBlock->getBlockID() << "." 90*06c3fb27SDimitry Andric << CurrentElementIndex << ":\n"; 91*06c3fb27SDimitry Andric } 92*06c3fb27SDimitry Andric // FIXME: currently the environment dump is verbose and unenlightening. 93*06c3fb27SDimitry Andric // FIXME: dump the user-defined lattice, too. 94*06c3fb27SDimitry Andric State.Env.dump(OS); 95*06c3fb27SDimitry Andric OS << "\n"; 96*06c3fb27SDimitry Andric } 97*06c3fb27SDimitry Andric void blockConverged() override { 98*06c3fb27SDimitry Andric OS << "B" << CurrentBlock->getBlockID() << " has converged!\n"; 99*06c3fb27SDimitry Andric } 100*06c3fb27SDimitry Andric virtual void logText(llvm::StringRef S) override { OS << S << "\n"; } 101*06c3fb27SDimitry Andric }; 102*06c3fb27SDimitry Andric } // namespace 103*06c3fb27SDimitry Andric 104*06c3fb27SDimitry Andric std::unique_ptr<Logger> Logger::textual(llvm::raw_ostream &OS) { 105*06c3fb27SDimitry Andric return std::make_unique<TextualLogger>(OS); 106*06c3fb27SDimitry Andric } 107*06c3fb27SDimitry Andric 108*06c3fb27SDimitry Andric } // namespace clang::dataflow 109