Reactor: Add Traits for Reference types

ReactorType<Reference<T>> will now resolve to T.

This also enables support of ValueOf(ReactorType<Reference<T>>).
Required for Coroutines.

Bug: b/131672705
Change-Id: Icbc95488f5299b8d70e72142e44af9ed1af598d1
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30569
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index d201904..c151ffa 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -161,6 +161,8 @@
 	class Reference
 	{
 	public:
+		using reference_underlying_type = T;
+
 		explicit Reference(Value *pointer, int alignment = 1);
 
 		RValue<T> operator=(RValue<T> rhs) const;
@@ -2402,7 +2404,8 @@
 
 	void branch(RValue<Bool> cmp, BasicBlock *bodyBB, BasicBlock *endBB);
 
-	// ValueOf returns a rr::Value* for the given C-type, RValue<T>, or LValue<T>.
+	// ValueOf returns a rr::Value* for the given C-type, RValue<T>, LValue<T>
+	// or Reference<T>.
 	template <typename T>
 	inline Value* ValueOf(const T &v)
 	{
diff --git a/src/Reactor/ReactorUnitTests.cpp b/src/Reactor/ReactorUnitTests.cpp
index 81c3700..d54aa6d 100644
--- a/src/Reactor/ReactorUnitTests.cpp
+++ b/src/Reactor/ReactorUnitTests.cpp
@@ -1434,6 +1434,17 @@
 static_assert(IsLValue<UInt>::value, "");
 static_assert(IsLValue<Float>::value, "");
 
+// Assert IsReference<> resolves true for Reference types.
+static_assert(IsReference<Reference<Bool>>::value, "");
+static_assert(IsReference<Reference<Byte>>::value, "");
+static_assert(IsReference<Reference<SByte>>::value, "");
+static_assert(IsReference<Reference<Short>>::value, "");
+static_assert(IsReference<Reference<UShort>>::value, "");
+static_assert(IsReference<Reference<Int>>::value, "");
+static_assert(IsReference<Reference<Long>>::value, "");
+static_assert(IsReference<Reference<UInt>>::value, "");
+static_assert(IsReference<Reference<Float>>::value, "");
+
 // Assert IsRValue<> resolves false for LValue types.
 static_assert(!IsRValue<Void>::value, "");
 static_assert(!IsRValue<Bool>::value, "");
@@ -1446,6 +1457,18 @@
 static_assert(!IsRValue<UInt>::value, "");
 static_assert(!IsRValue<Float>::value, "");
 
+// Assert IsRValue<> resolves false for Reference types.
+static_assert(!IsRValue<Reference<Void>>::value, "");
+static_assert(!IsRValue<Reference<Bool>>::value, "");
+static_assert(!IsRValue<Reference<Byte>>::value, "");
+static_assert(!IsRValue<Reference<SByte>>::value, "");
+static_assert(!IsRValue<Reference<Short>>::value, "");
+static_assert(!IsRValue<Reference<UShort>>::value, "");
+static_assert(!IsRValue<Reference<Int>>::value, "");
+static_assert(!IsRValue<Reference<Long>>::value, "");
+static_assert(!IsRValue<Reference<UInt>>::value, "");
+static_assert(!IsRValue<Reference<Float>>::value, "");
+
 // Assert IsRValue<> resolves false for C types.
 static_assert(!IsRValue<void>::value, "");
 static_assert(!IsRValue<bool>::value, "");
@@ -1473,6 +1496,18 @@
 // Assert IsLValue<> resolves false for Void type.
 static_assert(!IsLValue<Void>::value, "");
 
+// Assert IsLValue<> resolves false for Reference<> types.
+static_assert(!IsLValue<Reference<Void>>::value, "");
+static_assert(!IsLValue<Reference<Bool>>::value, "");
+static_assert(!IsLValue<Reference<Byte>>::value, "");
+static_assert(!IsLValue<Reference<SByte>>::value, "");
+static_assert(!IsLValue<Reference<Short>>::value, "");
+static_assert(!IsLValue<Reference<UShort>>::value, "");
+static_assert(!IsLValue<Reference<Int>>::value, "");
+static_assert(!IsLValue<Reference<Long>>::value, "");
+static_assert(!IsLValue<Reference<UInt>>::value, "");
+static_assert(!IsLValue<Reference<Float>>::value, "");
+
 // Assert IsLValue<> resolves false for C types.
 static_assert(!IsLValue<void>::value, "");
 static_assert(!IsLValue<bool>::value, "");
@@ -1509,6 +1544,17 @@
 static_assert(IsDefined<UInt>::value, "");
 static_assert(IsDefined<Float>::value, "");
 
+// Assert IsDefined<> resolves true for Reference<> types.
+static_assert(IsDefined<Reference<Bool>>::value, "");
+static_assert(IsDefined<Reference<Byte>>::value, "");
+static_assert(IsDefined<Reference<SByte>>::value, "");
+static_assert(IsDefined<Reference<Short>>::value, "");
+static_assert(IsDefined<Reference<UShort>>::value, "");
+static_assert(IsDefined<Reference<Int>>::value, "");
+static_assert(IsDefined<Reference<Long>>::value, "");
+static_assert(IsDefined<Reference<UInt>>::value, "");
+static_assert(IsDefined<Reference<Float>>::value, "");
+
 // Assert IsDefined<> resolves true for C types.
 static_assert(IsDefined<void>::value, "");
 static_assert(IsDefined<bool>::value, "");
diff --git a/src/Reactor/Traits.hpp b/src/Reactor/Traits.hpp
index ce6ac34..840d198 100644
--- a/src/Reactor/Traits.hpp
+++ b/src/Reactor/Traits.hpp
@@ -121,6 +121,10 @@
 	// IsLValue::value is true if T is of, or derives from type LValue<T>.
 	template <typename T> struct IsLValue { static constexpr bool value = std::is_base_of<LValue<T>, T>::value; };
 
+	// IsReference::value is true if T is of type Reference<X>, where X is any type.
+	template <typename T, typename Enable = void> struct IsReference { static constexpr bool value = false; };
+	template <typename T> struct IsReference<T, typename std::enable_if<IsDefined<typename T::reference_underlying_type>::value>::type> { static constexpr bool value = true; };
+
 	// ReactorType<T> returns the LValue Reactor type for T.
 	// T can be a C-type, RValue or LValue.
 	template<typename T, typename ENABLE = void> struct ReactorTypeT;
@@ -128,6 +132,8 @@
 	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsDefined<CToReactor<T>>::value>::type> { using type = CToReactor<T>; };
 	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsRValue<T>::value>::type> { using type = typename T::rvalue_underlying_type; };
 	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsLValue<T>::value>::type> { using type = T; };
+	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsReference<T>::value>::type> { using type = T; };
+
 
 	// Reactor types that can be used as a return type for a function.
 	template <typename T> struct CanBeUsedAsReturn { static constexpr bool value = false; };