cpu: Replace fixed sized arrays in the O3 inst with variable arrays.

The only way to allocate fixed sized arrays which will definitely be big
enough for all source/destination registers for a given instruction is
to track the maximum number of each at compile time, and then size the
arrays appropriately. That creates a point of centralization which
prevents breaking up decoder and instruction definitions into more
modular pieces, and if multiple ISAs are ever built at once, would
require coordination between all ISAs, and wasting memory for most of
them.

The dynamic allocation overhead is minimized by allocating the storage
for all variable arrays in one chunk, and then placing the arrays there
using placement new. There is still some overhead, although less than it
might be otherwise.

Change-Id: Id2c42869cba944deb97da01ca9e0e70186e22532
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/38384
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2020-12-07 04:41:45 -08:00
parent 57dd228cad
commit 344ea0330a
9 changed files with 217 additions and 134 deletions

View File

@@ -1004,7 +1004,7 @@ InstructionQueue<Impl>::wakeDependents(const DynInstPtr &completed_inst)
dest_reg_idx++)
{
PhysRegIdPtr dest_reg =
completed_inst->renamedDestRegIdx(dest_reg_idx);
completed_inst->regs.renamedDestIdx(dest_reg_idx);
// Special case of uniq or control registers. They are not
// handled by the IQ and thus have no dependency graph entry.
@@ -1242,7 +1242,7 @@ InstructionQueue<Impl>::doSquash(ThreadID tid)
src_reg_idx++)
{
PhysRegIdPtr src_reg =
squashed_inst->renamedSrcRegIdx(src_reg_idx);
squashed_inst->regs.renamedSrcIdx(src_reg_idx);
// Only remove it from the dependency graph if it
// was placed there in the first place.
@@ -1253,7 +1253,7 @@ InstructionQueue<Impl>::doSquash(ThreadID tid)
// overwritten. The only downside to this is it
// leaves more room for error.
if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) &&
if (!squashed_inst->regs.readySrcIdx(src_reg_idx) &&
!src_reg->isFixedMapping()) {
dependGraph.remove(src_reg->flatIndex(),
squashed_inst);
@@ -1315,7 +1315,7 @@ InstructionQueue<Impl>::doSquash(ThreadID tid)
dest_reg_idx++)
{
PhysRegIdPtr dest_reg =
squashed_inst->renamedDestRegIdx(dest_reg_idx);
squashed_inst->regs.renamedDestIdx(dest_reg_idx);
if (dest_reg->isFixedMapping()){
continue;
}
@@ -1341,8 +1341,8 @@ InstructionQueue<Impl>::addToDependents(const DynInstPtr &new_inst)
src_reg_idx++)
{
// Only add it to the dependency graph if it's not ready.
if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
PhysRegIdPtr src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
if (!new_inst->regs.readySrcIdx(src_reg_idx)) {
PhysRegIdPtr src_reg = new_inst->regs.renamedSrcIdx(src_reg_idx);
// Check the IQ's scoreboard to make sure the register
// hasn't become ready while the instruction was in flight
@@ -1389,7 +1389,7 @@ InstructionQueue<Impl>::addToProducers(const DynInstPtr &new_inst)
dest_reg_idx < total_dest_regs;
dest_reg_idx++)
{
PhysRegIdPtr dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
PhysRegIdPtr dest_reg = new_inst->regs.renamedDestIdx(dest_reg_idx);
// Some registers have fixed mapping, and there is no need to track
// dependencies as these instructions must be executed at commit.