DDG.cpp 11 KB

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