cpu: Result refactoring

The Result union used to collect the result of an instruction is now a
class of its own, with its constructor, and explicit casting methods for
cleanliness.

This is also a stepping stone to have vector registers, and instructions
that produce a vector register as output.

Change-Id: I6f40c11cb5e835d8b11f7804a4e967aff18025b9
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/2703
Reviewed-by: Anthony Gutierrez <anthony.gutierrez@amd.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Rekai Gonzalez-Alberquilla
2017-04-05 13:20:30 -05:00
committed by Andreas Sandberg
parent a473b5a6eb
commit 2da7656a9a
4 changed files with 205 additions and 78 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 ARM Limited
* Copyright (c) 2011, 2016 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
@@ -53,6 +53,7 @@
#include "cpu/base.hh"
#include "cpu/base_dyn_inst.hh"
#include "cpu/exec_context.hh"
#include "cpu/inst_res.hh"
#include "cpu/pc_event.hh"
#include "cpu/simple_thread.hh"
#include "cpu/static_inst.hh"
@@ -143,18 +144,9 @@ class CheckerCPU : public BaseCPU, public ExecContext
Addr dbg_vtophys(Addr addr);
union Result {
uint64_t integer;
double dbl;
void set(uint64_t i) { integer = i; }
void set(double d) { dbl = d; }
void get(uint64_t& i) { i = integer; }
void get(double& d) { d = dbl; }
};
// ISAs like ARM can have multiple destination registers to check,
// keep them all in a std::queue
std::queue<Result> result;
std::queue<InstResult> result;
// Pointer to the one memory request.
RequestPtr memReq;
@@ -240,12 +232,11 @@ class CheckerCPU : public BaseCPU, public ExecContext
return thread->readCCReg(reg.index());
}
template <class T>
void setResult(T t)
template<typename T>
void setScalarResult(T&& t)
{
Result instRes;
instRes.set(t);
result.push(instRes);
result.push(InstResult(std::forward<T>(t),
InstResult::ResultType::Scalar));
}
void setIntRegOperand(const StaticInst *si, int idx,
@@ -254,7 +245,7 @@ class CheckerCPU : public BaseCPU, public ExecContext
const RegId& reg = si->destRegIdx(idx);
assert(reg.isIntReg());
thread->setIntReg(reg.index(), val);
setResult<uint64_t>(val);
setScalarResult(val);
}
void setFloatRegOperand(const StaticInst *si, int idx,
@@ -263,7 +254,7 @@ class CheckerCPU : public BaseCPU, public ExecContext
const RegId& reg = si->destRegIdx(idx);
assert(reg.isFloatReg());
thread->setFloatReg(reg.index(), val);
setResult<double>(val);
setScalarResult(val);
}
void setFloatRegOperandBits(const StaticInst *si, int idx,
@@ -272,7 +263,7 @@ class CheckerCPU : public BaseCPU, public ExecContext
const RegId& reg = si->destRegIdx(idx);
assert(reg.isFloatReg());
thread->setFloatRegBits(reg.index(), val);
setResult<uint64_t>(val);
setScalarResult(val);
}
void setCCRegOperand(const StaticInst *si, int idx, CCReg val) override
@@ -280,7 +271,7 @@ class CheckerCPU : public BaseCPU, public ExecContext
const RegId& reg = si->destRegIdx(idx);
assert(reg.isCCReg());
thread->setCCReg(reg.index(), val);
setResult<uint64_t>(val);
setScalarResult((uint64_t)val);
}
bool readPredicate() override { return thread->readPredicate(); }
@@ -422,7 +413,7 @@ class CheckerCPU : public BaseCPU, public ExecContext
ThreadContext *tcBase() override { return tc; }
SimpleThread *threadBase() { return thread; }
Result unverifiedResult;
InstResult unverifiedResult;
Request *unverifiedReq;
uint8_t *unverifiedMemData;
@@ -464,7 +455,8 @@ class Checker : public CheckerCPU
void validateExecution(DynInstPtr &inst);
void validateState();
void copyResult(DynInstPtr &inst, uint64_t mismatch_val, int start_idx);
void copyResult(DynInstPtr &inst, const InstResult& mismatch_val,
int start_idx);
void handlePendingInt();
private:

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 ARM Limited
* Copyright (c) 2011, 2016 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
@@ -481,27 +481,29 @@ template <class Impl>
void
Checker<Impl>::validateExecution(DynInstPtr &inst)
{
uint64_t checker_val;
uint64_t inst_val;
InstResult checker_val;
InstResult inst_val;
int idx = -1;
bool result_mismatch = false;
bool scalar_mismatch = false;
if (inst->isUnverifiable()) {
// Unverifiable instructions assume they were executed
// properly by the CPU. Grab the result from the
// instruction and write it to the register.
copyResult(inst, 0, idx);
copyResult(inst, InstResult(0ul, InstResult::ResultType::Scalar), idx);
} else if (inst->numDestRegs() > 0 && !result.empty()) {
DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n",
inst->numDestRegs(), result.size());
for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) {
result.front().get(checker_val);
checker_val = result.front();
result.pop();
inst_val = 0;
inst->template popResult<uint64_t>(inst_val);
inst_val = inst->popResult(
InstResult(0ul, InstResult::ResultType::Scalar));
if (checker_val != inst_val) {
result_mismatch = true;
idx = i;
scalar_mismatch = true;
break;
}
}
@@ -512,9 +514,12 @@ Checker<Impl>::validateExecution(DynInstPtr &inst)
// this is ok and not a bug. May be worthwhile to try and correct this.
if (result_mismatch) {
warn("%lli: Instruction results do not match! (Values may not "
"actually be integers) Inst: %#x, checker: %#x",
curTick(), inst_val, checker_val);
if (scalar_mismatch) {
warn("%lli: Instruction results (%i) do not match! (Values may"
" not actually be integers) Inst: %#x, checker: %#x",
curTick(), idx, inst_val.asIntegerNoAssert(),
checker_val.asInteger());
}
// It's useful to verify load values from memory, but in MP
// systems the value obtained at execute may be different than
@@ -589,7 +594,7 @@ Checker<Impl>::validateState()
template <class Impl>
void
Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
Checker<Impl>::copyResult(DynInstPtr &inst, const InstResult& mismatch_val,
int start_idx)
{
// We've already popped one dest off the queue,
@@ -598,37 +603,45 @@ Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
const RegId& idx = inst->destRegIdx(start_idx);
switch (idx.classValue()) {
case IntRegClass:
thread->setIntReg(idx.index(), mismatch_val);
panic_if(!mismatch_val.isScalar(), "Unexpected type of result");
thread->setIntReg(idx.index(), mismatch_val.asInteger());
break;
case FloatRegClass:
thread->setFloatRegBits(idx.index(), mismatch_val);
panic_if(!mismatch_val.isScalar(), "Unexpected type of result");
thread->setFloatRegBits(idx.index(), mismatch_val.asInteger());
break;
case CCRegClass:
thread->setCCReg(idx.index(), mismatch_val);
panic_if(!mismatch_val.isScalar(), "Unexpected type of result");
thread->setCCReg(idx.index(), mismatch_val.asInteger());
break;
case MiscRegClass:
thread->setMiscReg(idx.index(), mismatch_val);
panic_if(!mismatch_val.isScalar(), "Unexpected type of result");
thread->setMiscReg(idx.index(), mismatch_val.asInteger());
break;
}
}
start_idx++;
uint64_t res = 0;
InstResult res;
for (int i = start_idx; i < inst->numDestRegs(); i++) {
const RegId& idx = inst->destRegIdx(i);
inst->template popResult<uint64_t>(res);
res = inst->popResult();
switch (idx.classValue()) {
case IntRegClass:
thread->setIntReg(idx.index(), res);
panic_if(!res.isScalar(), "Unexpected type of result");
thread->setIntReg(idx.index(), res.asInteger());
break;
case FloatRegClass:
thread->setFloatRegBits(idx.index(), res);
panic_if(!res.isScalar(), "Unexpected type of result");
thread->setFloatRegBits(idx.index(), res.asInteger());
break;
case CCRegClass:
thread->setCCReg(idx.index(), res);
panic_if(!res.isScalar(), "Unexpected type of result");
thread->setCCReg(idx.index(), res.asInteger());
break;
case MiscRegClass:
panic_if(res.isValid(), "MiscReg expecting invalid result");
// Try to get the proper misc register index for ARM here...
thread->setMiscReg(idx.index(), res);
thread->setMiscReg(idx.index(), 0);
break;
// else Register is out of range...
}