Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -127,6 +127,7 @@ struct AADepGraphNode; struct AADepGraph; +struct AASchedulingGraph; struct Attributor; struct AbstractAttribute; struct InformationCache; @@ -216,6 +217,17 @@ void print(); }; +struct AASchedulingGraph { + AASchedulingGraph(AADepGraph *DepGraph) : DepGraph(DepGraph) {} + ~AASchedulingGraph() {} + void dumpGraph(); + + enum SchedulingState { IDLE_OR_FIXPOINT, UPDATING, NEEDS_UPDATE }; + + DenseMap AttributeSchedulingState; + AADepGraph *DepGraph; +}; + /// Helper to describe and deal with positions in the LLVM-IR. /// /// A position in the IR is described by an anchor value and an "offset" that @@ -890,7 +902,7 @@ CallGraphUpdater &CGUpdater, DenseSet *Allowed = nullptr) : Allocator(InfoCache.Allocator), Functions(Functions), - InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed), + InfoCache(InfoCache), CGUpdater(CGUpdater), SG(&DG), Allowed(Allowed), SeedingPeriod(true) {} ~Attributor(); @@ -1416,6 +1428,9 @@ /// Also adjust the state if we know further updates are not necessary. ChangeStatus updateAA(AbstractAttribute &AA); + /// Dump a new scheduling graph. + void invalidateSchedulingGraph(); + /// Remember the dependences on the top of the dependence stack such that they /// may trigger further updates. (\see DependenceStack) void rememberDependences(); @@ -1465,6 +1480,10 @@ /// Abstract Attribute dependency graph AADepGraph DG; + /// Abstract Attribute scheduling graph. Used for visualizing the way the + /// Schedules Abstarct Attributes. + AASchedulingGraph SG; + /// Set of functions for which we modified the content such that it might /// impact the call graph. SmallPtrSet CGModifiedFunctions; Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -106,6 +106,11 @@ "allowed to be seeded."), cl::ZeroOrMore, cl::CommaSeparated); +static cl::opt + DumpSchedulingGraph("attributor-dump-scheduling-graph", cl::Hidden, + cl::desc("Dump the scheduling graph to dot files."), + cl::init(false)); + /// Logic operators for the change status enum class. /// ///{ @@ -1044,6 +1049,7 @@ ChangedAA->Deps.pop_back(); } } + invalidateSchedulingGraph(); LLVM_DEBUG({ if (!Visited.empty()) @@ -1097,6 +1103,7 @@ NumAtFixpoint++; NumManifested += (LocalChange == ChangeStatus::CHANGED); } + invalidateSchedulingGraph(); (void)NumManifested; (void)NumAtFixpoint; @@ -1304,11 +1311,21 @@ return ManifestChange | CleanupChange; } +void Attributor::invalidateSchedulingGraph() { + if (DumpSchedulingGraph) { + SG.dumpGraph(); + } +} + ChangeStatus Attributor::updateAA(AbstractAttribute &AA) { // Use a new dependence vector for this update. DependenceVector DV; DependenceStack.push_back(&DV); + if (DumpSchedulingGraph) + SG.AttributeSchedulingState[&AA] = AASchedulingGraph::UPDATING; + invalidateSchedulingGraph(); + auto &AAState = AA.getState(); ChangeStatus CS = ChangeStatus::UNCHANGED; if (!isAssumedDead(AA, nullptr, /* CheckBBLivenessOnly */ true)) @@ -1320,9 +1337,20 @@ AAState.indicateOptimisticFixpoint(); } + if (DumpSchedulingGraph) { + for (DepInfo depInfo : DV) { + SG.AttributeSchedulingState[depInfo.ToAA] = + AASchedulingGraph::NEEDS_UPDATE; + } + } + if (!AAState.isAtFixpoint()) rememberDependences(); + if (DumpSchedulingGraph) + SG.AttributeSchedulingState[AA] = AASchedulingGraph::IDLE_OR_FIXPOINT; + invalidateSchedulingGraph(); + // Verify the stack was used properly, that is we pop the dependence vector we // put there earlier. DependenceVector *PoppedDV = DependenceStack.pop_back_val(); @@ -2183,6 +2211,24 @@ AA->printDeps(errs()); } +void AASchedulingGraph::dumpGraph() { + static int CallTimes = 0; + + // Pad the number for names to sort properly. + std::string Number = std::to_string(CallTimes); + std::string Filename = + "sg_dot_file_" + std::string(10 - Number.size(), '0') + Number + ".dot"; + errs() << "Scheduling 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++; +} + PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) { FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); @@ -2272,6 +2318,53 @@ } }; +template <> +struct GraphTraits : public GraphTraits { + static NodeRef getEntryNode(AADepGraph *DG) { return DG->GetEntryNode(); } + + using nodes_iterator = + mapped_iterator::iterator, decltype(&DepGetVal)>; + + static nodes_iterator nodes_begin(AASchedulingGraph *SG) { + return SG->DepGraph->begin(); + } + + static nodes_iterator nodes_end(AASchedulingGraph *SG) { + return SG->DepGraph->end(); + } +}; + +template <> +struct DOTGraphTraits : public DefaultDOTGraphTraits { + DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const AADepGraphNode *Node, + const AASchedulingGraph *DG) { + std::string AAString = ""; + raw_string_ostream O(AAString); + Node->print(O); + return AAString; + } + + static std::string getNodeAttributes(const AADepGraphNode *DepNode, + AASchedulingGraph *SG) { + const AbstractAttribute *Node = (const AbstractAttribute *)DepNode; + if (Node->getState().isAtFixpoint()) + return "color=\"blue\""; + if (!Node->getState().isValidState()) + return "color=\"red\""; + + switch (SG->AttributeSchedulingState[Node]) { + case AASchedulingGraph::IDLE_OR_FIXPOINT: + return "color=\"white\""; + case AASchedulingGraph::UPDATING: + return "color=\"green\""; + case AASchedulingGraph::NEEDS_UPDATE: + return "color=\"brown\""; + } + llvm_unreachable("All cases covered!"); + } +}; } // end namespace llvm namespace {