From 526f5271d8f555020f0cf33555b4d82afde851e8 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 9 Aug 2021 02:09:53 -0700 Subject: [PATCH] cpu: Switch std::variant out for std::any in IntResult. This avoids having to explicitly list the types that the result can hold, avoiding having to specify what the vector types are. Also, the variant type always has enough space for the result no matter what type it is. For the "any" type, implementations are encouraged to not dynamically allocate storage for small values (and RegVal == uint64_t probably qualifies). This means that for the common case, RegVal, the amount of storage will be smaller, and only when we actually need space to store a VecRegContainer, etc, will that actually be allocated. Change-Id: I43bf8d1866b1538db7d91cd9f1e635df642dd2c9 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/49130 Maintainer: Gabe Black Reviewed-by: Yu-hsin Wang Tested-by: kokoro --- src/cpu/inst_res.hh | 81 +++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 21 deletions(-) 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); } /** @} */