File indexing completed on 2026-05-10 08:43:12
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_ANALYSIS_DDG_H
0014 #define LLVM_ANALYSIS_DDG_H
0015
0016 #include "llvm/ADT/DenseMap.h"
0017 #include "llvm/ADT/DirectedGraph.h"
0018 #include "llvm/Analysis/DependenceAnalysis.h"
0019 #include "llvm/Analysis/DependenceGraphBuilder.h"
0020 #include "llvm/Analysis/LoopAnalysisManager.h"
0021
0022 namespace llvm {
0023 class Function;
0024 class Loop;
0025 class LoopInfo;
0026 class DDGNode;
0027 class DDGEdge;
0028 using DDGNodeBase = DGNode<DDGNode, DDGEdge>;
0029 using DDGEdgeBase = DGEdge<DDGNode, DDGEdge>;
0030 using DDGBase = DirectedGraph<DDGNode, DDGEdge>;
0031 class LPMUpdater;
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 class DDGNode : public DDGNodeBase {
0045 public:
0046 using InstructionListType = SmallVectorImpl<Instruction *>;
0047
0048 enum class NodeKind {
0049 Unknown,
0050 SingleInstruction,
0051 MultiInstruction,
0052 PiBlock,
0053 Root,
0054 };
0055
0056 DDGNode() = delete;
0057 DDGNode(const NodeKind K) : Kind(K) {}
0058 DDGNode(const DDGNode &N) = default;
0059 DDGNode(DDGNode &&N) : DDGNodeBase(std::move(N)), Kind(N.Kind) {}
0060 virtual ~DDGNode() = 0;
0061
0062 DDGNode &operator=(const DDGNode &N) {
0063 DGNode::operator=(N);
0064 Kind = N.Kind;
0065 return *this;
0066 }
0067
0068 DDGNode &operator=(DDGNode &&N) {
0069 DGNode::operator=(std::move(N));
0070 Kind = N.Kind;
0071 return *this;
0072 }
0073
0074
0075 NodeKind getKind() const { return Kind; }
0076
0077
0078
0079
0080 bool collectInstructions(llvm::function_ref<bool(Instruction *)> const &Pred,
0081 InstructionListType &IList) const;
0082
0083 protected:
0084
0085 void setKind(NodeKind K) { Kind = K; }
0086
0087 private:
0088 NodeKind Kind;
0089 };
0090
0091
0092
0093 class RootDDGNode : public DDGNode {
0094 public:
0095 RootDDGNode() : DDGNode(NodeKind::Root) {}
0096 RootDDGNode(const RootDDGNode &N) = delete;
0097 RootDDGNode(RootDDGNode &&N) : DDGNode(std::move(N)) {}
0098 ~RootDDGNode() = default;
0099
0100
0101 static bool classof(const DDGNode *N) {
0102 return N->getKind() == NodeKind::Root;
0103 }
0104 static bool classof(const RootDDGNode *N) { return true; }
0105 };
0106
0107
0108 class SimpleDDGNode : public DDGNode {
0109 friend class DDGBuilder;
0110
0111 public:
0112 SimpleDDGNode() = delete;
0113 SimpleDDGNode(Instruction &I);
0114 SimpleDDGNode(const SimpleDDGNode &N);
0115 SimpleDDGNode(SimpleDDGNode &&N);
0116 ~SimpleDDGNode();
0117
0118 SimpleDDGNode &operator=(const SimpleDDGNode &N) = default;
0119
0120 SimpleDDGNode &operator=(SimpleDDGNode &&N) {
0121 DDGNode::operator=(std::move(N));
0122 InstList = std::move(N.InstList);
0123 return *this;
0124 }
0125
0126
0127 const InstructionListType &getInstructions() const {
0128 assert(!InstList.empty() && "Instruction List is empty.");
0129 return InstList;
0130 }
0131 InstructionListType &getInstructions() {
0132 return const_cast<InstructionListType &>(
0133 static_cast<const SimpleDDGNode *>(this)->getInstructions());
0134 }
0135
0136
0137 Instruction *getFirstInstruction() const { return getInstructions().front(); }
0138 Instruction *getLastInstruction() const { return getInstructions().back(); }
0139
0140
0141 static bool classof(const DDGNode *N) {
0142 return N->getKind() == NodeKind::SingleInstruction ||
0143 N->getKind() == NodeKind::MultiInstruction;
0144 }
0145 static bool classof(const SimpleDDGNode *N) { return true; }
0146
0147 private:
0148
0149 void appendInstructions(const InstructionListType &Input) {
0150 setKind((InstList.size() == 0 && Input.size() == 1)
0151 ? NodeKind::SingleInstruction
0152 : NodeKind::MultiInstruction);
0153 llvm::append_range(InstList, Input);
0154 }
0155 void appendInstructions(const SimpleDDGNode &Input) {
0156 appendInstructions(Input.getInstructions());
0157 }
0158
0159
0160 SmallVector<Instruction *, 2> InstList;
0161 };
0162
0163
0164
0165
0166
0167
0168
0169
0170 class PiBlockDDGNode : public DDGNode {
0171 public:
0172 using PiNodeList = SmallVector<DDGNode *, 4>;
0173
0174 PiBlockDDGNode() = delete;
0175 PiBlockDDGNode(const PiNodeList &List);
0176 PiBlockDDGNode(const PiBlockDDGNode &N);
0177 PiBlockDDGNode(PiBlockDDGNode &&N);
0178 ~PiBlockDDGNode();
0179
0180 PiBlockDDGNode &operator=(const PiBlockDDGNode &N) = default;
0181
0182 PiBlockDDGNode &operator=(PiBlockDDGNode &&N) {
0183 DDGNode::operator=(std::move(N));
0184 NodeList = std::move(N.NodeList);
0185 return *this;
0186 }
0187
0188
0189 const PiNodeList &getNodes() const {
0190 assert(!NodeList.empty() && "Node list is empty.");
0191 return NodeList;
0192 }
0193 PiNodeList &getNodes() {
0194 return const_cast<PiNodeList &>(
0195 static_cast<const PiBlockDDGNode *>(this)->getNodes());
0196 }
0197
0198
0199 static bool classof(const DDGNode *N) {
0200 return N->getKind() == NodeKind::PiBlock;
0201 }
0202
0203 private:
0204
0205 PiNodeList NodeList;
0206 };
0207
0208
0209
0210
0211
0212
0213 class DDGEdge : public DDGEdgeBase {
0214 public:
0215
0216 enum class EdgeKind {
0217 Unknown,
0218 RegisterDefUse,
0219 MemoryDependence,
0220 Rooted,
0221 Last = Rooted
0222 };
0223
0224 explicit DDGEdge(DDGNode &N) = delete;
0225 DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {}
0226 DDGEdge(const DDGEdge &E) : DDGEdgeBase(E), Kind(E.getKind()) {}
0227 DDGEdge(DDGEdge &&E) : DDGEdgeBase(std::move(E)), Kind(E.Kind) {}
0228 DDGEdge &operator=(const DDGEdge &E) = default;
0229
0230 DDGEdge &operator=(DDGEdge &&E) {
0231 DDGEdgeBase::operator=(std::move(E));
0232 Kind = E.Kind;
0233 return *this;
0234 }
0235
0236
0237 EdgeKind getKind() const { return Kind; };
0238
0239
0240 bool isDefUse() const { return Kind == EdgeKind::RegisterDefUse; }
0241
0242
0243 bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; }
0244
0245
0246
0247 bool isRooted() const { return Kind == EdgeKind::Rooted; }
0248
0249 private:
0250 EdgeKind Kind;
0251 };
0252
0253
0254
0255 template <typename NodeType> class DependenceGraphInfo {
0256 public:
0257 using DependenceList = SmallVector<std::unique_ptr<Dependence>, 1>;
0258
0259 DependenceGraphInfo() = delete;
0260 DependenceGraphInfo(const DependenceGraphInfo &G) = delete;
0261 DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo)
0262 : Name(N), DI(DepInfo), Root(nullptr) {}
0263 DependenceGraphInfo(DependenceGraphInfo &&G)
0264 : Name(std::move(G.Name)), DI(std::move(G.DI)), Root(G.Root) {}
0265 virtual ~DependenceGraphInfo() = default;
0266
0267
0268 StringRef getName() const { return Name; }
0269
0270
0271 NodeType &getRoot() const {
0272 assert(Root && "Root node is not available yet. Graph construction may "
0273 "still be in progress\n");
0274 return *Root;
0275 }
0276
0277
0278
0279
0280 bool getDependencies(const NodeType &Src, const NodeType &Dst,
0281 DependenceList &Deps) const;
0282
0283
0284
0285
0286 std::string getDependenceString(const NodeType &Src,
0287 const NodeType &Dst) const;
0288
0289 protected:
0290
0291 std::string Name;
0292
0293
0294
0295
0296 const DependenceInfo DI;
0297
0298
0299
0300 NodeType *Root = nullptr;
0301 };
0302
0303 using DDGInfo = DependenceGraphInfo<DDGNode>;
0304
0305
0306 class DataDependenceGraph : public DDGBase, public DDGInfo {
0307 friend AbstractDependenceGraphBuilder<DataDependenceGraph>;
0308 friend class DDGBuilder;
0309
0310 public:
0311 using NodeType = DDGNode;
0312 using EdgeType = DDGEdge;
0313
0314 DataDependenceGraph() = delete;
0315 DataDependenceGraph(const DataDependenceGraph &G) = delete;
0316 DataDependenceGraph(DataDependenceGraph &&G)
0317 : DDGBase(std::move(G)), DDGInfo(std::move(G)) {}
0318 DataDependenceGraph(Function &F, DependenceInfo &DI);
0319 DataDependenceGraph(Loop &L, LoopInfo &LI, DependenceInfo &DI);
0320 ~DataDependenceGraph();
0321
0322
0323
0324 const PiBlockDDGNode *getPiBlock(const NodeType &N) const;
0325
0326 protected:
0327
0328
0329
0330 bool addNode(NodeType &N);
0331
0332 private:
0333 using PiBlockMapType = DenseMap<const NodeType *, const PiBlockDDGNode *>;
0334
0335
0336
0337 PiBlockMapType PiBlockMap;
0338 };
0339
0340
0341
0342
0343
0344
0345
0346 class DDGBuilder : public AbstractDependenceGraphBuilder<DataDependenceGraph> {
0347 public:
0348 DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
0349 const BasicBlockListType &BBs)
0350 : AbstractDependenceGraphBuilder(G, D, BBs) {}
0351 DDGNode &createRootNode() final {
0352 auto *RN = new RootDDGNode();
0353 assert(RN && "Failed to allocate memory for DDG root node.");
0354 Graph.addNode(*RN);
0355 return *RN;
0356 }
0357 DDGNode &createFineGrainedNode(Instruction &I) final {
0358 auto *SN = new SimpleDDGNode(I);
0359 assert(SN && "Failed to allocate memory for simple DDG node.");
0360 Graph.addNode(*SN);
0361 return *SN;
0362 }
0363 DDGNode &createPiBlock(const NodeListType &L) final {
0364 auto *Pi = new PiBlockDDGNode(L);
0365 assert(Pi && "Failed to allocate memory for pi-block node.");
0366 Graph.addNode(*Pi);
0367 return *Pi;
0368 }
0369 DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final {
0370 auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse);
0371 assert(E && "Failed to allocate memory for edge");
0372 Graph.connect(Src, Tgt, *E);
0373 return *E;
0374 }
0375 DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final {
0376 auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence);
0377 assert(E && "Failed to allocate memory for edge");
0378 Graph.connect(Src, Tgt, *E);
0379 return *E;
0380 }
0381 DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final {
0382 auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted);
0383 assert(E && "Failed to allocate memory for edge");
0384 assert(isa<RootDDGNode>(Src) && "Expected root node");
0385 Graph.connect(Src, Tgt, *E);
0386 return *E;
0387 }
0388
0389 const NodeListType &getNodesInPiBlock(const DDGNode &N) final {
0390 auto *PiNode = dyn_cast<const PiBlockDDGNode>(&N);
0391 assert(PiNode && "Expected a pi-block node.");
0392 return PiNode->getNodes();
0393 }
0394
0395
0396
0397 bool areNodesMergeable(const DDGNode &Src, const DDGNode &Tgt) const final;
0398 void mergeNodes(DDGNode &Src, DDGNode &Tgt) final;
0399 bool shouldSimplify() const final;
0400 bool shouldCreatePiBlocks() const final;
0401 };
0402
0403 raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
0404 raw_ostream &operator<<(raw_ostream &OS, const DDGNode::NodeKind K);
0405 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge &E);
0406 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K);
0407 raw_ostream &operator<<(raw_ostream &OS, const DataDependenceGraph &G);
0408
0409
0410
0411
0412
0413
0414 class DDGAnalysis : public AnalysisInfoMixin<DDGAnalysis> {
0415 public:
0416 using Result = std::unique_ptr<DataDependenceGraph>;
0417 Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR);
0418
0419 private:
0420 friend AnalysisInfoMixin<DDGAnalysis>;
0421 static AnalysisKey Key;
0422 };
0423
0424
0425 class DDGAnalysisPrinterPass : public PassInfoMixin<DDGAnalysisPrinterPass> {
0426 public:
0427 explicit DDGAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
0428 PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
0429 LoopStandardAnalysisResults &AR, LPMUpdater &U);
0430 static bool isRequired() { return true; }
0431
0432 private:
0433 raw_ostream &OS;
0434 };
0435
0436
0437
0438
0439
0440 template <typename NodeType>
0441 bool DependenceGraphInfo<NodeType>::getDependencies(
0442 const NodeType &Src, const NodeType &Dst, DependenceList &Deps) const {
0443 assert(Deps.empty() && "Expected empty output list at the start.");
0444
0445
0446 SmallVector<Instruction *, 8> SrcIList, DstIList;
0447 auto isMemoryAccess = [](const Instruction *I) {
0448 return I->mayReadOrWriteMemory();
0449 };
0450 Src.collectInstructions(isMemoryAccess, SrcIList);
0451 Dst.collectInstructions(isMemoryAccess, DstIList);
0452
0453 for (auto *SrcI : SrcIList)
0454 for (auto *DstI : DstIList)
0455 if (auto Dep =
0456 const_cast<DependenceInfo *>(&DI)->depends(SrcI, DstI, true))
0457 Deps.push_back(std::move(Dep));
0458
0459 return !Deps.empty();
0460 }
0461
0462 template <typename NodeType>
0463 std::string
0464 DependenceGraphInfo<NodeType>::getDependenceString(const NodeType &Src,
0465 const NodeType &Dst) const {
0466 std::string Str;
0467 raw_string_ostream OS(Str);
0468 DependenceList Deps;
0469 if (!getDependencies(Src, Dst, Deps))
0470 return Str;
0471 interleaveComma(Deps, OS, [&](const std::unique_ptr<Dependence> &D) {
0472 D->dump(OS);
0473
0474
0475 if (Str.back() == '\n')
0476 Str.pop_back();
0477 });
0478
0479 return Str;
0480 }
0481
0482
0483
0484
0485
0486
0487 template <> struct GraphTraits<DDGNode *> {
0488 using NodeRef = DDGNode *;
0489
0490 static DDGNode *DDGGetTargetNode(DGEdge<DDGNode, DDGEdge> *P) {
0491 return &P->getTargetNode();
0492 }
0493
0494
0495
0496 using ChildIteratorType =
0497 mapped_iterator<DDGNode::iterator, decltype(&DDGGetTargetNode)>;
0498 using ChildEdgeIteratorType = DDGNode::iterator;
0499
0500 static NodeRef getEntryNode(NodeRef N) { return N; }
0501 static ChildIteratorType child_begin(NodeRef N) {
0502 return ChildIteratorType(N->begin(), &DDGGetTargetNode);
0503 }
0504 static ChildIteratorType child_end(NodeRef N) {
0505 return ChildIteratorType(N->end(), &DDGGetTargetNode);
0506 }
0507
0508 static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
0509 return N->begin();
0510 }
0511 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
0512 };
0513
0514 template <>
0515 struct GraphTraits<DataDependenceGraph *> : public GraphTraits<DDGNode *> {
0516 using nodes_iterator = DataDependenceGraph::iterator;
0517 static NodeRef getEntryNode(DataDependenceGraph *DG) {
0518 return &DG->getRoot();
0519 }
0520 static nodes_iterator nodes_begin(DataDependenceGraph *DG) {
0521 return DG->begin();
0522 }
0523 static nodes_iterator nodes_end(DataDependenceGraph *DG) { return DG->end(); }
0524 };
0525
0526
0527 template <> struct GraphTraits<const DDGNode *> {
0528 using NodeRef = const DDGNode *;
0529
0530 static const DDGNode *DDGGetTargetNode(const DGEdge<DDGNode, DDGEdge> *P) {
0531 return &P->getTargetNode();
0532 }
0533
0534
0535
0536 using ChildIteratorType =
0537 mapped_iterator<DDGNode::const_iterator, decltype(&DDGGetTargetNode)>;
0538 using ChildEdgeIteratorType = DDGNode::const_iterator;
0539
0540 static NodeRef getEntryNode(NodeRef N) { return N; }
0541 static ChildIteratorType child_begin(NodeRef N) {
0542 return ChildIteratorType(N->begin(), &DDGGetTargetNode);
0543 }
0544 static ChildIteratorType child_end(NodeRef N) {
0545 return ChildIteratorType(N->end(), &DDGGetTargetNode);
0546 }
0547
0548 static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
0549 return N->begin();
0550 }
0551 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
0552 };
0553
0554 template <>
0555 struct GraphTraits<const DataDependenceGraph *>
0556 : public GraphTraits<const DDGNode *> {
0557 using nodes_iterator = DataDependenceGraph::const_iterator;
0558 static NodeRef getEntryNode(const DataDependenceGraph *DG) {
0559 return &DG->getRoot();
0560 }
0561 static nodes_iterator nodes_begin(const DataDependenceGraph *DG) {
0562 return DG->begin();
0563 }
0564 static nodes_iterator nodes_end(const DataDependenceGraph *DG) {
0565 return DG->end();
0566 }
0567 };
0568
0569 }
0570
0571 #endif