dep_graph.hh revision 2348
1
2#ifndef __CPU_O3_DEP_GRAPH_HH__
3#define __CPU_O3_DEP_GRAPH_HH__
4
5#include "cpu/o3/comm.hh"
6
7/** Node in a linked list. */
8template <class DynInstPtr>
9class DependencyEntry
10{
11  public:
12    DependencyEntry()
13        : inst(NULL), next(NULL)
14    { }
15
16    DynInstPtr inst;
17    //Might want to include data about what arch. register the
18    //dependence is waiting on.
19    DependencyEntry<DynInstPtr> *next;
20};
21
22/** Array of linked list that maintains the dependencies between
23 * producing instructions and consuming instructions.  Each linked
24 * list represents a single physical register, having the future
25 * producer of the register's value, and all consumers waiting on that
26 * value on the list.  The head node of each linked list represents
27 * the producing instruction of that register.  Instructions are put
28 * on the list upon reaching the IQ, and are removed from the list
29 * either when the producer completes, or the instruction is squashed.
30*/
31template <class DynInstPtr>
32class DependencyGraph
33{
34  public:
35    typedef DependencyEntry<DynInstPtr> DepEntry;
36
37    /** Default construction.  Must call resize() prior to use. */
38    DependencyGraph()
39        : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0)
40    { }
41
42    /** Resize the dependency graph to have num_entries registers. */
43    void resize(int num_entries);
44
45    /** Clears all of the linked lists. */
46    void reset();
47
48    /** Inserts an instruction to be dependent on the given index. */
49    void insert(PhysRegIndex idx, DynInstPtr &new_inst);
50
51    /** Sets the producing instruction of a given register. */
52    void setInst(PhysRegIndex idx, DynInstPtr &new_inst)
53    { dependGraph[idx].inst = new_inst; }
54
55    /** Clears the producing instruction. */
56    void clearInst(PhysRegIndex idx)
57    { dependGraph[idx].inst = NULL; }
58
59    /** Removes an instruction from a single linked list. */
60    void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove);
61
62    /** Removes and returns the newest dependent of a specific register. */
63    DynInstPtr pop(PhysRegIndex idx);
64
65    /** Checks if there are any dependents on a specific register. */
66    bool empty(PhysRegIndex idx) { return !dependGraph[idx].next; }
67
68    /** Debugging function to dump out the dependency graph.
69     */
70    void dump();
71
72  private:
73    /** Array of linked lists.  Each linked list is a list of all the
74     *  instructions that depend upon a given register.  The actual
75     *  register's index is used to index into the graph; ie all
76     *  instructions in flight that are dependent upon r34 will be
77     *  in the linked list of dependGraph[34].
78     */
79    DepEntry *dependGraph;
80
81    /** Number of linked lists; identical to the number of registers. */
82    int numEntries;
83
84    // Debug variable, remove when done testing.
85    unsigned memAllocCounter;
86
87  public:
88    // Debug variable, remove when done testing.
89    uint64_t nodesTraversed;
90    // Debug variable, remove when done testing.
91    uint64_t nodesRemoved;
92};
93
94template <class DynInstPtr>
95void
96DependencyGraph<DynInstPtr>::resize(int num_entries)
97{
98    numEntries = num_entries;
99    dependGraph = new DepEntry[numEntries];
100}
101
102template <class DynInstPtr>
103void
104DependencyGraph<DynInstPtr>::reset()
105{
106    // Clear the dependency graph
107    DepEntry *curr;
108    DepEntry *prev;
109
110    for (int i = 0; i < numEntries; ++i) {
111        curr = dependGraph[i].next;
112
113        while (curr) {
114            memAllocCounter--;
115
116            prev = curr;
117            curr = prev->next;
118            prev->inst = NULL;
119
120            delete prev;
121        }
122
123        if (dependGraph[i].inst) {
124            dependGraph[i].inst = NULL;
125        }
126
127        dependGraph[i].next = NULL;
128    }
129}
130
131template <class DynInstPtr>
132void
133DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst)
134{
135    //Add this new, dependent instruction at the head of the dependency
136    //chain.
137
138    // First create the entry that will be added to the head of the
139    // dependency chain.
140    DepEntry *new_entry = new DepEntry;
141    new_entry->next = dependGraph[idx].next;
142    new_entry->inst = new_inst;
143
144    // Then actually add it to the chain.
145    dependGraph[idx].next = new_entry;
146
147    ++memAllocCounter;
148}
149
150
151template <class DynInstPtr>
152void
153DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx,
154                                    DynInstPtr &inst_to_remove)
155{
156    DepEntry *prev = &dependGraph[idx];
157    DepEntry *curr = dependGraph[idx].next;
158
159    // Make sure curr isn't NULL.  Because this instruction is being
160    // removed from a dependency list, it must have been placed there at
161    // an earlier time.  The dependency chain should not be empty,
162    // unless the instruction dependent upon it is already ready.
163    if (curr == NULL) {
164        return;
165    }
166
167    nodesRemoved++;
168
169    // Find the instruction to remove within the dependency linked list.
170    while (curr->inst != inst_to_remove) {
171        prev = curr;
172        curr = curr->next;
173        nodesTraversed++;
174
175        assert(curr != NULL);
176    }
177
178    // Now remove this instruction from the list.
179    prev->next = curr->next;
180
181    --memAllocCounter;
182
183    // Could push this off to the destructor of DependencyEntry
184    curr->inst = NULL;
185
186    delete curr;
187}
188
189template <class DynInstPtr>
190DynInstPtr
191DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx)
192{
193    DepEntry *node;
194    node = dependGraph[idx].next;
195    DynInstPtr inst = NULL;
196    if (node) {
197        inst = node->inst;
198        dependGraph[idx].next = node->next;
199        node->inst = NULL;
200        memAllocCounter--;
201        delete node;
202    }
203    return inst;
204}
205
206template <class DynInstPtr>
207void
208DependencyGraph<DynInstPtr>::dump()
209{
210    DepEntry *curr;
211
212    for (int i = 0; i < numEntries; ++i)
213    {
214        curr = &dependGraph[i];
215
216        if (curr->inst) {
217            cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ",
218                    i, curr->inst->readPC(), curr->inst->seqNum);
219        } else {
220            cprintf("dependGraph[%i]: No producer. consumer: ", i);
221        }
222
223        while (curr->next != NULL) {
224            curr = curr->next;
225
226            cprintf("%#x [sn:%lli] ",
227                    curr->inst->readPC(), curr->inst->seqNum);
228        }
229
230        cprintf("\n");
231    }
232    cprintf("memAllocCounter: %i\n", memAllocCounter);
233}
234
235#endif // __CPU_O3_DEP_GRAPH_HH__
236