| /* | |
| * Copyright (c) 2012 ARM Limited | |
| * All rights reserved | |
| * | |
| * The license below extends only to copyright in the software and shall | |
| * not be construed as granting a license to any other intellectual | |
| * property including but not limited to intellectual property relating | |
| * to a hardware implementation of the functionality of the software | |
| * licensed hereunder. You may use the software subject to the license | |
| * terms below provided that you ensure that this notice is replicated | |
| * unmodified and in its entirety in all distributions of the software, | |
| * modified or unmodified, in source code or in binary form. | |
| * | |
| * Copyright (c) 2006 The Regents of The University of Michigan | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Authors: Kevin Lim | |
| */ | |
| #ifndef __CPU_O3_DEP_GRAPH_HH__ | |
| #define __CPU_O3_DEP_GRAPH_HH__ | |
| #include "cpu/o3/comm.hh" | |
| /** Node in a linked list. */ | |
| template <class DynInstPtr> | |
| class DependencyEntry | |
| { | |
| public: | |
| DependencyEntry() | |
| : inst(NULL), next(NULL) | |
| { } | |
| DynInstPtr inst; | |
| //Might want to include data about what arch. register the | |
| //dependence is waiting on. | |
| DependencyEntry<DynInstPtr> *next; | |
| }; | |
| /** Array of linked list that maintains the dependencies between | |
| * producing instructions and consuming instructions. Each linked | |
| * list represents a single physical register, having the future | |
| * producer of the register's value, and all consumers waiting on that | |
| * value on the list. The head node of each linked list represents | |
| * the producing instruction of that register. Instructions are put | |
| * on the list upon reaching the IQ, and are removed from the list | |
| * either when the producer completes, or the instruction is squashed. | |
| */ | |
| template <class DynInstPtr> | |
| class DependencyGraph | |
| { | |
| public: | |
| typedef DependencyEntry<DynInstPtr> DepEntry; | |
| /** Default construction. Must call resize() prior to use. */ | |
| DependencyGraph() | |
| : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0) | |
| { } | |
| ~DependencyGraph(); | |
| /** Resize the dependency graph to have num_entries registers. */ | |
| void resize(int num_entries); | |
| /** Clears all of the linked lists. */ | |
| void reset(); | |
| /** Inserts an instruction to be dependent on the given index. */ | |
| void insert(PhysRegIndex idx, DynInstPtr &new_inst); | |
| /** Sets the producing instruction of a given register. */ | |
| void setInst(PhysRegIndex idx, DynInstPtr &new_inst) | |
| { dependGraph[idx].inst = new_inst; } | |
| /** Clears the producing instruction. */ | |
| void clearInst(PhysRegIndex idx) | |
| { dependGraph[idx].inst = NULL; } | |
| /** Removes an instruction from a single linked list. */ | |
| void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove); | |
| /** Removes and returns the newest dependent of a specific register. */ | |
| DynInstPtr pop(PhysRegIndex idx); | |
| /** Checks if the entire dependency graph is empty. */ | |
| bool empty() const; | |
| /** Checks if there are any dependents on a specific register. */ | |
| bool empty(PhysRegIndex idx) const { return !dependGraph[idx].next; } | |
| /** Debugging function to dump out the dependency graph. | |
| */ | |
| void dump(); | |
| private: | |
| /** Array of linked lists. Each linked list is a list of all the | |
| * instructions that depend upon a given register. The actual | |
| * register's index is used to index into the graph; ie all | |
| * instructions in flight that are dependent upon r34 will be | |
| * in the linked list of dependGraph[34]. | |
| */ | |
| DepEntry *dependGraph; | |
| /** Number of linked lists; identical to the number of registers. */ | |
| int numEntries; | |
| // Debug variable, remove when done testing. | |
| unsigned memAllocCounter; | |
| public: | |
| // Debug variable, remove when done testing. | |
| uint64_t nodesTraversed; | |
| // Debug variable, remove when done testing. | |
| uint64_t nodesRemoved; | |
| }; | |
| template <class DynInstPtr> | |
| DependencyGraph<DynInstPtr>::~DependencyGraph() | |
| { | |
| delete [] dependGraph; | |
| } | |
| template <class DynInstPtr> | |
| void | |
| DependencyGraph<DynInstPtr>::resize(int num_entries) | |
| { | |
| numEntries = num_entries; | |
| dependGraph = new DepEntry[numEntries]; | |
| } | |
| template <class DynInstPtr> | |
| void | |
| DependencyGraph<DynInstPtr>::reset() | |
| { | |
| // Clear the dependency graph | |
| DepEntry *curr; | |
| DepEntry *prev; | |
| for (int i = 0; i < numEntries; ++i) { | |
| curr = dependGraph[i].next; | |
| while (curr) { | |
| memAllocCounter--; | |
| prev = curr; | |
| curr = prev->next; | |
| prev->inst = NULL; | |
| delete prev; | |
| } | |
| if (dependGraph[i].inst) { | |
| dependGraph[i].inst = NULL; | |
| } | |
| dependGraph[i].next = NULL; | |
| } | |
| } | |
| template <class DynInstPtr> | |
| void | |
| DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst) | |
| { | |
| //Add this new, dependent instruction at the head of the dependency | |
| //chain. | |
| // First create the entry that will be added to the head of the | |
| // dependency chain. | |
| DepEntry *new_entry = new DepEntry; | |
| new_entry->next = dependGraph[idx].next; | |
| new_entry->inst = new_inst; | |
| // Then actually add it to the chain. | |
| dependGraph[idx].next = new_entry; | |
| ++memAllocCounter; | |
| } | |
| template <class DynInstPtr> | |
| void | |
| DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx, | |
| DynInstPtr &inst_to_remove) | |
| { | |
| DepEntry *prev = &dependGraph[idx]; | |
| DepEntry *curr = dependGraph[idx].next; | |
| // Make sure curr isn't NULL. Because this instruction is being | |
| // removed from a dependency list, it must have been placed there at | |
| // an earlier time. The dependency chain should not be empty, | |
| // unless the instruction dependent upon it is already ready. | |
| if (curr == NULL) { | |
| return; | |
| } | |
| nodesRemoved++; | |
| // Find the instruction to remove within the dependency linked list. | |
| while (curr->inst != inst_to_remove) { | |
| prev = curr; | |
| curr = curr->next; | |
| nodesTraversed++; | |
| assert(curr != NULL); | |
| } | |
| // Now remove this instruction from the list. | |
| prev->next = curr->next; | |
| --memAllocCounter; | |
| // Could push this off to the destructor of DependencyEntry | |
| curr->inst = NULL; | |
| delete curr; | |
| } | |
| template <class DynInstPtr> | |
| DynInstPtr | |
| DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx) | |
| { | |
| DepEntry *node; | |
| node = dependGraph[idx].next; | |
| DynInstPtr inst = NULL; | |
| if (node) { | |
| inst = node->inst; | |
| dependGraph[idx].next = node->next; | |
| node->inst = NULL; | |
| memAllocCounter--; | |
| delete node; | |
| } | |
| return inst; | |
| } | |
| template <class DynInstPtr> | |
| bool | |
| DependencyGraph<DynInstPtr>::empty() const | |
| { | |
| for (int i = 0; i < numEntries; ++i) { | |
| if (!empty(i)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| template <class DynInstPtr> | |
| void | |
| DependencyGraph<DynInstPtr>::dump() | |
| { | |
| DepEntry *curr; | |
| for (int i = 0; i < numEntries; ++i) | |
| { | |
| curr = &dependGraph[i]; | |
| if (curr->inst) { | |
| cprintf("dependGraph[%i]: producer: %s [sn:%lli] consumer: ", | |
| i, curr->inst->pcState(), curr->inst->seqNum); | |
| } else { | |
| cprintf("dependGraph[%i]: No producer. consumer: ", i); | |
| } | |
| while (curr->next != NULL) { | |
| curr = curr->next; | |
| cprintf("%s [sn:%lli] ", | |
| curr->inst->pcState(), curr->inst->seqNum); | |
| } | |
| cprintf("\n"); | |
| } | |
| cprintf("memAllocCounter: %i\n", memAllocCounter); | |
| } | |
| #endif // __CPU_O3_DEP_GRAPH_HH__ |