Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -97,8 +97,10 @@ #ifndef LLVM_TRANSFORMS_IPO_ATTRIBUTOR_H #define LLVM_TRANSFORMS_IPO_ATTRIBUTOR_H +#include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SCCIterator.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumeBundleQueries.h" @@ -116,10 +118,13 @@ #include "llvm/IR/ConstantRange.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/GraphWriter.h" #include "llvm/Transforms/Utils/CallGraphUpdater.h" namespace llvm { +struct AADepGraph; struct Attributor; struct AbstractAttribute; struct InformationCache; @@ -912,6 +917,9 @@ /// Return the internal information cache. InformationCache &getInfoCache() { return InfoCache; } + /// Return the first element of the AA list + AbstractAttribute *getEntryAA() { return AllAbstractAttributes.front(); } + /// Return true if this is a module pass, false otherwise. bool isModulePass() const { return !Functions.empty() && @@ -1206,12 +1214,18 @@ bool checkForAllReadWriteInstructions(function_ref Pred, AbstractAttribute &QueryingAA); + /// Print All dependencies for every AbstractAttribute in the AA list + /// For debug use only. + void printAllDependency(raw_ostream &); + /// Return the data layout associated with the anchor scope. const DataLayout &getDataLayout() const { return InfoCache.DL; } /// The allocator used to allocate memory, e.g. for `AbstractAttribute`s. BumpPtrAllocator &Allocator; + AADepGraph *DG; + private: /// Run `::update` on \p AA and track the dependences queried while doing so. /// Also adjust the state if we know further updates are not necessary. @@ -1389,6 +1403,8 @@ SmallPtrSet ToBeDeletedFunctions; SmallPtrSet ToBeDeletedBlocks; SmallDenseSet ToBeDeletedInsts; + + friend AADepGraph; ///} }; @@ -1437,6 +1453,30 @@ virtual ChangeStatus indicatePessimisticFixpoint() = 0; }; +/// The data structure for the dependency graph +struct AADepGraph { + AADepGraph(Attributor &A) : A(A) {} + ~AADepGraph() {} + + Attributor &A; + + using AAVector = SmallVector; + + AbstractAttribute *GetEntryNode() const { + return A.AllAbstractAttributes.front(); + } + + using iterator = AAVector::iterator; + + iterator begin() { return A.AllAbstractAttributes.begin(); } + iterator end() { return A.AllAbstractAttributes.end(); } + + void viewGraph(); + + /// Dump graph to file + void dumpGraph(); +}; + /// Simple state with integers encoding. /// /// The interface ensures that the assumed bits are always a subset of the known @@ -2038,6 +2078,9 @@ /// if there is an optional of required dependence. using DepTy = PointerIntPair; TinyPtrVector Deps; + +public: + TinyPtrVector &getDeps() { return Deps; } }; /// Forward declarations of output streams for debug purposes. Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -15,7 +15,10 @@ #include "llvm/Transforms/IPO/Attributor.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Analysis/LazyValueInfo.h" #include "llvm/Analysis/MustExecute.h" #include "llvm/Analysis/ValueTracking.h" @@ -23,10 +26,15 @@ #include "llvm/IR/NoFolder.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include +#include using namespace llvm; @@ -77,6 +85,15 @@ "wrappers for non-exact definitions."), cl::init(false)); +static cl::opt + DumpDepGraph("attributor-dump-dep-graph", cl::Hidden, + cl::desc("Dump the dependency graph to dot files."), + cl::init(false)); + +static cl::opt ViewDepGraph("attributor-view-dep-graph", cl::Hidden, + cl::desc("View the dependency graph."), + cl::init(false)); + /// Logic operators for the change status enum class. /// ///{ @@ -2021,6 +2038,8 @@ // while we identify default attribute opportunities. Attributor A(Functions, InfoCache, CGUpdater); + A.DG = new AADepGraph(A); + // Create shallow wrappers for all functions that are not IPO amendable if (AllowShallowWrappers) for (Function *F : Functions) @@ -2034,8 +2053,8 @@ NumFnWithoutExactDefinition++; // We look at internal functions only on-demand but if any use is not a - // direct call or outside the current set of analyzed functions, we have to - // do it eagerly. + // direct call or outside the current set of analyzed functions, we have + // to do it eagerly. if (F->hasLocalLinkage()) { if (llvm::all_of(F->uses(), [&Functions](const Use &U) { const auto *CB = dyn_cast(U.getUser()); @@ -2051,11 +2070,106 @@ } ChangeStatus Changed = A.run(); + + if (DumpDepGraph) + A.DG->dumpGraph(); + + if (ViewDepGraph) + A.DG->viewGraph(); + LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() << " functions, result: " << Changed << ".\n"); return Changed == ChangeStatus::CHANGED; } +void Attributor::printAllDependency(raw_ostream &OS) { + for (AbstractAttribute *AA : AllAbstractAttributes) { + OS << "-+ "; + AA->print(OS); + OS << "\n"; + + for (auto DepAAPair : AA->getDeps()) { + AbstractAttribute *DepAA = DepAAPair.getPointer(); + OS << "--* "; + DepAA->print(OS); + OS << "\n"; + } + + OS << "\n"; + } +} + +void AADepGraph::viewGraph() { llvm::ViewGraph(this, "Dependency Graph"); } + +void AADepGraph::dumpGraph() { + static int CallTimes = 0; + std::string Filename = "dot_file_" + std::to_string(CallTimes) + ".dot"; + + errs() << "Dependency graph dump to " << Filename << ".\n"; + + std::error_code EC; + + raw_fd_ostream File(Filename, EC, sys::fs::OF_Text); + if (!EC) + llvm::WriteGraph(File, this); + + CallTimes++; +} + +template <> struct llvm::GraphTraits { + using NodeRef = AbstractAttribute *; + using DepTy = PointerIntPair; + using EdgeRef = PointerIntPair; + + static NodeRef getEntryNode(AbstractAttribute *AA) { return AA; } + static NodeRef DepGetVal(DepTy &DT) { return DT.getPointer(); } + + using ChildIteratorType = + mapped_iterator::iterator, decltype(&DepGetVal)>; + using ChildEdgeIteratorType = TinyPtrVector::iterator; + + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->getDeps().begin(), &DepGetVal); + } + + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->getDeps().end(), &DepGetVal); + } + + static ChildEdgeIteratorType child_edge_begin(NodeRef N) { + return N->getDeps().begin(); + } + + static ChildEdgeIteratorType child_edge_end(NodeRef N) { + return N->getDeps().end(); + } +}; + +template <> +struct llvm::GraphTraits + : public GraphTraits { + static NodeRef getEntryNode(AADepGraph *DG) { return DG->GetEntryNode(); } + + using nodes_iterator = SmallVector::iterator; + + static nodes_iterator nodes_begin(AADepGraph *DG) { return DG->begin(); } + + static nodes_iterator nodes_end(AADepGraph *DG) { return DG->end(); } +}; + +template <> +struct llvm::DOTGraphTraits : public DefaultDOTGraphTraits { + DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const AbstractAttribute *Node, + const AADepGraph *DG) { + std::string AAString = ""; + raw_string_ostream O(AAString); + Node->print(O); + return AAString; + } +}; + PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) { FunctionAnalysisManager &FAM = AM.getResult(M).getManager();