diff --git a/src/cpu/inst_res.hh b/src/cpu/inst_res.hh index 19ce640e64..c9507ba2ef 100644 --- a/src/cpu/inst_res.hh +++ b/src/cpu/inst_res.hh @@ -38,10 +38,11 @@ #ifndef __CPU_INST_RES_HH__ #define __CPU_INST_RES_HH__ +#include #include -#include #include "arch/vecregs.hh" +#include "base/logging.hh" #include "base/types.hh" namespace gem5 @@ -50,25 +51,61 @@ namespace gem5 class InstResult { private: - std::variant result; + std::any result; + std::function equals; public: /** Default constructor creates an invalid result. */ - InstResult() = default; + InstResult() : + // This InstResult is empty, and will only equal other InstResults + // which are also empty. + equals([](const std::any &a, const std::any &b) -> bool { + gem5_assert(!a.has_value()); + return !b.has_value(); + }) + {} InstResult(const InstResult &) = default; template - explicit InstResult(T val) : result(val) {} + explicit InstResult(T val) : result(val), - template >> - explicit InstResult(T val) : result(floatToBits(val)) {} + // Set equals so it knows how to compare results of type T. + equals([](const std::any &a, const std::any &b) -> bool { + // If one has a value but the other doesn't, not equal. + if (a.has_value() != b.has_value()) + return false; + // If they are both empty, equal. + if (!a.has_value()) + return true; + // At least the local object should be of the right type. + gem5_assert(a.type() == typeid(T)); + // If these aren't the same type, not equal. + if (a.type() != b.type()) + return false; + // We now know these both hold a result of the right type. + return std::any_cast(a) == std::any_cast(b); + }) + { + static_assert(!std::is_pointer_v, + "InstResult shouldn't point to external data."); + } + + // Convert floating point values to integers. + template , int> = 0> + explicit InstResult(T val) : InstResult(floatToBits(val)) {} + + // Convert all integer types to RegVal. + template && !std::is_same_v, + int> = 0> + explicit InstResult(T val) : InstResult(static_cast(val)) {} InstResult & operator=(const InstResult& that) { result = that.result; + equals = that.equals; return *this; } @@ -79,7 +116,7 @@ class InstResult bool operator==(const InstResult& that) const { - return result == that.result; + return equals(result, that.result); } bool @@ -94,23 +131,23 @@ class InstResult bool isScalar() const { - return std::holds_alternative(result); + return result.type() == typeid(RegVal); } /** Is this a vector result?. */ bool isVector() const { - return std::holds_alternative(result); + return result.type() == typeid(TheISA::VecRegContainer); } /** Is this a predicate result?. */ bool isPred() const { - return std::holds_alternative(result); + return result.type() == typeid(TheISA::VecPredRegContainer); } /** Is this a valid result?. */ - bool isValid() const { return result.index() != 0; } + bool isValid() const { return result.has_value(); } /** @} */ /** Explicit cast-like operations. */ @@ -118,8 +155,8 @@ class InstResult RegVal asInteger() const { - assert(isScalar()); - return std::get(result); + panic_if(!isScalar(), "Converting non-scalar to scalar!!"); + return std::any_cast(result); } /** Cast to integer without checking type. @@ -129,21 +166,23 @@ class InstResult RegVal asIntegerNoAssert() const { - const RegVal *ptr = std::get_if(&result); - return ptr ? *ptr : 0; + if (!isScalar()) + return 0; + return std::any_cast(result); } - const TheISA::VecRegContainer& + + TheISA::VecRegContainer asVector() const { panic_if(!isVector(), "Converting scalar (or invalid) to vector!!"); - return std::get(result); + return std::any_cast(result); } - const TheISA::VecPredRegContainer& + TheISA::VecPredRegContainer asPred() const { panic_if(!isPred(), "Converting scalar (or invalid) to predicate!!"); - return std::get(result); + return std::any_cast(result); } /** @} */