diff options
Diffstat (limited to 'clang-r353983/include/llvm/Analysis/CFGPrinter.h')
| -rw-r--r-- | clang-r353983/include/llvm/Analysis/CFGPrinter.h | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/clang-r353983/include/llvm/Analysis/CFGPrinter.h b/clang-r353983/include/llvm/Analysis/CFGPrinter.h new file mode 100644 index 00000000..aaefc116 --- /dev/null +++ b/clang-r353983/include/llvm/Analysis/CFGPrinter.h @@ -0,0 +1,185 @@ +//===-- CFGPrinter.h - CFG printer external interface -----------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines a 'dot-cfg' analysis pass, which emits the +// cfg.<fnname>.dot file for each function in the program, with a graph of the +// CFG for that function. +// +// This file defines external functions that can be called to explicitly +// instantiate the CFG printer. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CFGPRINTER_H +#define LLVM_ANALYSIS_CFGPRINTER_H + +#include "llvm/IR/CFG.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Support/GraphWriter.h" + +namespace llvm { +class CFGViewerPass + : public PassInfoMixin<CFGViewerPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +class CFGOnlyViewerPass + : public PassInfoMixin<CFGOnlyViewerPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +class CFGPrinterPass + : public PassInfoMixin<CFGPrinterPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +class CFGOnlyPrinterPass + : public PassInfoMixin<CFGOnlyPrinterPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +template<> +struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getGraphName(const Function *F) { + return "CFG for '" + F->getName().str() + "' function"; + } + + static std::string getSimpleNodeLabel(const BasicBlock *Node, + const Function *) { + if (!Node->getName().empty()) + return Node->getName().str(); + + std::string Str; + raw_string_ostream OS(Str); + + Node->printAsOperand(OS, false); + return OS.str(); + } + + static std::string getCompleteNodeLabel(const BasicBlock *Node, + const Function *) { + enum { MaxColumns = 80 }; + std::string Str; + raw_string_ostream OS(Str); + + if (Node->getName().empty()) { + Node->printAsOperand(OS, false); + OS << ":"; + } + + OS << *Node; + std::string OutStr = OS.str(); + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + unsigned ColNum = 0; + unsigned LastSpace = 0; + for (unsigned i = 0; i != OutStr.length(); ++i) { + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + ColNum = 0; + LastSpace = 0; + } else if (OutStr[i] == ';') { // Delete comments! + unsigned Idx = OutStr.find('\n', i+1); // Find end of line + OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); + --i; + } else if (ColNum == MaxColumns) { // Wrap lines. + // Wrap very long names even though we can't find a space. + if (!LastSpace) + LastSpace = i; + OutStr.insert(LastSpace, "\\l..."); + ColNum = i - LastSpace; + LastSpace = 0; + i += 3; // The loop will advance 'i' again. + } + else + ++ColNum; + if (OutStr[i] == ' ') + LastSpace = i; + } + return OutStr; + } + + std::string getNodeLabel(const BasicBlock *Node, + const Function *Graph) { + if (isSimple()) + return getSimpleNodeLabel(Node, Graph); + else + return getCompleteNodeLabel(Node, Graph); + } + + static std::string getEdgeSourceLabel(const BasicBlock *Node, + succ_const_iterator I) { + // Label source of conditional branches with "T" or "F" + if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) + if (BI->isConditional()) + return (I == succ_begin(Node)) ? "T" : "F"; + + // Label source of switch edges with the associated value. + if (const SwitchInst *SI = dyn_cast<SwitchInst>(Node->getTerminator())) { + unsigned SuccNo = I.getSuccessorIndex(); + + if (SuccNo == 0) return "def"; + + std::string Str; + raw_string_ostream OS(Str); + auto Case = *SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo); + OS << Case.getCaseValue()->getValue(); + return OS.str(); + } + return ""; + } + + /// Display the raw branch weights from PGO. + std::string getEdgeAttributes(const BasicBlock *Node, succ_const_iterator I, + const Function *F) { + const Instruction *TI = Node->getTerminator(); + if (TI->getNumSuccessors() == 1) + return ""; + + MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof); + if (!WeightsNode) + return ""; + + MDString *MDName = cast<MDString>(WeightsNode->getOperand(0)); + if (MDName->getString() != "branch_weights") + return ""; + + unsigned OpNo = I.getSuccessorIndex() + 1; + if (OpNo >= WeightsNode->getNumOperands()) + return ""; + ConstantInt *Weight = + mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo)); + if (!Weight) + return ""; + + // Prepend a 'W' to indicate that this is a weight rather than the actual + // profile count (due to scaling). + return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str(); + } +}; +} // End llvm namespace + +namespace llvm { + class FunctionPass; + FunctionPass *createCFGPrinterLegacyPassPass (); + FunctionPass *createCFGOnlyPrinterLegacyPassPass (); +} // End llvm namespace + +#endif |
