dep_graph.hh revision 7720
1/*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Kevin Lim
29 */
30
31#ifndef __CPU_O3_DEP_GRAPH_HH__
32#define __CPU_O3_DEP_GRAPH_HH__
33
34#include "cpu/o3/comm.hh"
35
36/** Node in a linked list. */
37template <class DynInstPtr>
38class DependencyEntry
39{
40  public:
41    DependencyEntry()
42        : inst(NULL), next(NULL)
43    { }
44
45    DynInstPtr inst;
46    //Might want to include data about what arch. register the
47    //dependence is waiting on.
48    DependencyEntry<DynInstPtr> *next;
49};
50
51/** Array of linked list that maintains the dependencies between
52 * producing instructions and consuming instructions.  Each linked
53 * list represents a single physical register, having the future
54 * producer of the register's value, and all consumers waiting on that
55 * value on the list.  The head node of each linked list represents
56 * the producing instruction of that register.  Instructions are put
57 * on the list upon reaching the IQ, and are removed from the list
58 * either when the producer completes, or the instruction is squashed.
59*/
60template <class DynInstPtr>
61class DependencyGraph
62{
63  public:
64    typedef DependencyEntry<DynInstPtr> DepEntry;
65
66    /** Default construction.  Must call resize() prior to use. */
67    DependencyGraph()
68        : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0)
69    { }
70
71    ~DependencyGraph();
72
73    /** Resize the dependency graph to have num_entries registers. */
74    void resize(int num_entries);
75
76    /** Clears all of the linked lists. */
77    void reset();
78
79    /** Inserts an instruction to be dependent on the given index. */
80    void insert(PhysRegIndex idx, DynInstPtr &new_inst);
81
82    /** Sets the producing instruction of a given register. */
83    void setInst(PhysRegIndex idx, DynInstPtr &new_inst)
84    { dependGraph[idx].inst = new_inst; }
85
86    /** Clears the producing instruction. */
87    void clearInst(PhysRegIndex idx)
88    { dependGraph[idx].inst = NULL; }
89
90    /** Removes an instruction from a single linked list. */
91    void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove);
92
93    /** Removes and returns the newest dependent of a specific register. */
94    DynInstPtr pop(PhysRegIndex idx);
95
96    /** Checks if there are any dependents on a specific register. */
97    bool empty(PhysRegIndex idx) { return !dependGraph[idx].next; }
98
99    /** Debugging function to dump out the dependency graph.
100     */
101    void dump();
102
103  private:
104    /** Array of linked lists.  Each linked list is a list of all the
105     *  instructions that depend upon a given register.  The actual
106     *  register's index is used to index into the graph; ie all
107     *  instructions in flight that are dependent upon r34 will be
108     *  in the linked list of dependGraph[34].
109     */
110    DepEntry *dependGraph;
111
112    /** Number of linked lists; identical to the number of registers. */
113    int numEntries;
114
115    // Debug variable, remove when done testing.
116    unsigned memAllocCounter;
117
118  public:
119    // Debug variable, remove when done testing.
120    uint64_t nodesTraversed;
121    // Debug variable, remove when done testing.
122    uint64_t nodesRemoved;
123};
124
125template <class DynInstPtr>
126DependencyGraph<DynInstPtr>::~DependencyGraph()
127{
128    delete [] dependGraph;
129}
130
131template <class DynInstPtr>
132void
133DependencyGraph<DynInstPtr>::resize(int num_entries)
134{
135    numEntries = num_entries;
136    dependGraph = new DepEntry[numEntries];
137}
138
139template <class DynInstPtr>
140void
141DependencyGraph<DynInstPtr>::reset()
142{
143    // Clear the dependency graph
144    DepEntry *curr;
145    DepEntry *prev;
146
147    for (int i = 0; i < numEntries; ++i) {
148        curr = dependGraph[i].next;
149
150        while (curr) {
151            memAllocCounter--;
152
153            prev = curr;
154            curr = prev->next;
155            prev->inst = NULL;
156
157            delete prev;
158        }
159
160        if (dependGraph[i].inst) {
161            dependGraph[i].inst = NULL;
162        }
163
164        dependGraph[i].next = NULL;
165    }
166}
167
168template <class DynInstPtr>
169void
170DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst)
171{
172    //Add this new, dependent instruction at the head of the dependency
173    //chain.
174
175    // First create the entry that will be added to the head of the
176    // dependency chain.
177    DepEntry *new_entry = new DepEntry;
178    new_entry->next = dependGraph[idx].next;
179    new_entry->inst = new_inst;
180
181    // Then actually add it to the chain.
182    dependGraph[idx].next = new_entry;
183
184    ++memAllocCounter;
185}
186
187
188template <class DynInstPtr>
189void
190DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx,
191                                    DynInstPtr &inst_to_remove)
192{
193    DepEntry *prev = &dependGraph[idx];
194    DepEntry *curr = dependGraph[idx].next;
195
196    // Make sure curr isn't NULL.  Because this instruction is being
197    // removed from a dependency list, it must have been placed there at
198    // an earlier time.  The dependency chain should not be empty,
199    // unless the instruction dependent upon it is already ready.
200    if (curr == NULL) {
201        return;
202    }
203
204    nodesRemoved++;
205
206    // Find the instruction to remove within the dependency linked list.
207    while (curr->inst != inst_to_remove) {
208        prev = curr;
209        curr = curr->next;
210        nodesTraversed++;
211
212        assert(curr != NULL);
213    }
214
215    // Now remove this instruction from the list.
216    prev->next = curr->next;
217
218    --memAllocCounter;
219
220    // Could push this off to the destructor of DependencyEntry
221    curr->inst = NULL;
222
223    delete curr;
224}
225
226template <class DynInstPtr>
227DynInstPtr
228DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx)
229{
230    DepEntry *node;
231    node = dependGraph[idx].next;
232    DynInstPtr inst = NULL;
233    if (node) {
234        inst = node->inst;
235        dependGraph[idx].next = node->next;
236        node->inst = NULL;
237        memAllocCounter--;
238        delete node;
239    }
240    return inst;
241}
242
243template <class DynInstPtr>
244void
245DependencyGraph<DynInstPtr>::dump()
246{
247    DepEntry *curr;
248
249    for (int i = 0; i < numEntries; ++i)
250    {
251        curr = &dependGraph[i];
252
253        if (curr->inst) {
254            cprintf("dependGraph[%i]: producer: %s [sn:%lli] consumer: ",
255                    i, curr->inst->pcState(), curr->inst->seqNum);
256        } else {
257            cprintf("dependGraph[%i]: No producer. consumer: ", i);
258        }
259
260        while (curr->next != NULL) {
261            curr = curr->next;
262
263            cprintf("%s [sn:%lli] ",
264                    curr->inst->pcState(), curr->inst->seqNum);
265        }
266
267        cprintf("\n");
268    }
269    cprintf("memAllocCounter: %i\n", memAllocCounter);
270}
271
272#endif // __CPU_O3_DEP_GRAPH_HH__
273