Retrieve Variable type through an abstract method

This is just a refactoring which avoids storing the type as a Variable
fields, since the 'LValue<T>' subclass knows the type statically and we
only need it during materialization.

This gives us a vtable for overloading other methods in subsequent
changes, at no additional storage cost for Variable.

Bug: b/155302798
Change-Id: I36f6ef8f5f4d2b50ba04d539dc8b9735481c816a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44668
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index e76e653..d254aea 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -637,7 +637,7 @@
 	jit = new JITBuilder(Nucleus::getDefaultConfig());
 
 	ASSERT(Variable::unmaterializedVariables == nullptr);
-	Variable::unmaterializedVariables = new std::unordered_set<Variable *>();
+	Variable::unmaterializedVariables = new std::unordered_set<const Variable *>();
 }
 
 Nucleus::~Nucleus()
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index de85b03..5922a58 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -64,11 +64,10 @@
 }
 
 // Set of variables that do not have a stack location yet.
-thread_local std::unordered_set<Variable *> *Variable::unmaterializedVariables = nullptr;
+thread_local std::unordered_set<const Variable *> *Variable::unmaterializedVariables = nullptr;
 
-Variable::Variable(Type *type, int arraySize)
+Variable::Variable(int arraySize)
     : arraySize(arraySize)
-    , type(type)
 {
 #if REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION
 	materialize();
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index f9b986d..552e128 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -102,7 +102,6 @@
 class Variable
 {
 	friend class Nucleus;
-	friend class PrintValue;
 
 	Variable() = delete;
 	Variable &operator=(const Variable &) = delete;
@@ -116,13 +115,14 @@
 	Value *getBaseAddress() const;
 	Value *getElementPointer(Value *index, bool unsignedIndex) const;
 
+	virtual Type *getType() const = 0;
+	int getArraySize() const { return arraySize; }
+
 protected:
-	Variable(Type *type, int arraySize);
+	Variable(int arraySize);
 	Variable(const Variable &) = default;
 
-	~Variable();
-
-	const int arraySize;
+	virtual ~Variable();
 
 private:
 	static void materializeAll();
@@ -130,9 +130,9 @@
 
 	// This has to be a raw pointer because glibc 2.17 doesn't support __cxa_thread_atexit_impl
 	// for destructing objects at exit. See crbug.com/1074222
-	static thread_local std::unordered_set<Variable *> *unmaterializedVariables;
+	static thread_local std::unordered_set<const Variable *> *unmaterializedVariables;
 
-	Type *const type;
+	const int arraySize;
 	mutable Value *rvalue = nullptr;
 	mutable Value *address = nullptr;
 };
@@ -145,6 +145,11 @@
 
 	RValue<Pointer<T>> operator&();
 
+	Type *getType() const override
+	{
+		return T::type();
+	}
+
 	// self() returns the this pointer to this LValue<T> object.
 	// This function exists because operator&() is overloaded.
 	inline LValue<T> *self() { return this; }
@@ -240,6 +245,7 @@
 	RValue(typename FloatLiteral<T>::type f);
 	RValue(const Reference<T> &rhs);
 
+	// Rvalues cannot be assigned to: "(a + b) = c;"
 	RValue<T> &operator=(const RValue<T> &) = delete;
 
 	Value *value;  // FIXME: Make private
@@ -2592,7 +2598,7 @@
 
 template<class T>
 LValue<T>::LValue(int arraySize)
-    : Variable(T::type(), arraySize)
+    : Variable(arraySize)
 {
 #ifdef ENABLE_RR_DEBUG_INFO
 	materialize();
@@ -2603,7 +2609,7 @@
 {
 	if(!address)
 	{
-		address = Nucleus::allocateStackVariable(type, arraySize);
+		address = Nucleus::allocateStackVariable(getType(), arraySize);
 		RR_DEBUG_INFO_EMIT_VAR(address);
 
 		if(rvalue)
@@ -2627,14 +2633,14 @@
 		materialize();
 	}
 
-	return Nucleus::createLoad(address, type, false, 0);
+	return Nucleus::createLoad(address, getType(), false, 0);
 }
 
 inline Value *Variable::storeValue(Value *value) const
 {
 	if(address)
 	{
-		return Nucleus::createStore(value, address, type, false, 0);
+		return Nucleus::createStore(value, address, getType(), false, 0);
 	}
 
 	rvalue = value;
@@ -2651,7 +2657,7 @@
 
 inline Value *Variable::getElementPointer(Value *index, bool unsignedIndex) const
 {
-	return Nucleus::createGEP(getBaseAddress(), type, index, unsignedIndex);
+	return Nucleus::createGEP(getBaseAddress(), getType(), index, unsignedIndex);
 }
 
 template<class T>
@@ -3060,7 +3066,7 @@
 template<class T, int S>
 Reference<T> Array<T, S>::operator[](int index)
 {
-	assert(index < Variable::arraySize);
+	assert(index < Variable::getArraySize());
 	Value *element = LValue<T>::getElementPointer(Nucleus::createConstantInt(index), false);
 
 	return Reference<T>(element);
@@ -3069,7 +3075,7 @@
 template<class T, int S>
 Reference<T> Array<T, S>::operator[](unsigned int index)
 {
-	assert(index < static_cast<unsigned int>(Variable::arraySize));
+	assert(index < static_cast<unsigned int>(Variable::getArraySize()));
 	Value *element = LValue<T>::getElementPointer(Nucleus::createConstantInt(index), true);
 
 	return Reference<T>(element);
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 16ff015..67026e5 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -903,7 +903,7 @@
 	}
 
 	ASSERT(Variable::unmaterializedVariables == nullptr);
-	Variable::unmaterializedVariables = new std::unordered_set<Variable *>();
+	Variable::unmaterializedVariables = new std::unordered_set<const Variable *>();
 }
 
 Nucleus::~Nucleus()