cpu: Use std::variant to simplify InstResult.

std::variant is a similar to (and also modestly superior to)
MultiResult. Use it instead to simplify InstResult.

Change-Id: I22338f5e89814c6d13538129757158126013a414
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/49127
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2021-08-09 01:19:27 -07:00
parent 7f540a333d
commit 91f7486482
4 changed files with 47 additions and 107 deletions

View File

@@ -248,24 +248,21 @@ class CheckerCPU : public BaseCPU, public ExecContext
void
setScalarResult(T&& t)
{
result.push(InstResult(std::forward<T>(t),
InstResult::ResultType::Scalar));
result.push(InstResult(std::forward<T>(t)));
}
template<typename T>
void
setVecResult(T&& t)
{
result.push(InstResult(std::forward<T>(t),
InstResult::ResultType::VecReg));
result.push(InstResult(std::forward<T>(t)));
}
template<typename T>
void
setVecPredResult(T&& t)
{
result.push(InstResult(std::forward<T>(t),
InstResult::ResultType::VecPredReg));
result.push(InstResult(std::forward<T>(t)));
}
void

View File

@@ -477,15 +477,14 @@ Checker<DynInstPtr>::validateExecution(const DynInstPtr &inst)
// Unverifiable instructions assume they were executed
// properly by the CPU. Grab the result from the
// instruction and write it to the register.
copyResult(inst, InstResult(0ul, InstResult::ResultType::Scalar), idx);
copyResult(inst, InstResult((RegVal)0), 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++) {
checker_val = result.front();
result.pop();
inst_val = inst->popResult(
InstResult(0ul, InstResult::ResultType::Scalar));
inst_val = inst->popResult(InstResult((RegVal)0));
if (checker_val != inst_val) {
result_mismatch = true;
idx = i;

View File

@@ -39,8 +39,9 @@
#define __CPU_INST_RES_HH__
#include <type_traits>
#include <variant>
#include "arch/generic/vec_reg.hh"
#include "arch/vecregs.hh"
#include "base/types.hh"
namespace gem5
@@ -48,81 +49,26 @@ namespace gem5
class InstResult
{
public:
union MultiResult
{
RegVal integer;
TheISA::VecRegContainer vector;
TheISA::VecPredRegContainer pred;
MultiResult() {}
};
enum class ResultType
{
Scalar,
VecReg,
VecPredReg,
NumResultTypes,
Invalid
};
private:
MultiResult result;
ResultType type;
std::variant<RegVal, TheISA::VecRegContainer,
TheISA::VecPredRegContainer> result;
public:
/** Default constructor creates an invalid result. */
InstResult() : type(ResultType::Invalid) { }
InstResult() = default;
InstResult(const InstResult &) = default;
/** Scalar result from scalar. */
template<typename T>
explicit InstResult(T i, const ResultType& t) : type(t)
{
static_assert(std::is_integral_v<T> ^ std::is_floating_point_v<T>,
"Parameter type is neither integral nor fp, or it is both");
if constexpr (std::is_integral_v<T>) {
result.integer = i;
} else if constexpr (std::is_floating_point_v<T>) {
result.integer = floatToBits(i);
}
}
/** Vector result. */
explicit InstResult(const TheISA::VecRegContainer& v, const ResultType& t)
: type(t)
{
result.vector = v;
}
/** Predicate result. */
explicit InstResult(const TheISA::VecPredRegContainer& v,
const ResultType& t)
: type(t)
{
result.pred = v;
}
InstResult&
template <typename T>
explicit InstResult(T val) : result(val) {}
template <typename T, typename enable=
std::enable_if_t<std::is_floating_point_v<T>>>
explicit InstResult(T val) : result(floatToBits(val)) {}
InstResult &
operator=(const InstResult& that)
{
type = that.type;
switch (type) {
// Given that misc regs are not written to, there may be invalids in
//the result stack.
case ResultType::Invalid:
break;
case ResultType::Scalar:
result.integer = that.result.integer;
break;
case ResultType::VecReg:
result.vector = that.result.vector;
break;
case ResultType::VecPredReg:
result.pred = that.result.pred;
break;
default:
panic("Assigning result from unknown result type");
break;
}
result = that.result;
return *this;
}
@@ -133,20 +79,7 @@ class InstResult
bool
operator==(const InstResult& that) const
{
if (this->type != that.type)
return false;
switch (type) {
case ResultType::Scalar:
return result.integer == that.result.integer;
case ResultType::VecReg:
return result.vector == that.result.vector;
case ResultType::VecPredReg:
return result.pred == that.result.pred;
case ResultType::Invalid:
return false;
default:
panic("Unknown type of result: %d\n", (int)type);
}
return result == that.result;
}
bool
@@ -158,45 +91,59 @@ class InstResult
/** Checks */
/** @{ */
/** Is this a scalar result?. */
bool isScalar() const { return type == ResultType::Scalar; }
bool
isScalar() const
{
return std::holds_alternative<RegVal>(result);
}
/** Is this a vector result?. */
bool isVector() const { return type == ResultType::VecReg; }
bool
isVector() const
{
return std::holds_alternative<TheISA::VecRegContainer>(result);
}
/** Is this a predicate result?. */
bool isPred() const { return type == ResultType::VecPredReg; }
bool
isPred() const
{
return std::holds_alternative<TheISA::VecPredRegContainer>(result);
}
/** Is this a valid result?. */
bool isValid() const { return type != ResultType::Invalid; }
bool isValid() const { return result.index() != 0; }
/** @} */
/** Explicit cast-like operations. */
/** @{ */
const uint64_t&
RegVal
asInteger() const
{
assert(isScalar());
return result.integer;
return std::get<RegVal>(result);
}
/** Cast to integer without checking type.
* This is required to have the o3 cpu checker happy, as it
* compares results as integers without being fully aware of
* their nature. */
const uint64_t&
RegVal
asIntegerNoAssert() const
{
return result.integer;
const RegVal *ptr = std::get_if<RegVal>(&result);
return ptr ? *ptr : 0;
}
const TheISA::VecRegContainer&
asVector() const
{
panic_if(!isVector(), "Converting scalar (or invalid) to vector!!");
return result.vector;
return std::get<TheISA::VecRegContainer>(result);
}
const TheISA::VecPredRegContainer&
asPred() const
{
panic_if(!isPred(), "Converting scalar (or invalid) to predicate!!");
return result.pred;
return std::get<TheISA::VecPredRegContainer>(result);
}
/** @} */

View File

@@ -777,8 +777,7 @@ class DynInst : public ExecContext, public RefCounted
setScalarResult(T &&t)
{
if (instFlags[RecordResult]) {
instResult.push(InstResult(std::forward<T>(t),
InstResult::ResultType::Scalar));
instResult.push(InstResult(std::forward<T>(t)));
}
}
@@ -788,8 +787,7 @@ class DynInst : public ExecContext, public RefCounted
setVecResult(T &&t)
{
if (instFlags[RecordResult]) {
instResult.push(InstResult(std::forward<T>(t),
InstResult::ResultType::VecReg));
instResult.push(InstResult(std::forward<T>(t)));
}
}
@@ -799,8 +797,7 @@ class DynInst : public ExecContext, public RefCounted
setVecPredResult(T &&t)
{
if (instFlags[RecordResult]) {
instResult.push(InstResult(std::forward<T>(t),
InstResult::ResultType::VecPredReg));
instResult.push(InstResult(std::forward<T>(t)));
}
}
/** @} */