1 //===- ScheduleDFS.h - ILP metric for ScheduleDAGInstrs ---------*- C++ -*-===//
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 // Definition of an ILP metric for machine level instruction scheduling.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CODEGEN_SCHEDULEDFS_H
14 #define LLVM_CODEGEN_SCHEDULEDFS_H
15 
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/CodeGen/ScheduleDAG.h"
18 #include <cassert>
19 #include <cstdint>
20 #include <vector>
21 
22 namespace llvm {
23 
24 template <typename T> class ArrayRef;
25 class raw_ostream;
26 
27 /// Represent the ILP of the subDAG rooted at a DAG node.
28 ///
29 /// ILPValues summarize the DAG subtree rooted at each node. ILPValues are
30 /// valid for all nodes regardless of their subtree membership.
31 ///
32 /// When computed using bottom-up DFS, this metric assumes that the DAG is a
33 /// forest of trees with roots at the bottom of the schedule branching upward.
34 struct ILPValue {
35   unsigned InstrCount;
36   /// Length may either correspond to depth or height, depending on direction,
37   /// and cycles or nodes depending on context.
38   unsigned Length;
39 
40   ILPValue(unsigned count, unsigned length):
41     InstrCount(count), Length(length) {}
42 
43   // Order by the ILP metric's value.
44   bool operator<(ILPValue RHS) const {
45     return (uint64_t)InstrCount * RHS.Length
46       < (uint64_t)Length * RHS.InstrCount;
47   }
48   bool operator>(ILPValue RHS) const {
49     return RHS < *this;
50   }
51   bool operator<=(ILPValue RHS) const {
52     return (uint64_t)InstrCount * RHS.Length
53       <= (uint64_t)Length * RHS.InstrCount;
54   }
55   bool operator>=(ILPValue RHS) const {
56     return RHS <= *this;
57   }
58 
59   void print(raw_ostream &OS) const;
60 
61   void dump() const;
62 };
63 
64 /// Compute the values of each DAG node for various metrics during DFS.
65 class SchedDFSResult {
66   friend class SchedDFSImpl;
67 
68   static const unsigned InvalidSubtreeID = ~0u;
69 
70   /// Per-SUnit data computed during DFS for various metrics.
71   ///
72   /// A node's SubtreeID is set to itself when it is visited to indicate that it
73   /// is the root of a subtree. Later it is set to its parent to indicate an
74   /// interior node. Finally, it is set to a representative subtree ID during
75   /// finalization.
76   struct NodeData {
77     unsigned InstrCount = 0;
78     unsigned SubtreeID = InvalidSubtreeID;
79 
80     NodeData() = default;
81   };
82 
83   /// Per-Subtree data computed during DFS.
84   struct TreeData {
85     unsigned ParentTreeID = InvalidSubtreeID;
86     unsigned SubInstrCount = 0;
87 
88     TreeData() = default;
89   };
90 
91   /// Record a connection between subtrees and the connection level.
92   struct Connection {
93     unsigned TreeID;
94     unsigned Level;
95 
96     Connection(unsigned tree, unsigned level): TreeID(tree), Level(level) {}
97   };
98 
99   bool IsBottomUp;
100   unsigned SubtreeLimit;
101   /// DFS results for each SUnit in this DAG.
102   std::vector<NodeData> DFSNodeData;
103 
104   // Store per-tree data indexed on tree ID,
105   SmallVector<TreeData, 16> DFSTreeData;
106 
107   // For each subtree discovered during DFS, record its connections to other
108   // subtrees.
109   std::vector<SmallVector<Connection, 4>> SubtreeConnections;
110 
111   /// Cache the current connection level of each subtree.
112   /// This mutable array is updated during scheduling.
113   std::vector<unsigned> SubtreeConnectLevels;
114 
115 public:
116   SchedDFSResult(bool IsBU, unsigned lim)
117     : IsBottomUp(IsBU), SubtreeLimit(lim) {}
118 
119   /// Get the node cutoff before subtrees are considered significant.
120   unsigned getSubtreeLimit() const { return SubtreeLimit; }
121 
122   /// Return true if this DFSResult is uninitialized.
123   ///
124   /// resize() initializes DFSResult, while compute() populates it.
125   bool empty() const { return DFSNodeData.empty(); }
126 
127   /// Clear the results.
128   void clear() {
129     DFSNodeData.clear();
130     DFSTreeData.clear();
131     SubtreeConnections.clear();
132     SubtreeConnectLevels.clear();
133   }
134 
135   /// Initialize the result data with the size of the DAG.
136   void resize(unsigned NumSUnits) {
137     DFSNodeData.resize(NumSUnits);
138   }
139 
140   /// Compute various metrics for the DAG with given roots.
141   void compute(ArrayRef<SUnit> SUnits);
142 
143   /// Get the number of instructions in the given subtree and its
144   /// children.
145   unsigned getNumInstrs(const SUnit *SU) const {
146     return DFSNodeData[SU->NodeNum].InstrCount;
147   }
148 
149   /// Get the number of instructions in the given subtree not including
150   /// children.
151   unsigned getNumSubInstrs(unsigned SubtreeID) const {
152     return DFSTreeData[SubtreeID].SubInstrCount;
153   }
154 
155   /// Get the ILP value for a DAG node.
156   ///
157   /// A leaf node has an ILP of 1/1.
158   ILPValue getILP(const SUnit *SU) const {
159     return ILPValue(DFSNodeData[SU->NodeNum].InstrCount, 1 + SU->getDepth());
160   }
161 
162   /// The number of subtrees detected in this DAG.
163   unsigned getNumSubtrees() const { return SubtreeConnectLevels.size(); }
164 
165   /// Get the ID of the subtree the given DAG node belongs to.
166   ///
167   /// For convenience, if DFSResults have not been computed yet, give everything
168   /// tree ID 0.
169   unsigned getSubtreeID(const SUnit *SU) const {
170     if (empty())
171       return 0;
172     assert(SU->NodeNum < DFSNodeData.size() &&  "New Node");
173     return DFSNodeData[SU->NodeNum].SubtreeID;
174   }
175 
176   /// Get the connection level of a subtree.
177   ///
178   /// For bottom-up trees, the connection level is the latency depth (in cycles)
179   /// of the deepest connection to another subtree.
180   unsigned getSubtreeLevel(unsigned SubtreeID) const {
181     return SubtreeConnectLevels[SubtreeID];
182   }
183 
184   /// Scheduler callback to update SubtreeConnectLevels when a tree is
185   /// initially scheduled.
186   void scheduleTree(unsigned SubtreeID);
187 };
188 
189 raw_ostream &operator<<(raw_ostream &OS, const ILPValue &Val);
190 
191 } // end namespace llvm
192 
193 #endif // LLVM_CODEGEN_SCHEDULEDFS_H
194