From 552622184752dc798bc81f9b0b395db68aee9511 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Tue, 15 Oct 2013 14:22:44 -0400 Subject: [PATCH] cpu/o3: clean up rename map and free list Restructured rename map and free list to clean up some extraneous code and separate out common code that can be reused across different register classes (int and fp at this point). Both components now consist of a set of Simple* objects that are stand-alone rename map & free list for each class, plus a Unified* object that presents a unified interface across all register classes and then redirects accesses to the appropriate Simple* object as needed. Moved free list initialization to PhysRegFile to better isolate knowledge of physical register index mappings to that class (and remove the need to pass a number of parameters to the free list constructor). Causes a small change to these stats: cpu.rename.int_rename_lookups cpu.rename.fp_rename_lookups because they are now categorized on a per-operand basis rather than a per-instruction basis. That is, an instruction with mixed fp/int/misc operand types will have each operand categorized independently, where previously the lookup was categorized based on the instruction type. --- src/cpu/o3/SConscript | 1 + src/cpu/o3/cpu.cc | 86 +++++------ src/cpu/o3/cpu.hh | 3 +- src/cpu/o3/cpu_policy.hh | 9 +- src/cpu/o3/free_list.cc | 41 +----- src/cpu/o3/free_list.hh | 176 ++++++++++------------ src/cpu/o3/regfile.cc | 64 ++++++++ src/cpu/o3/regfile.hh | 38 ++--- src/cpu/o3/rename_impl.hh | 135 ++++++++--------- src/cpu/o3/rename_map.cc | 272 ++++++++++++---------------------- src/cpu/o3/rename_map.hh | 302 ++++++++++++++++++++++++++++---------- 11 files changed, 593 insertions(+), 534 deletions(-) create mode 100644 src/cpu/o3/regfile.cc diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript index 50b5a8ea4..b8f14cc25 100755 --- a/src/cpu/o3/SConscript +++ b/src/cpu/o3/SConscript @@ -56,6 +56,7 @@ if 'O3CPU' in env['CPU_MODELS']: Source('lsq.cc') Source('lsq_unit.cc') Source('mem_dep_unit.cc') + Source('regfile.cc') Source('rename.cc') Source('rename_map.cc') Source('rob.cc') diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 496961380..3e33e139a 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -227,9 +227,7 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) regFile(params->numPhysIntRegs, params->numPhysFloatRegs), - freeList(params->numThreads, - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs), + freeList(name() + ".freelist", ®File), rob(this, params->numROBEntries, params->squashWidth, @@ -334,56 +332,46 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) iew.setScoreboard(&scoreboard); // Setup the rename map for whichever stages need it. - PhysRegIndex lreg_idx = 0; - PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs - for (ThreadID tid = 0; tid < numThreads; tid++) { - bool bindRegs = (tid <= active_threads - 1); - isa[tid] = params->isa[tid]; - commitRenameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - false); - - renameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, + // Only Alpha has an FP zero register, so for other ISAs we + // use an invalid FP register index to avoid special treatment + // of any valid FP reg. + RegIndex invalidFPReg = TheISA::NumFloatRegs + 1; + RegIndex fpZeroReg = + (THE_ISA == ALPHA_ISA) ? TheISA::ZeroReg : invalidFPReg; - TheISA::ZeroReg, - TheISA::ZeroReg, + commitRenameMap[tid].init(®File, TheISA::ZeroReg, fpZeroReg, + &freeList); - tid, - bindRegs); + renameMap[tid].init(®File, TheISA::ZeroReg, fpZeroReg, + &freeList); activateThreadEvent[tid].init(tid, this); deallocateContextEvent[tid].init(tid, this); } + // Initialize rename map to assign physical registers to the + // architectural registers for active threads only. + for (ThreadID tid = 0; tid < active_threads; tid++) { + for (RegIndex ridx = 0; ridx < TheISA::NumIntRegs; ++ridx) { + // Note that we can't use the rename() method because we don't + // want special treatment for the zero register at this point + PhysRegIndex phys_reg = freeList.getIntReg(); + renameMap[tid].setIntEntry(ridx, phys_reg); + commitRenameMap[tid].setIntEntry(ridx, phys_reg); + } + + for (RegIndex ridx = 0; ridx < TheISA::NumFloatRegs; ++ridx) { + PhysRegIndex phys_reg = freeList.getFloatReg(); + renameMap[tid].setFloatEntry(ridx, phys_reg); + commitRenameMap[tid].setFloatEntry(ridx, phys_reg); + } + } + rename.setRenameMap(renameMap); commit.setRenameMap(commitRenameMap); - - // Give renameMap & rename stage access to the freeList; - for (ThreadID tid = 0; tid < numThreads; tid++) - renameMap[tid].setFreeList(&freeList); rename.setFreeList(&freeList); // Setup the ROB for whichever stages need it. @@ -1406,7 +1394,7 @@ uint64_t FullO3CPU::readArchIntReg(int reg_idx, ThreadID tid) { intRegfileReads++; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + PhysRegIndex phys_reg = commitRenameMap[tid].lookupInt(reg_idx); return regFile.readIntReg(phys_reg); } @@ -1416,8 +1404,7 @@ float FullO3CPU::readArchFloatReg(int reg_idx, ThreadID tid) { fpRegfileReads++; - int idx = reg_idx + TheISA::NumIntRegs; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + PhysRegIndex phys_reg = commitRenameMap[tid].lookupFloat(reg_idx); return regFile.readFloatReg(phys_reg); } @@ -1427,8 +1414,7 @@ uint64_t FullO3CPU::readArchFloatRegInt(int reg_idx, ThreadID tid) { fpRegfileReads++; - int idx = reg_idx + TheISA::NumIntRegs; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + PhysRegIndex phys_reg = commitRenameMap[tid].lookupFloat(reg_idx); return regFile.readFloatRegBits(phys_reg); } @@ -1438,7 +1424,7 @@ void FullO3CPU::setArchIntReg(int reg_idx, uint64_t val, ThreadID tid) { intRegfileWrites++; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + PhysRegIndex phys_reg = commitRenameMap[tid].lookupInt(reg_idx); regFile.setIntReg(phys_reg, val); } @@ -1448,8 +1434,7 @@ void FullO3CPU::setArchFloatReg(int reg_idx, float val, ThreadID tid) { fpRegfileWrites++; - int idx = reg_idx + TheISA::NumIntRegs; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + PhysRegIndex phys_reg = commitRenameMap[tid].lookupFloat(reg_idx); regFile.setFloatReg(phys_reg, val); } @@ -1459,8 +1444,7 @@ void FullO3CPU::setArchFloatRegInt(int reg_idx, uint64_t val, ThreadID tid) { fpRegfileWrites++; - int idx = reg_idx + TheISA::NumIntRegs; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + PhysRegIndex phys_reg = commitRenameMap[tid].lookupFloat(reg_idx); regFile.setFloatRegBits(phys_reg, val); } diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 98a6972e9..1a1f8f8a3 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved * * The license below extends only to copyright in the software and shall @@ -655,7 +656,7 @@ class FullO3CPU : public BaseO3CPU typename CPUPolicy::Commit commit; /** The register file. */ - typename CPUPolicy::RegFile regFile; + PhysRegFile regFile; /** The free list. */ typename CPUPolicy::FreeList freeList; diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh index a48059202..6db532ade 100644 --- a/src/cpu/o3/cpu_policy.hh +++ b/src/cpu/o3/cpu_policy.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,14 +60,10 @@ template struct SimpleCPUPolicy { - /** Typedef for the register file. Most classes assume a unified - * physical register file. - */ - typedef PhysRegFile RegFile; /** Typedef for the freelist of registers. */ - typedef SimpleFreeList FreeList; + typedef UnifiedFreeList FreeList; /** Typedef for the rename map. */ - typedef SimpleRenameMap RenameMap; + typedef UnifiedRenameMap RenameMap; /** Typedef for the ROB. */ typedef ::ROB ROB; /** Typedef for the instruction queue/scheduler. */ diff --git a/src/cpu/o3/free_list.cc b/src/cpu/o3/free_list.cc index 4224d0e41..0c8a16d0d 100644 --- a/src/cpu/o3/free_list.cc +++ b/src/cpu/o3/free_list.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,41 +33,13 @@ #include "cpu/o3/free_list.hh" #include "debug/FreeList.hh" -SimpleFreeList::SimpleFreeList(ThreadID activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs) - : numLogicalIntRegs(_numLogicalIntRegs), - numPhysicalIntRegs(_numPhysicalIntRegs), - numLogicalFloatRegs(_numLogicalFloatRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs), - numPhysicalRegs(numPhysicalIntRegs + numPhysicalFloatRegs) +UnifiedFreeList::UnifiedFreeList(const std::string &_my_name, + PhysRegFile *_regFile) + : _name(_my_name), regFile(_regFile) { DPRINTF(FreeList, "Creating new free list object.\n"); - // Put all of the extra physical registers onto the free list. This - // means excluding all of the base logical registers. - for (PhysRegIndex i = numLogicalIntRegs * activeThreads; - i < numPhysicalIntRegs; ++i) - { - freeIntRegs.push(i); - } - - // Put all of the extra physical registers onto the free list. This - // means excluding all of the base logical registers. Because the - // float registers' indices start where the physical registers end, - // some math must be done to determine where the free registers start. - PhysRegIndex i = numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads); - - for ( ; i < numPhysicalRegs; ++i) - { - freeFloatRegs.push(i); - } -} - -std::string -SimpleFreeList::name() const -{ - return "cpu.freelist"; + // Have the register file initialize the free list since it knows + // about its internal organization + regFile->initFreeList(this); } diff --git a/src/cpu/o3/free_list.hh b/src/cpu/o3/free_list.hh index fec076097..3919d0afb 100644 --- a/src/cpu/o3/free_list.hh +++ b/src/cpu/o3/free_list.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,13 +35,50 @@ #include #include -#include "arch/registers.hh" #include "base/misc.hh" #include "base/trace.hh" -#include "config/the_isa.hh" #include "cpu/o3/comm.hh" +#include "cpu/o3/regfile.hh" #include "debug/FreeList.hh" +/** + * Free list for a single class of registers (e.g., integer + * or floating point). Because the register class is implicitly + * determined by the rename map instance being accessed, all + * architectural register index parameters and values in this class + * are relative (e.g., %fp2 is just index 2). + */ +class SimpleFreeList +{ + private: + + /** The actual free list */ + std::queue freeRegs; + + public: + + SimpleFreeList() {}; + + /** Add a physical register to the free list */ + void addReg(PhysRegIndex reg) { freeRegs.push(reg); } + + /** Get the next available register from the free list */ + PhysRegIndex getReg() + { + assert(!freeRegs.empty()); + PhysRegIndex free_reg = freeRegs.front(); + freeRegs.pop(); + return free_reg; + } + + /** Return the number of free registers on the list. */ + unsigned numFreeRegs() const { return freeRegs.size(); } + + /** True iff there are free registers on the list. */ + bool hasFreeRegs() const { return !freeRegs.empty(); } +}; + + /** * FreeList class that simply holds the list of free integer and floating * point registers. Can request for a free register of either type, and @@ -54,125 +92,86 @@ * class can be named simply "FreeList". * @todo: Give a better name to the base FP dependency. */ -class SimpleFreeList +class UnifiedFreeList { private: - /** The list of free integer registers. */ - std::queue freeIntRegs; - /** The list of free floating point registers. */ - std::queue freeFloatRegs; - - /** Number of logical integer registers. */ - int numLogicalIntRegs; + /** The object name, for DPRINTF. We have to declare this + * explicitly because Scoreboard is not a SimObject. */ + const std::string _name; - /** Number of physical integer registers. */ - int numPhysicalIntRegs; + /** The list of free integer registers. */ + SimpleFreeList intList; - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; + /** The list of free floating point registers. */ + SimpleFreeList floatList; - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; + /** + * The register file object is used only to distinguish integer + * from floating-point physical register indices. + */ + PhysRegFile *regFile; - /** Total number of physical registers. */ - int numPhysicalRegs; + /* + * We give UnifiedRenameMap internal access so it can get at the + * internal per-class free lists and associate those with its + * per-class rename maps. See UnifiedRenameMap::init(). + */ + friend class UnifiedRenameMap; public: /** Constructs a free list. - * @param activeThreads Number of active threads. - * @param _numLogicalIntRegs Number of logical integer registers. * @param _numPhysicalIntRegs Number of physical integer registers. - * @param _numLogicalFloatRegs Number of logical fp registers. + * @param reservedIntRegs Number of integer registers already + * used by initial mappings. * @param _numPhysicalFloatRegs Number of physical fp registers. + * @param reservedFloatRegs Number of fp registers already + * used by initial mappings. */ - SimpleFreeList(ThreadID activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs); + UnifiedFreeList(const std::string &_my_name, PhysRegFile *_regFile); /** Gives the name of the freelist. */ - std::string name() const; + std::string name() const { return _name; }; /** Gets a free integer register. */ - inline PhysRegIndex getIntReg(); + PhysRegIndex getIntReg() { return intList.getReg(); } /** Gets a free fp register. */ - inline PhysRegIndex getFloatReg(); + PhysRegIndex getFloatReg() { return floatList.getReg(); } /** Adds a register back to the free list. */ - inline void addReg(PhysRegIndex freed_reg); + void addReg(PhysRegIndex freed_reg); /** Adds an integer register back to the free list. */ - inline void addIntReg(PhysRegIndex freed_reg); + void addIntReg(PhysRegIndex freed_reg) { intList.addReg(freed_reg); } /** Adds a fp register back to the free list. */ - inline void addFloatReg(PhysRegIndex freed_reg); + void addFloatReg(PhysRegIndex freed_reg) { floatList.addReg(freed_reg); } /** Checks if there are any free integer registers. */ - bool hasFreeIntRegs() - { return !freeIntRegs.empty(); } + bool hasFreeIntRegs() const { return intList.hasFreeRegs(); } /** Checks if there are any free fp registers. */ - bool hasFreeFloatRegs() - { return !freeFloatRegs.empty(); } + bool hasFreeFloatRegs() const { return floatList.hasFreeRegs(); } /** Returns the number of free integer registers. */ - int numFreeIntRegs() - { return freeIntRegs.size(); } + unsigned numFreeIntRegs() const { return intList.numFreeRegs(); } /** Returns the number of free fp registers. */ - int numFreeFloatRegs() - { return freeFloatRegs.size(); } + unsigned numFreeFloatRegs() const { return floatList.numFreeRegs(); } }; -inline PhysRegIndex -SimpleFreeList::getIntReg() -{ - DPRINTF(FreeList, "Trying to get free integer register.\n"); - - if (freeIntRegs.empty()) { - panic("No free integer registers!"); - } - - PhysRegIndex free_reg = freeIntRegs.front(); - - freeIntRegs.pop(); - - return(free_reg); -} - -inline PhysRegIndex -SimpleFreeList::getFloatReg() -{ - DPRINTF(FreeList, "Trying to get free float register.\n"); - - if (freeFloatRegs.empty()) { - panic("No free integer registers!"); - } - - PhysRegIndex free_reg = freeFloatRegs.front(); - - freeFloatRegs.pop(); - - return(free_reg); -} - inline void -SimpleFreeList::addReg(PhysRegIndex freed_reg) +UnifiedFreeList::addReg(PhysRegIndex freed_reg) { DPRINTF(FreeList,"Freeing register %i.\n", freed_reg); //Might want to add in a check for whether or not this register is //already in there. A bit vector or something similar would be useful. - if (freed_reg < numPhysicalIntRegs) { - if (freed_reg != TheISA::ZeroReg) - freeIntRegs.push(freed_reg); - } else if (freed_reg < numPhysicalRegs) { -#if THE_ISA == ALPHA_ISA - if (freed_reg != (TheISA::ZeroReg + numPhysicalIntRegs)) -#endif - freeFloatRegs.push(freed_reg); + if (regFile->isIntPhysReg(freed_reg)) { + intList.addReg(freed_reg); + } else { + assert(regFile->isFloatPhysReg(freed_reg)); + floatList.addReg(freed_reg); } // These assert conditions ensure that the number of free @@ -188,20 +187,5 @@ SimpleFreeList::addReg(PhysRegIndex freed_reg) // assert(freeFloatRegs.size() <= numPhysicalFloatRegs); } -inline void -SimpleFreeList::addIntReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing int register %i.\n", freed_reg); - - freeIntRegs.push(freed_reg); -} - -inline void -SimpleFreeList::addFloatReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing float register %i.\n", freed_reg); - - freeFloatRegs.push(freed_reg); -} #endif // __CPU_O3_FREE_LIST_HH__ diff --git a/src/cpu/o3/regfile.cc b/src/cpu/o3/regfile.cc new file mode 100644 index 000000000..5ba0caefc --- /dev/null +++ b/src/cpu/o3/regfile.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. + * 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 + * Gabe Black + * Steve Reinhardt + */ + +#include "cpu/o3/free_list.hh" +#include "cpu/o3/regfile.hh" + + +PhysRegFile::PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs) + : intRegFile(_numPhysicalIntRegs), + floatRegFile(_numPhysicalFloatRegs), + baseFloatRegIndex(_numPhysicalIntRegs), + totalNumRegs(_numPhysicalIntRegs + _numPhysicalFloatRegs) +{ +} + + +void +PhysRegFile::initFreeList(UnifiedFreeList *freeList) +{ + // Initialize the free lists. + PhysRegIndex reg_idx = 0; + + // The initial batch of registers are the integer ones + while (reg_idx < baseFloatRegIndex) { + freeList->addIntReg(reg_idx++); + } + + // The rest of the registers are the floating-point physical + // registers; put them onto the floating-point free list. + while (reg_idx < totalNumRegs) { + freeList->addFloatReg(reg_idx++); + } +} diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh index b58f7a2a5..bd3a4f730 100644 --- a/src/cpu/o3/regfile.hh +++ b/src/cpu/o3/regfile.hh @@ -43,6 +43,8 @@ #include "cpu/o3/comm.hh" #include "debug/IEW.hh" +class UnifiedFreeList; + /** * Simple physical register file class. */ @@ -60,10 +62,10 @@ class PhysRegFile } PhysFloatReg; /** Integer register file. */ - IntReg *intRegFile; + std::vector intRegFile; /** Floating point register file. */ - PhysFloatReg *floatRegFile; + std::vector floatRegFile; /** * The first floating-point physical register index. The physical @@ -72,6 +74,12 @@ class PhysRegFile * immediately by the floating-point registers. Thus the first * floating-point index is equal to the number of integer * registers. + * + * Note that this internal organizational detail on how physical + * register file indices are ordered should *NOT* be exposed + * outside of this class. Other classes can use the is*PhysReg() + * methods to map from a physical register index to a class + * without knowing the internal structure of the index map. */ unsigned baseFloatRegIndex; @@ -89,7 +97,10 @@ class PhysRegFile /** * Destructor to free resources */ - ~PhysRegFile(); + ~PhysRegFile() {} + + /** Initialize the free list */ + void initFreeList(UnifiedFreeList *freeList); /** @return the number of integer physical registers. */ unsigned numIntPhysRegs() const { return baseFloatRegIndex; } @@ -203,25 +214,4 @@ class PhysRegFile }; -inline -PhysRegFile::PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs) - : baseFloatRegIndex(_numPhysicalIntRegs), - totalNumRegs(_numPhysicalIntRegs + _numPhysicalFloatRegs) -{ - intRegFile = new IntReg[_numPhysicalIntRegs]; - floatRegFile = new PhysFloatReg[_numPhysicalFloatRegs]; - - memset(intRegFile, 0, sizeof(IntReg) * _numPhysicalIntRegs); - memset(floatRegFile, 0, sizeof(PhysFloatReg) * _numPhysicalFloatRegs); -} - - -inline -PhysRegFile::~PhysRegFile() -{ - delete intRegFile; - delete floatRegFile; -} - #endif //__CPU_O3_REGFILE_HH__ diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index 60a929551..6bfc7d952 100644 --- a/src/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh @@ -871,18 +871,26 @@ DefaultRename::doSquash(const InstSeqNum &squashed_seq_num, ThreadID tid) // Go through the most recent instructions, undoing the mappings // they did and freeing up the registers. while (!historyBuffer[tid].empty() && - (*hb_it).instSeqNum > squashed_seq_num) { + hb_it->instSeqNum > squashed_seq_num) { assert(hb_it != historyBuffer[tid].end()); DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " - "number %i.\n", tid, (*hb_it).instSeqNum); - - // Tell the rename map to set the architected register to the - // previous physical register that it was renamed to. - renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg); - - // Put the renamed physical register back on the free list. - freeList->addReg(hb_it->newPhysReg); + "number %i.\n", tid, hb_it->instSeqNum); + + // Undo the rename mapping only if it was really a change. + // Special regs that are not really renamed (like misc regs + // and the zero reg) can be recognized because the new mapping + // is the same as the old one. While it would be merely a + // waste of time to update the rename table, we definitely + // don't want to put these on the free list. + if (hb_it->newPhysReg != hb_it->prevPhysReg) { + // Tell the rename map to set the architected register to the + // previous physical register that it was renamed to. + renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg); + + // Put the renamed physical register back on the free list. + freeList->addReg(hb_it->newPhysReg); + } historyBuffer[tid].erase(hb_it++); @@ -918,13 +926,19 @@ DefaultRename::removeFromHistory(InstSeqNum inst_seq_num, ThreadID tid) // renamed. while (!historyBuffer[tid].empty() && hb_it != historyBuffer[tid].end() && - (*hb_it).instSeqNum <= inst_seq_num) { + hb_it->instSeqNum <= inst_seq_num) { DPRINTF(Rename, "[tid:%u]: Freeing up older rename of reg %i, " "[sn:%lli].\n", - tid, (*hb_it).prevPhysReg, (*hb_it).instSeqNum); + tid, hb_it->prevPhysReg, hb_it->instSeqNum); + + // Don't free special phys regs like misc and zero regs, which + // can be recognized because the new mapping is the same as + // the old one. + if (hb_it->newPhysReg != hb_it->prevPhysReg) { + freeList->addReg(hb_it->prevPhysReg); + } - freeList->addReg((*hb_it).prevPhysReg); ++renameCommittedMaps; historyBuffer[tid].erase(hb_it--); @@ -935,54 +949,49 @@ template inline void DefaultRename::renameSrcRegs(DynInstPtr &inst, ThreadID tid) { - assert(renameMap[tid] != 0); - + ThreadContext *tc = inst->tcBase(); + RenameMap *map = renameMap[tid]; unsigned num_src_regs = inst->numSrcRegs(); // Get the architectual register numbers from the source and - // destination operands, and redirect them to the right register. - // Will need to mark dependencies though. + // operands, and redirect them to the right physical register. for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { RegIndex src_reg = inst->srcRegIdx(src_idx); - RegIndex flat_src_reg = src_reg; - switch (regIdxToClass(src_reg)) { + RegIndex rel_src_reg; + RegIndex flat_rel_src_reg; + PhysRegIndex renamed_reg; + + switch (regIdxToClass(src_reg, &rel_src_reg)) { case IntRegClass: - flat_src_reg = inst->tcBase()->flattenIntIndex(src_reg); - DPRINTF(Rename, "Flattening index %d to %d.\n", - (int)src_reg, (int)flat_src_reg); + flat_rel_src_reg = tc->flattenIntIndex(rel_src_reg); + renamed_reg = map->lookupInt(flat_rel_src_reg); + intRenameLookups++; break; case FloatRegClass: - src_reg = src_reg - TheISA::FP_Reg_Base; - flat_src_reg = inst->tcBase()->flattenFloatIndex(src_reg); - DPRINTF(Rename, "Flattening index %d to %d.\n", - (int)src_reg, (int)flat_src_reg); - flat_src_reg += TheISA::NumIntRegs; + flat_rel_src_reg = tc->flattenFloatIndex(rel_src_reg); + renamed_reg = map->lookupFloat(flat_rel_src_reg); + fpRenameLookups++; break; case MiscRegClass: - flat_src_reg = src_reg - TheISA::Misc_Reg_Base + - TheISA::NumFloatRegs + TheISA::NumIntRegs; - DPRINTF(Rename, "Adjusting reg index from %d to %d.\n", - src_reg, flat_src_reg); + // misc regs don't get flattened + flat_rel_src_reg = rel_src_reg; + renamed_reg = map->lookupMisc(flat_rel_src_reg); break; default: panic("Reg index is out of bound: %d.", src_reg); } - // Look up the source registers to get the phys. register they've - // been renamed to, and set the sources to those registers. - PhysRegIndex renamed_reg = renameMap[tid]->lookup(flat_src_reg); - - DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got " - "physical reg %i.\n", tid, (int)flat_src_reg, - (int)renamed_reg); + DPRINTF(Rename, "[tid:%u]: Looking up %s arch reg %i (flattened %i), " + "got phys reg %i\n", tid, RegClassStrings[regIdxToClass(src_reg)], + (int)src_reg, (int)flat_rel_src_reg, (int)renamed_reg); inst->renameSrcReg(src_idx, renamed_reg); // See if the register is ready or not. - if (scoreboard->getReg(renamed_reg) == true) { + if (scoreboard->getReg(renamed_reg)) { DPRINTF(Rename, "[tid:%u]: Register %d is ready.\n", tid, renamed_reg); @@ -993,7 +1002,6 @@ DefaultRename::renameSrcRegs(DynInstPtr &inst, ThreadID tid) } ++renameRenameLookups; - inst->isFloating() ? fpRenameLookups++ : intRenameLookups++; } } @@ -1001,58 +1009,53 @@ template inline void DefaultRename::renameDestRegs(DynInstPtr &inst, ThreadID tid) { - typename RenameMap::RenameInfo rename_result; - + ThreadContext *tc = inst->tcBase(); + RenameMap *map = renameMap[tid]; unsigned num_dest_regs = inst->numDestRegs(); // Rename the destination registers. for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { RegIndex dest_reg = inst->destRegIdx(dest_idx); - RegIndex flat_dest_reg = dest_reg; - switch (regIdxToClass(dest_reg)) { + RegIndex rel_dest_reg; + RegIndex flat_rel_dest_reg; + RegIndex flat_uni_dest_reg; + typename RenameMap::RenameInfo rename_result; + + switch (regIdxToClass(dest_reg, &rel_dest_reg)) { case IntRegClass: - // Integer registers are flattened. - flat_dest_reg = inst->tcBase()->flattenIntIndex(dest_reg); - DPRINTF(Rename, "Flattening index %d to %d.\n", - (int)dest_reg, (int)flat_dest_reg); + flat_rel_dest_reg = tc->flattenIntIndex(rel_dest_reg); + rename_result = map->renameInt(flat_rel_dest_reg); + flat_uni_dest_reg = flat_rel_dest_reg; // 1:1 mapping break; case FloatRegClass: - dest_reg = dest_reg - TheISA::FP_Reg_Base; - flat_dest_reg = inst->tcBase()->flattenFloatIndex(dest_reg); - DPRINTF(Rename, "Flattening index %d to %d.\n", - (int)dest_reg, (int)flat_dest_reg); - flat_dest_reg += TheISA::NumIntRegs; + flat_rel_dest_reg = tc->flattenFloatIndex(rel_dest_reg); + rename_result = map->renameFloat(flat_rel_dest_reg); + flat_uni_dest_reg = flat_rel_dest_reg + TheISA::FP_Reg_Base; break; case MiscRegClass: - // Floating point and Miscellaneous registers need their indexes - // adjusted to account for the expanded number of flattened int regs. - flat_dest_reg = dest_reg - TheISA::Misc_Reg_Base + - TheISA::NumIntRegs + TheISA::NumFloatRegs; - DPRINTF(Rename, "Adjusting reg index from %d to %d.\n", - dest_reg, flat_dest_reg); + // misc regs don't get flattened + flat_rel_dest_reg = rel_dest_reg; + rename_result = map->renameMisc(flat_rel_dest_reg); + flat_uni_dest_reg = flat_rel_dest_reg + TheISA::Misc_Reg_Base; break; default: panic("Reg index is out of bound: %d.", dest_reg); } - inst->flattenDestReg(dest_idx, flat_dest_reg); - - // Get the physical register that the destination will be - // renamed to. - rename_result = renameMap[tid]->rename(flat_dest_reg); + inst->flattenDestReg(dest_idx, flat_uni_dest_reg); - //Mark Scoreboard entry as not ready + // Mark Scoreboard entry as not ready scoreboard->unsetReg(rename_result.first); DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " - "reg %i.\n", tid, (int)flat_dest_reg, + "reg %i.\n", tid, (int)flat_rel_dest_reg, (int)rename_result.first); // Record the rename information so that a history can be kept. - RenameHistory hb_entry(inst->seqNum, flat_dest_reg, + RenameHistory hb_entry(inst->seqNum, flat_uni_dest_reg, rename_result.first, rename_result.second); diff --git a/src/cpu/o3/rename_map.cc b/src/cpu/o3/rename_map.cc index 57caa76be..ecee4c721 100644 --- a/src/cpu/o3/rename_map.cc +++ b/src/cpu/o3/rename_map.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,222 +36,135 @@ using namespace std; -// @todo: Consider making inline bool functions that determine if the -// register is a logical int, logical fp, physical int, physical fp, -// etc. +/**** SimpleRenameMap methods ****/ -SimpleRenameMap::~SimpleRenameMap() +SimpleRenameMap::SimpleRenameMap() + : freeList(NULL) { } -void -SimpleRenameMap::init(unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - PhysRegIndex &ireg_idx, - - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - PhysRegIndex &freg_idx, - unsigned _numMiscRegs, +void +SimpleRenameMap::init(unsigned size, SimpleFreeList *_freeList, + RegIndex _zeroReg) +{ + assert(freeList == NULL); + assert(map.empty()); - RegIndex _intZeroReg, - RegIndex _floatZeroReg, + map.resize(size); + freeList = _freeList; + zeroReg = _zeroReg; +} - int map_id, - bool bindRegs) +SimpleRenameMap::RenameInfo +SimpleRenameMap::rename(RegIndex arch_reg) { - id = map_id; - - numLogicalIntRegs = _numLogicalIntRegs; + PhysRegIndex renamed_reg; - numLogicalFloatRegs = _numLogicalFloatRegs; + // Record the current physical register that is renamed to the + // requested architected register. + PhysRegIndex prev_reg = map[arch_reg]; - numPhysicalIntRegs = _numPhysicalIntRegs; + // If it's not referencing the zero register, then rename the + // register. + if (arch_reg != zeroReg) { + renamed_reg = freeList->getReg(); - numPhysicalFloatRegs = _numPhysicalFloatRegs; + map[arch_reg] = renamed_reg; + } else { + // Otherwise return the zero register so nothing bad happens. + assert(prev_reg == zeroReg); + renamed_reg = zeroReg; + } - numMiscRegs = _numMiscRegs; + DPRINTF(Rename, "Renamed reg %d to physical reg %d old mapping was %d\n", + arch_reg, renamed_reg, prev_reg); - intZeroReg = _intZeroReg; - floatZeroReg = _floatZeroReg; + return RenameInfo(renamed_reg, prev_reg); +} - DPRINTF(Rename, "Creating rename map %i. Phys: %i / %i, Float: " - "%i / %i.\n", id, numLogicalIntRegs, numPhysicalIntRegs, - numLogicalFloatRegs, numPhysicalFloatRegs); - numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs; +/**** UnifiedRenameMap methods ****/ - numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs; +void +UnifiedRenameMap::init(PhysRegFile *_regFile, + RegIndex _intZeroReg, + RegIndex _floatZeroReg, + UnifiedFreeList *freeList) +{ + regFile = _regFile; - //Create the rename maps - intRenameMap.resize(numLogicalIntRegs); - floatRenameMap.resize(numLogicalRegs); + intMap.init(TheISA::NumIntRegs, &(freeList->intList), _intZeroReg); - if (bindRegs) { - DPRINTF(Rename, "Binding registers into rename map %i\n",id); + floatMap.init(TheISA::NumFloatRegs, &(freeList->floatList), _floatZeroReg); +} - // Initialize the entries in the integer rename map to point to the - // physical registers of the same index - for (RegIndex index = 0; index < numLogicalIntRegs; ++index) - { - intRenameMap[index].physical_reg = ireg_idx++; - } - // Initialize the entries in the floating point rename map to point to - // the physical registers of the same index - // Although the index refers purely to architected registers, because - // the floating reg indices come after the integer reg indices, they - // may exceed the size of a normal RegIndex (short). - for (PhysRegIndex index = numLogicalIntRegs; - index < numLogicalRegs; ++index) - { - floatRenameMap[index].physical_reg = freg_idx++; - } - } else { - DPRINTF(Rename, "Binding registers into rename map %i\n",id); +UnifiedRenameMap::RenameInfo +UnifiedRenameMap::rename(RegIndex arch_reg) +{ + RegIndex rel_arch_reg; - PhysRegIndex temp_ireg = ireg_idx; + switch (regIdxToClass(arch_reg, &rel_arch_reg)) { + case IntRegClass: + return renameInt(rel_arch_reg); - for (RegIndex index = 0; index < numLogicalIntRegs; ++index) - { - intRenameMap[index].physical_reg = temp_ireg++; - } + case FloatRegClass: + return renameFloat(rel_arch_reg); - PhysRegIndex temp_freg = freg_idx; + case MiscRegClass: + return renameMisc(rel_arch_reg); - for (PhysRegIndex index = numLogicalIntRegs; - index < numLogicalRegs; ++index) - { - floatRenameMap[index].physical_reg = temp_freg++; - } + default: + panic("rename rename(): unknown reg class %s\n", + RegClassStrings[regIdxToClass(arch_reg)]); } } -void -SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr) -{ - freeList = fl_ptr; -} - -SimpleRenameMap::RenameInfo -SimpleRenameMap::rename(RegIndex arch_reg) +PhysRegIndex +UnifiedRenameMap::lookup(RegIndex arch_reg) const { - PhysRegIndex renamed_reg; - PhysRegIndex prev_reg; - - if (arch_reg < numLogicalIntRegs) { - - // Record the current physical register that is renamed to the - // requested architected register. - prev_reg = intRenameMap[arch_reg].physical_reg; - - // If it's not referencing the zero register, then rename the - // register. - if (arch_reg != intZeroReg) { - renamed_reg = freeList->getIntReg(); - - intRenameMap[arch_reg].physical_reg = renamed_reg; - - assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs); - - } else { - // Otherwise return the zero register so nothing bad happens. - renamed_reg = intZeroReg; - prev_reg = intZeroReg; - } - } else if (arch_reg < numLogicalRegs) { - // Record the current physical register that is renamed to the - // requested architected register. - prev_reg = floatRenameMap[arch_reg].physical_reg; - - // If it's not referencing the zero register, then rename the - // register. -#if THE_ISA == ALPHA_ISA - if (arch_reg != floatZeroReg) { -#endif - renamed_reg = freeList->getFloatReg(); - - floatRenameMap[arch_reg].physical_reg = renamed_reg; - - assert(renamed_reg < numPhysicalRegs && - renamed_reg >= numPhysicalIntRegs); -#if THE_ISA == ALPHA_ISA - } else { - // Otherwise return the zero register so nothing bad happens. - renamed_reg = floatZeroReg; - } -#endif - } else { - // Subtract off the base offset for miscellaneous registers. - arch_reg = arch_reg - numLogicalRegs; + RegIndex rel_arch_reg; - DPRINTF(Rename, "Renamed misc reg %d\n", arch_reg); + switch (regIdxToClass(arch_reg, &rel_arch_reg)) { + case IntRegClass: + return lookupInt(rel_arch_reg); - // No renaming happens to the misc. registers. They are - // simply the registers that come after all the physical - // registers; thus take the base architected register and add - // the physical registers to it. - renamed_reg = arch_reg + numPhysicalRegs; + case FloatRegClass: + return lookupFloat(rel_arch_reg); - // Set the previous register to the same register; mainly it must be - // known that the prev reg was outside the range of normal registers - // so the free list can avoid adding it. - prev_reg = renamed_reg; - } - - DPRINTF(Rename, "Renamed reg %d to physical reg %d old mapping was %d\n", - arch_reg, renamed_reg, prev_reg); + case MiscRegClass: + return lookupMisc(rel_arch_reg); - return RenameInfo(renamed_reg, prev_reg); -} - -PhysRegIndex -SimpleRenameMap::lookup(RegIndex arch_reg) -{ - if (arch_reg < numLogicalIntRegs) { - return intRenameMap[arch_reg].physical_reg; - } else if (arch_reg < numLogicalRegs) { - return floatRenameMap[arch_reg].physical_reg; - } else { - // Subtract off the misc registers offset. - arch_reg = arch_reg - numLogicalRegs; - - // Misc. regs don't rename, so simply add the base arch reg to - // the number of physical registers. - return numPhysicalRegs + arch_reg; + default: + panic("rename lookup(): unknown reg class %s\n", + RegClassStrings[regIdxToClass(arch_reg)]); } } void -SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg) +UnifiedRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex phys_reg) { - // In this implementation the miscellaneous registers do not - // actually rename, so this function does not allow you to try to - // change their mappings. - if (arch_reg < numLogicalIntRegs) { - DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n", - (int)arch_reg, renamed_reg); - - intRenameMap[arch_reg].physical_reg = renamed_reg; - } else if (arch_reg < numLogicalIntRegs + numLogicalFloatRegs) { - DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n", - (int)arch_reg - numLogicalIntRegs, renamed_reg); - - floatRenameMap[arch_reg].physical_reg = renamed_reg; - } -} - -int -SimpleRenameMap::numFreeEntries() -{ - int free_int_regs = freeList->numFreeIntRegs(); - int free_float_regs = freeList->numFreeFloatRegs(); - - if (free_int_regs < free_float_regs) { - return free_int_regs; - } else { - return free_float_regs; + RegIndex rel_arch_reg; + + switch (regIdxToClass(arch_reg, &rel_arch_reg)) { + case IntRegClass: + return setIntEntry(rel_arch_reg, phys_reg); + + case FloatRegClass: + return setFloatEntry(rel_arch_reg, phys_reg); + + case MiscRegClass: + // Misc registers do not actually rename, so don't change + // their mappings. We end up here when a commit or squash + // tries to update or undo a hardwired misc reg nmapping, + // which should always be setting it to what it already is. + assert(phys_reg == lookupMisc(rel_arch_reg)); + return; + + default: + panic("rename setEntry(): unknown reg class %s\n", + RegClassStrings[regIdxToClass(arch_reg)]); } } diff --git a/src/cpu/o3/rename_map.hh b/src/cpu/o3/rename_map.hh index 51d8db4d8..c989fb88f 100644 --- a/src/cpu/o3/rename_map.hh +++ b/src/cpu/o3/rename_map.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,6 +27,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim + * Steve Reinhardt */ // Todo: Create destructor. @@ -42,18 +44,54 @@ #include "arch/types.hh" #include "config/the_isa.hh" #include "cpu/o3/free_list.hh" - +#include "cpu/o3/regfile.hh" +#include "cpu/reg_class.hh" + +/** + * Register rename map for a single class of registers (e.g., integer + * or floating point). Because the register class is implicitly + * determined by the rename map instance being accessed, all + * architectural register index parameters and values in this class + * are relative (e.g., %fp2 is just index 2). + */ class SimpleRenameMap { - protected: + public: + typedef TheISA::RegIndex RegIndex; + + private: + + /** The acutal arch-to-phys register map */ + std::vector map; + + /** + * Pointer to the free list from which new physical registers + * should be allocated in rename() + */ + SimpleFreeList *freeList; + + /** + * The architectural index of the zero register. This register is + * mapped but read-only, so we ignore attempts to rename it via + * the rename() method. If there is no such register for this map + * table, it should be set to an invalid index so that it never + * matches. + */ + RegIndex zeroReg; + public: + + SimpleRenameMap(); + + ~SimpleRenameMap() {}; + /** - * Pair of a logical register and a physical register. Tells the - * previous mapping of a logical register to a physical register. - * Used to roll back the rename map to a previous state. + * Because we have an array of rename maps (one per thread) in the CPU, + * it's awkward to initialize this object via the constructor. + * Instead, this method is used for initialization. */ - typedef std::pair UnmapInfo; + void init(unsigned size, SimpleFreeList *_freeList, RegIndex _zeroReg); /** * Pair of a physical register and a physical register. Used to @@ -63,106 +101,216 @@ class SimpleRenameMap */ typedef std::pair RenameInfo; - public: - /** Default constructor. init() must be called prior to use. */ - SimpleRenameMap() {}; - - /** Destructor. */ - ~SimpleRenameMap(); - - /** Initializes rename map with given parameters. */ - void init(unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - PhysRegIndex &_int_reg_start, + /** + * Tell rename map to get a new free physical register to remap + * the specified architectural register. + * @param arch_reg The architectural register to remap. + * @return A RenameInfo pair indicating both the new and previous + * physical registers. + */ + RenameInfo rename(RegIndex arch_reg); - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - PhysRegIndex &_float_reg_start, + /** + * Look up the physical register mapped to an architectural register. + * @param arch_reg The architectural register to look up. + * @return The physical register it is currently mapped to. + */ + PhysRegIndex lookup(RegIndex arch_reg) const + { + assert(arch_reg < map.size()); + return map[arch_reg]; + } - unsigned _numMiscRegs, + /** + * Update rename map with a specific mapping. Generally used to + * roll back to old mappings on a squash. + * @param arch_reg The architectural register to remap. + * @param phys_reg The physical register to remap it to. + */ + void setEntry(RegIndex arch_reg, PhysRegIndex phys_reg) + { + map[arch_reg] = phys_reg; + } - RegIndex _intZeroReg, - RegIndex _floatZeroReg, + /** Return the number of free entries on the associated free list. */ + unsigned numFreeEntries() const { return freeList->numFreeRegs(); } +}; - int id, - bool bindRegs); - /** Sets the free list used with this rename map. */ - void setFreeList(SimpleFreeList *fl_ptr); +/** + * Unified register rename map for all classes of registers. Wraps a + * set of class-specific rename maps. Methods that do not specify a + * register class (e.g., rename()) take unified register indices, + * while methods that do specify a register class (e.g., renameInt()) + * take relative register indices. See http://gem5.org/Register_Indexing. + */ +class UnifiedRenameMap +{ + private: - //Tell rename map to get a free physical register for a given - //architected register. Not sure it should have a return value, - //but perhaps it should have some sort of fault in case there are - //no free registers. - RenameInfo rename(RegIndex arch_reg); + /** The integer register rename map */ + SimpleRenameMap intMap; - PhysRegIndex lookup(RegIndex phys_reg); + /** The floating-point register rename map */ + SimpleRenameMap floatMap; /** - * Marks the given register as ready, meaning that its value has been - * calculated and written to the register file. - * @param ready_reg The index of the physical register that is now ready. + * The register file object is used only to distinguish integer + * from floating-point physical register indices, which in turn is + * used only for assert statements that make sure the physical + * register indices that get passed in and handed out are of the + * proper class. */ - void setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg); + PhysRegFile *regFile; + + public: + typedef TheISA::RegIndex RegIndex; - int numFreeEntries(); + typedef SimpleRenameMap::RenameInfo RenameInfo; - private: - /** Rename Map ID */ - int id; + /** Default constructor. init() must be called prior to use. */ + UnifiedRenameMap() {}; - /** Number of logical integer registers. */ - int numLogicalIntRegs; + /** Destructor. */ + ~UnifiedRenameMap() {}; - /** Number of physical integer registers. */ - int numPhysicalIntRegs; + /** Initializes rename map with given parameters. */ + void init(PhysRegFile *_regFile, + RegIndex _intZeroReg, + RegIndex _floatZeroReg, + UnifiedFreeList *freeList); - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; + /** + * Tell rename map to get a new free physical register to remap + * the specified architectural register. This version takes a + * unified flattened architectural register index and calls the + * appropriate class-specific rename table. + * @param arch_reg The unified architectural register index to remap. + * @return A RenameInfo pair indicating both the new and previous + * physical registers. + */ + RenameInfo rename(RegIndex arch_reg); - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; + /** + * Perform rename() on an integer register, given a relative + * integer register index. + */ + RenameInfo renameInt(RegIndex rel_arch_reg) + { + RenameInfo info = intMap.rename(rel_arch_reg); + assert(regFile->isIntPhysReg(info.first)); + return info; + } + + /** + * Perform rename() on a floating-point register, given a relative + * floating-point register index. + */ + RenameInfo renameFloat(RegIndex rel_arch_reg) + { + RenameInfo info = floatMap.rename(rel_arch_reg); + assert(regFile->isFloatPhysReg(info.first)); + return info; + } - /** Number of miscellaneous registers. */ - int numMiscRegs; + /** + * Perform rename() on a misc register, given a relative + * misc register index. + */ + RenameInfo renameMisc(RegIndex rel_arch_reg) + { + // misc regs aren't really renamed, just remapped + PhysRegIndex phys_reg = lookupMisc(rel_arch_reg); + // Set the previous register to the same register; mainly it must be + // known that the prev reg was outside the range of normal registers + // so the free list can avoid adding it. + return RenameInfo(phys_reg, phys_reg); + } - /** Number of logical integer + float registers. */ - int numLogicalRegs; - /** Number of physical integer + float registers. */ - int numPhysicalRegs; + /** + * Look up the physical register mapped to an architectural register. + * This version takes a unified flattened architectural register index + * and calls the appropriate class-specific rename table. + * @param arch_reg The unified architectural register to look up. + * @return The physical register it is currently mapped to. + */ + PhysRegIndex lookup(RegIndex arch_reg) const; - /** The integer zero register. This implementation assumes it is always - * zero and never can be anything else. + /** + * Perform lookup() on an integer register, given a relative + * integer register index. */ - RegIndex intZeroReg; + PhysRegIndex lookupInt(RegIndex rel_arch_reg) const + { + PhysRegIndex phys_reg = intMap.lookup(rel_arch_reg); + assert(regFile->isIntPhysReg(phys_reg)); + return phys_reg; + } - /** The floating point zero register. This implementation assumes it is - * always zero and never can be anything else. + /** + * Perform lookup() on a floating-point register, given a relative + * floating-point register index. */ - RegIndex floatZeroReg; + PhysRegIndex lookupFloat(RegIndex rel_arch_reg) const + { + PhysRegIndex phys_reg = floatMap.lookup(rel_arch_reg); + assert(regFile->isFloatPhysReg(phys_reg)); + return phys_reg; + } - class RenameEntry + /** + * Perform lookup() on a misc register, given a relative + * misc register index. + */ + PhysRegIndex lookupMisc(RegIndex rel_arch_reg) const { - public: - PhysRegIndex physical_reg; - bool valid; + // misc regs aren't really renamed, just given an index + // beyond the range of actual physical registers + PhysRegIndex phys_reg = rel_arch_reg + regFile->totalNumPhysRegs(); + return phys_reg; + } - RenameEntry() - : physical_reg(0), valid(false) - { } - }; + /** + * Update rename map with a specific mapping. Generally used to + * roll back to old mappings on a squash. This version takes a + * unified flattened architectural register index and calls the + * appropriate class-specific rename table. + * @param arch_reg The unified architectural register to remap. + * @param phys_reg The physical register to remap it to. + */ + void setEntry(RegIndex arch_reg, PhysRegIndex phys_reg); - private: - /** Integer rename map. */ - std::vector intRenameMap; + /** + * Perform setEntry() on an integer register, given a relative + * integer register index. + */ + void setIntEntry(RegIndex arch_reg, PhysRegIndex phys_reg) + { + assert(regFile->isIntPhysReg(phys_reg)); + intMap.setEntry(arch_reg, phys_reg); + } - /** Floating point rename map. */ - std::vector floatRenameMap; + /** + * Perform setEntry() on a floating-point register, given a relative + * floating-point register index. + */ + void setFloatEntry(RegIndex arch_reg, PhysRegIndex phys_reg) + { + assert(regFile->isFloatPhysReg(phys_reg)); + floatMap.setEntry(arch_reg, phys_reg); + } - private: - /** Free list interface. */ - SimpleFreeList *freeList; + /** + * Return the minimum number of free entries across all of the + * register classes. The minimum is used so we guarantee that + * this number of entries is available regardless of which class + * of registers is requested. + */ + unsigned numFreeEntries() const + { + return std::min(intMap.numFreeEntries(), floatMap.numFreeEntries()); + } }; #endif //__CPU_O3_RENAME_MAP_HH__ -- 2.30.2