Eliminate the array size from rr::Variable

We only need to know the array size during materialization of Array<>
types, so store it only for that class and make the allocation a
virtual method.

This change removes the REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION
option, since it requires knowing the full size of Variable at
construction, which would require Array<> to still pass that into the
Variable constructor. If we need an debugging feature like this again,
we could also materialize variables on first use instead of at
construction.

Bug: b/155302798
Change-Id: I65b02c1258643dcbd3ae18f3f097cb815efa0830
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/45148
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index 2ddeaa3..cedbe96 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -20,12 +20,6 @@
 #include <algorithm>
 #include <cmath>
 
-// Define REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION to non-zero to ensure all
-// variables have a stack location obtained throuch alloca().
-#ifndef REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION
-#	define REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION 0
-#endif
-
 namespace rr {
 
 const Config::Edit Config::Edit::None = {};
@@ -66,14 +60,9 @@
 // Set of variables that do not have a stack location yet.
 thread_local std::unordered_set<const Variable *> *Variable::unmaterializedVariables = nullptr;
 
-Variable::Variable(int arraySize)
-    : arraySize(arraySize)
+Variable::Variable()
 {
-#if REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION
-	materialize();
-#else
 	unmaterializedVariables->emplace(this);
-#endif
 }
 
 Variable::~Variable()
@@ -81,6 +70,11 @@
 	unmaterializedVariables->erase(this);
 }
 
+Value *Variable::allocate() const
+{
+	return Nucleus::allocateStackVariable(getType());
+}
+
 void Variable::materializeAll()
 {
 	for(auto *var : *unmaterializedVariables)
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 92cfdf0..95dae47 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -103,7 +103,6 @@
 {
 	friend class Nucleus;
 
-	Variable() = delete;
 	Variable &operator=(const Variable &) = delete;
 
 public:
@@ -116,10 +115,9 @@
 	Value *getElementPointer(Value *index, bool unsignedIndex) const;
 
 	virtual Type *getType() const = 0;
-	int getArraySize() const { return arraySize; }
 
 protected:
-	Variable(int arraySize);
+	Variable();
 	Variable(const Variable &) = default;
 
 	virtual ~Variable();
@@ -128,11 +126,12 @@
 	static void materializeAll();
 	static void killUnmaterialized();
 
+	virtual Value *allocate() const;
+
 	// 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<const Variable *> *unmaterializedVariables;
 
-	const int arraySize;
 	mutable Value *rvalue = nullptr;
 	mutable Value *address = nullptr;
 };
@@ -141,7 +140,7 @@
 class LValue : public Variable
 {
 public:
-	LValue(int arraySize = 0);
+	LValue();
 
 	RValue<Pointer<T>> operator&();
 
@@ -2511,6 +2510,11 @@
 	// self() returns the this pointer to this Array object.
 	// This function exists because operator&() is overloaded by LValue<T>.
 	inline Array *self() { return this; }
+
+private:
+	Value *allocate() const override;
+
+	const int arraySize;
 };
 
 //	RValue<Array<T>> operator++(Array<T> &val, int);   // Post-increment
@@ -2617,8 +2621,7 @@
 namespace rr {
 
 template<class T>
-LValue<T>::LValue(int arraySize)
-    : Variable(arraySize)
+LValue<T>::LValue()
 {
 #ifdef ENABLE_RR_DEBUG_INFO
 	materialize();
@@ -2629,7 +2632,7 @@
 {
 	if(!address)
 	{
-		address = Nucleus::allocateStackVariable(getType(), arraySize);
+		address = allocate();
 		RR_DEBUG_INFO_EMIT_VAR(address);
 
 		if(rvalue)
@@ -3084,14 +3087,20 @@
 
 template<class T, int S>
 Array<T, S>::Array(int size)
-    : LValue<T>(size)
+    : arraySize(size)
 {
 }
 
 template<class T, int S>
+Value *Array<T, S>::allocate() const
+{
+	return Nucleus::allocateStackVariable(T::type(), arraySize);
+}
+
+template<class T, int S>
 Reference<T> Array<T, S>::operator[](int index)
 {
-	assert(index < Variable::getArraySize());
+	assert(index < arraySize);
 	Value *element = LValue<T>::getElementPointer(Nucleus::createConstantInt(index), false);
 
 	return Reference<T>(element);
@@ -3100,7 +3109,7 @@
 template<class T, int S>
 Reference<T> Array<T, S>::operator[](unsigned int index)
 {
-	assert(index < static_cast<unsigned int>(Variable::getArraySize()));
+	assert(index < static_cast<unsigned int>(arraySize));
 	Value *element = LValue<T>::getElementPointer(Nucleus::createConstantInt(index), true);
 
 	return Reference<T>(element);