DDG.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. //===- DDG.cpp - Data Dependence Graph -------------------------------------==//
  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. // The implementation for the data dependence graph.
  10. //===----------------------------------------------------------------------===//
  11. #include "llvm/Analysis/DDG.h"
  12. #include "llvm/ADT/SCCIterator.h"
  13. #include "llvm/Analysis/LoopInfo.h"
  14. #include "llvm/Analysis/LoopIterator.h"
  15. #include "llvm/Support/CommandLine.h"
  16. using namespace llvm;
  17. static cl::opt<bool> SimplifyDDG(
  18. "ddg-simplify", cl::init(true), cl::Hidden,
  19. cl::desc(
  20. "Simplify DDG by merging nodes that have less interesting edges."));
  21. static cl::opt<bool> CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden,
  22. cl::desc("Create pi-block nodes."));
  23. #define DEBUG_TYPE "ddg"
  24. template class llvm::DGEdge<DDGNode, DDGEdge>;
  25. template class llvm::DGNode<DDGNode, DDGEdge>;
  26. template class llvm::DirectedGraph<DDGNode, DDGEdge>;
  27. //===--------------------------------------------------------------------===//
  28. // DDGNode implementation
  29. //===--------------------------------------------------------------------===//
  30. DDGNode::~DDGNode() = default;
  31. bool DDGNode::collectInstructions(
  32. llvm::function_ref<bool(Instruction *)> const &Pred,
  33. InstructionListType &IList) const {
  34. assert(IList.empty() && "Expected the IList to be empty on entry.");
  35. if (isa<SimpleDDGNode>(this)) {
  36. for (Instruction *I : cast<const SimpleDDGNode>(this)->getInstructions())
  37. if (Pred(I))
  38. IList.push_back(I);
  39. } else if (isa<PiBlockDDGNode>(this)) {
  40. for (const DDGNode *PN : cast<const PiBlockDDGNode>(this)->getNodes()) {
  41. assert(!isa<PiBlockDDGNode>(PN) && "Nested PiBlocks are not supported.");
  42. SmallVector<Instruction *, 8> TmpIList;
  43. PN->collectInstructions(Pred, TmpIList);
  44. llvm::append_range(IList, TmpIList);
  45. }
  46. } else
  47. llvm_unreachable("unimplemented type of node");
  48. return !IList.empty();
  49. }
  50. raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode::NodeKind K) {
  51. const char *Out;
  52. switch (K) {
  53. case DDGNode::NodeKind::SingleInstruction:
  54. Out = "single-instruction";
  55. break;
  56. case DDGNode::NodeKind::MultiInstruction:
  57. Out = "multi-instruction";
  58. break;
  59. case DDGNode::NodeKind::PiBlock:
  60. Out = "pi-block";
  61. break;
  62. case DDGNode::NodeKind::Root:
  63. Out = "root";
  64. break;
  65. case DDGNode::NodeKind::Unknown:
  66. Out = "?? (error)";
  67. break;
  68. }
  69. OS << Out;
  70. return OS;
  71. }
  72. raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode &N) {
  73. OS << "Node Address:" << &N << ":" << N.getKind() << "\n";
  74. if (isa<SimpleDDGNode>(N)) {
  75. OS << " Instructions:\n";
  76. for (const Instruction *I : cast<const SimpleDDGNode>(N).getInstructions())
  77. OS.indent(2) << *I << "\n";
  78. } else if (isa<PiBlockDDGNode>(&N)) {
  79. OS << "--- start of nodes in pi-block ---\n";
  80. auto &Nodes = cast<const PiBlockDDGNode>(&N)->getNodes();
  81. unsigned Count = 0;
  82. for (const DDGNode *N : Nodes)
  83. OS << *N << (++Count == Nodes.size() ? "" : "\n");
  84. OS << "--- end of nodes in pi-block ---\n";
  85. } else if (!isa<RootDDGNode>(N))
  86. llvm_unreachable("unimplemented type of node");
  87. OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
  88. for (const auto &E : N.getEdges())
  89. OS.indent(2) << *E;
  90. return OS;
  91. }
  92. //===--------------------------------------------------------------------===//
  93. // SimpleDDGNode implementation
  94. //===--------------------------------------------------------------------===//
  95. SimpleDDGNode::SimpleDDGNode(Instruction &I)
  96. : DDGNode(NodeKind::SingleInstruction) {
  97. assert(InstList.empty() && "Expected empty list.");
  98. InstList.push_back(&I);
  99. }
  100. SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode &N)
  101. : DDGNode(N), InstList(N.InstList) {
  102. assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
  103. (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
  104. "constructing from invalid simple node.");
  105. }
  106. SimpleDDGNode::SimpleDDGNode(SimpleDDGNode &&N)
  107. : DDGNode(std::move(N)), InstList(std::move(N.InstList)) {
  108. assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
  109. (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
  110. "constructing from invalid simple node.");
  111. }
  112. SimpleDDGNode::~SimpleDDGNode() { InstList.clear(); }
  113. //===--------------------------------------------------------------------===//
  114. // PiBlockDDGNode implementation
  115. //===--------------------------------------------------------------------===//
  116. PiBlockDDGNode::PiBlockDDGNode(const PiNodeList &List)
  117. : DDGNode(NodeKind::PiBlock), NodeList(List) {
  118. assert(!NodeList.empty() && "pi-block node constructed with an empty list.");
  119. }
  120. PiBlockDDGNode::PiBlockDDGNode(const PiBlockDDGNode &N)
  121. : DDGNode(N), NodeList(N.NodeList) {
  122. assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&
  123. "constructing from invalid pi-block node.");
  124. }
  125. PiBlockDDGNode::PiBlockDDGNode(PiBlockDDGNode &&N)
  126. : DDGNode(std::move(N)), NodeList(std::move(N.NodeList)) {
  127. assert(getKind() == NodeKind::PiBlock && !NodeList.empty() &&
  128. "constructing from invalid pi-block node.");
  129. }
  130. PiBlockDDGNode::~PiBlockDDGNode() { NodeList.clear(); }
  131. //===--------------------------------------------------------------------===//
  132. // DDGEdge implementation
  133. //===--------------------------------------------------------------------===//
  134. raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K) {
  135. const char *Out;
  136. switch (K) {
  137. case DDGEdge::EdgeKind::RegisterDefUse:
  138. Out = "def-use";
  139. break;
  140. case DDGEdge::EdgeKind::MemoryDependence:
  141. Out = "memory";
  142. break;
  143. case DDGEdge::EdgeKind::Rooted:
  144. Out = "rooted";
  145. break;
  146. case DDGEdge::EdgeKind::Unknown:
  147. Out = "?? (error)";
  148. break;
  149. }
  150. OS << Out;
  151. return OS;
  152. }
  153. raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge &E) {
  154. OS << "[" << E.getKind() << "] to " << &E.getTargetNode() << "\n";
  155. return OS;
  156. }
  157. //===--------------------------------------------------------------------===//
  158. // DataDependenceGraph implementation
  159. //===--------------------------------------------------------------------===//
  160. using BasicBlockListType = SmallVector<BasicBlock *, 8>;
  161. DataDependenceGraph::DataDependenceGraph(Function &F, DependenceInfo &D)
  162. : DependenceGraphInfo(F.getName().str(), D) {
  163. // Put the basic blocks in program order for correct dependence
  164. // directions.
  165. BasicBlockListType BBList;
  166. for (const auto &SCC : make_range(scc_begin(&F), scc_end(&F)))
  167. append_range(BBList, SCC);
  168. std::reverse(BBList.begin(), BBList.end());
  169. DDGBuilder(*this, D, BBList).populate();
  170. }
  171. DataDependenceGraph::DataDependenceGraph(Loop &L, LoopInfo &LI,
  172. DependenceInfo &D)
  173. : DependenceGraphInfo(Twine(L.getHeader()->getParent()->getName() + "." +
  174. L.getHeader()->getName())
  175. .str(),
  176. D) {
  177. // Put the basic blocks in program order for correct dependence
  178. // directions.
  179. LoopBlocksDFS DFS(&L);
  180. DFS.perform(&LI);
  181. BasicBlockListType BBList;
  182. append_range(BBList, make_range(DFS.beginRPO(), DFS.endRPO()));
  183. DDGBuilder(*this, D, BBList).populate();
  184. }
  185. DataDependenceGraph::~DataDependenceGraph() {
  186. for (auto *N : Nodes) {
  187. for (auto *E : *N)
  188. delete E;
  189. delete N;
  190. }
  191. }
  192. bool DataDependenceGraph::addNode(DDGNode &N) {
  193. if (!DDGBase::addNode(N))
  194. return false;
  195. // In general, if the root node is already created and linked, it is not safe
  196. // to add new nodes since they may be unreachable by the root. However,
  197. // pi-block nodes need to be added after the root node is linked, and they are
  198. // always reachable by the root, because they represent components that are
  199. // already reachable by root.
  200. auto *Pi = dyn_cast<PiBlockDDGNode>(&N);
  201. assert((!Root || Pi) &&
  202. "Root node is already added. No more nodes can be added.");
  203. if (isa<RootDDGNode>(N))
  204. Root = &N;
  205. if (Pi)
  206. for (DDGNode *NI : Pi->getNodes())
  207. PiBlockMap.insert(std::make_pair(NI, Pi));
  208. return true;
  209. }
  210. const PiBlockDDGNode *DataDependenceGraph::getPiBlock(const NodeType &N) const {
  211. if (PiBlockMap.find(&N) == PiBlockMap.end())
  212. return nullptr;
  213. auto *Pi = PiBlockMap.find(&N)->second;
  214. assert(PiBlockMap.find(Pi) == PiBlockMap.end() &&
  215. "Nested pi-blocks detected.");
  216. return Pi;
  217. }
  218. raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) {
  219. for (DDGNode *Node : G)
  220. // Avoid printing nodes that are part of a pi-block twice. They will get
  221. // printed when the pi-block is printed.
  222. if (!G.getPiBlock(*Node))
  223. OS << *Node << "\n";
  224. OS << "\n";
  225. return OS;
  226. }
  227. //===--------------------------------------------------------------------===//
  228. // DDGBuilder implementation
  229. //===--------------------------------------------------------------------===//
  230. bool DDGBuilder::areNodesMergeable(const DDGNode &Src,
  231. const DDGNode &Tgt) const {
  232. // Only merge two nodes if they are both simple nodes and the consecutive
  233. // instructions after merging belong to the same BB.
  234. const auto *SimpleSrc = dyn_cast<const SimpleDDGNode>(&Src);
  235. const auto *SimpleTgt = dyn_cast<const SimpleDDGNode>(&Tgt);
  236. if (!SimpleSrc || !SimpleTgt)
  237. return false;
  238. return SimpleSrc->getLastInstruction()->getParent() ==
  239. SimpleTgt->getFirstInstruction()->getParent();
  240. }
  241. void DDGBuilder::mergeNodes(DDGNode &A, DDGNode &B) {
  242. DDGEdge &EdgeToFold = A.back();
  243. assert(A.getEdges().size() == 1 && EdgeToFold.getTargetNode() == B &&
  244. "Expected A to have a single edge to B.");
  245. assert(isa<SimpleDDGNode>(&A) && isa<SimpleDDGNode>(&B) &&
  246. "Expected simple nodes");
  247. // Copy instructions from B to the end of A.
  248. cast<SimpleDDGNode>(&A)->appendInstructions(*cast<SimpleDDGNode>(&B));
  249. // Move to A any outgoing edges from B.
  250. for (DDGEdge *BE : B)
  251. Graph.connect(A, BE->getTargetNode(), *BE);
  252. A.removeEdge(EdgeToFold);
  253. destroyEdge(EdgeToFold);
  254. Graph.removeNode(B);
  255. destroyNode(B);
  256. }
  257. bool DDGBuilder::shouldSimplify() const { return SimplifyDDG; }
  258. bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks; }
  259. //===--------------------------------------------------------------------===//
  260. // DDG Analysis Passes
  261. //===--------------------------------------------------------------------===//
  262. /// DDG as a loop pass.
  263. DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM,
  264. LoopStandardAnalysisResults &AR) {
  265. Function *F = L.getHeader()->getParent();
  266. DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);
  267. return std::make_unique<DataDependenceGraph>(L, AR.LI, DI);
  268. }
  269. AnalysisKey DDGAnalysis::Key;
  270. PreservedAnalyses DDGAnalysisPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
  271. LoopStandardAnalysisResults &AR,
  272. LPMUpdater &U) {
  273. OS << "'DDG' for loop '" << L.getHeader()->getName() << "':\n";
  274. OS << *AM.getResult<DDGAnalysis>(L, AR);
  275. return PreservedAnalyses::all();
  276. }