Reactor: Move print apis out of core reactor header.

This is considered non-core functionality.

Fixes: b/144686205
Change-Id: I41b811d70db9c07d26a3e6cb2f8c36a2a9e34296
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38450
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab7064b..ae486e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1538,16 +1538,17 @@
     )
 
     set(SUBZERO_REACTOR_LIST
-        ${SOURCE_DIR}/Reactor/Reactor.cpp
-        ${SOURCE_DIR}/Reactor/Reactor.hpp
-        ${SOURCE_DIR}/Reactor/SubzeroReactor.cpp
-        ${SOURCE_DIR}/Reactor/Optimizer.cpp
-        ${SOURCE_DIR}/Reactor/Nucleus.hpp
-        ${SOURCE_DIR}/Reactor/Routine.hpp
         ${SOURCE_DIR}/Reactor/Debug.cpp
         ${SOURCE_DIR}/Reactor/Debug.hpp
         ${SOURCE_DIR}/Reactor/ExecutableMemory.cpp
         ${SOURCE_DIR}/Reactor/ExecutableMemory.hpp
+        ${SOURCE_DIR}/Reactor/Nucleus.hpp
+        ${SOURCE_DIR}/Reactor/Optimizer.cpp
+        ${SOURCE_DIR}/Reactor/Print.hpp
+        ${SOURCE_DIR}/Reactor/Reactor.cpp
+        ${SOURCE_DIR}/Reactor/Reactor.hpp
+        ${SOURCE_DIR}/Reactor/Routine.hpp
+        ${SOURCE_DIR}/Reactor/SubzeroReactor.cpp
     )
 
     set(SUBZERO_INCLUDE_DIR
@@ -1670,20 +1671,21 @@
 endif(REACTOR_EMIT_DEBUG_INFO)
 
 set(REACTOR_LLVM_LIST
-    ${SOURCE_DIR}/Reactor/Reactor.cpp
-    ${SOURCE_DIR}/Reactor/Reactor.hpp
-    ${SOURCE_DIR}/Reactor/LLVMReactor.cpp
-    ${SOURCE_DIR}/Reactor/LLVMReactor.hpp
-    ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.cpp
-    ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.hpp
-    ${SOURCE_DIR}/Reactor/Nucleus.hpp
-    ${SOURCE_DIR}/Reactor/Routine.hpp
     ${SOURCE_DIR}/Reactor/CPUID.cpp
     ${SOURCE_DIR}/Reactor/CPUID.hpp
     ${SOURCE_DIR}/Reactor/Debug.cpp
     ${SOURCE_DIR}/Reactor/Debug.hpp
     ${SOURCE_DIR}/Reactor/ExecutableMemory.cpp
     ${SOURCE_DIR}/Reactor/ExecutableMemory.hpp
+    ${SOURCE_DIR}/Reactor/LLVMReactor.cpp
+    ${SOURCE_DIR}/Reactor/LLVMReactor.hpp
+    ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.cpp
+    ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.hpp
+    ${SOURCE_DIR}/Reactor/Nucleus.hpp
+    ${SOURCE_DIR}/Reactor/Print.hpp
+    ${SOURCE_DIR}/Reactor/Reactor.cpp
+    ${SOURCE_DIR}/Reactor/Reactor.hpp
+    ${SOURCE_DIR}/Reactor/Routine.hpp
 )
 
 file(GLOB_RECURSE EGL_LIST
diff --git a/src/Pipeline/SamplerCore.hpp b/src/Pipeline/SamplerCore.hpp
index b733710..e5ab898 100644
--- a/src/Pipeline/SamplerCore.hpp
+++ b/src/Pipeline/SamplerCore.hpp
@@ -17,6 +17,7 @@
 
 #include "ShaderCore.hpp"
 #include "Device/Sampler.hpp"
+#include "Reactor/Print.hpp"
 #include "Reactor/Reactor.hpp"
 
 #ifdef None
diff --git a/src/Pipeline/ShaderCore.hpp b/src/Pipeline/ShaderCore.hpp
index fd51000..aa707d5 100644
--- a/src/Pipeline/ShaderCore.hpp
+++ b/src/Pipeline/ShaderCore.hpp
@@ -15,6 +15,7 @@
 #ifndef sw_ShaderCore_hpp
 #define sw_ShaderCore_hpp
 
+#include "Reactor/Print.hpp"
 #include "Reactor/Reactor.hpp"
 #include "Vulkan/VkDebug.hpp"
 
diff --git a/src/Reactor/Print.hpp b/src/Reactor/Print.hpp
new file mode 100644
index 0000000..252e621
--- /dev/null
+++ b/src/Reactor/Print.hpp
@@ -0,0 +1,371 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef rr_Print_hpp
+#define rr_Print_hpp
+
+#if !defined(NDEBUG)
+#define ENABLE_RR_PRINT 1 // Enables RR_PRINT(), RR_WATCH()
+#endif // !defined(NDEBUG)
+
+#ifdef ENABLE_RR_PRINT
+
+#include "Reactor.hpp"
+
+#include <string>
+#include <vector>
+
+namespace rr {
+
+	// PrintValue holds the printf format and value(s) for a single argument
+	// to Print(). A single argument can be expanded into multiple printf
+	// values - for example a Float4 will expand to "%f %f %f %f" and four
+	// scalar values.
+	// The PrintValue constructor accepts the following:
+	//   * Reactor LValues, RValues, Pointers.
+	//   * Standard Plain-Old-Value types (int, float, bool, etc)
+	//   * Custom types that specialize the PrintValue::Ty template struct.
+	//   * Static arrays in the form T[N] where T can be any of the above.
+	class PrintValue
+	{
+		// Ty is a template that can be specialized for printing type T.
+		// Each specialization must expose:
+		//  * A 'static std::string fmt(const T& v)' method that provides the
+		//    printf format specifier.
+		//  * A 'static std::vector<rr::Value*> val(const T& v)' method that
+		//    returns all the printf format values.
+		template <typename T> struct Ty
+		{
+			// static std::string fmt(const T& v);
+			// static std::vector<rr::Value*> val(const T& v);
+		};
+
+		// returns the printf values for all the values in the given array.
+		template <typename T>
+		static std::vector<Value*> val(const T* list, int count) {
+			std::vector<Value*> values;
+			values.reserve(count);
+			for (int i = 0; i < count; i++)
+			{
+				auto v = val(list[i]);
+				values.insert(values.end(), v.begin(), v.end());
+			}
+			return values;
+		}
+
+		// fmt returns the comma-delimited list of printf format strings for
+		// every element in the provided list, all enclosed in square brackets.
+		template <typename T>
+		static std::string fmt(const T* list, int count)
+		{
+			std::string out = "[";
+			for (int i = 0; i < count; i++)
+			{
+				if (i > 0) { out += ", "; }
+				out += fmt(list[i]);
+			}
+			return out + "]";
+		}
+
+		static std::string addr(const void* ptr)
+		{
+			char buf[32];
+			snprintf(buf, sizeof(buf), "%p", ptr);
+			return buf;
+		}
+
+	public:
+		const std::string format;
+		const std::vector<Value*> values;
+
+		// Constructs a PrintValue for the given value.
+		template <typename T>
+		PrintValue(const T& v) : format(fmt(v)), values(val(v)) {}
+
+		// Constructs a PrintValue for the given static array.
+		template <typename T, int N>
+		PrintValue(const T (&v)[N]) : format(fmt(&v[0], N)), values(val(&v[0], N)) {}
+
+		// Constructs a PrintValue for the given array starting at arr of length
+		// len.
+		template <typename T>
+		PrintValue(const T* arr, int len) : format(fmt(arr, len)), values(val(arr, len)) {}
+
+		// PrintValue constructors for plain-old-data values.
+		PrintValue(bool v) : format(v ? "true" : "false") {}
+		PrintValue(int8_t v) : format(std::to_string(v)) {}
+		PrintValue(uint8_t v) : format(std::to_string(v)) {}
+		PrintValue(int16_t v) : format(std::to_string(v)) {}
+		PrintValue(uint16_t v) : format(std::to_string(v)) {}
+		PrintValue(int32_t v) : format(std::to_string(v)) {}
+		PrintValue(uint32_t v) : format(std::to_string(v)) {}
+		PrintValue(int64_t v) : format(std::to_string(v)) {}
+		PrintValue(uint64_t v) : format(std::to_string(v)) {}
+		PrintValue(float v) : format(std::to_string(v)) {}
+		PrintValue(double v) : format(std::to_string(v)) {}
+
+		template <typename T>
+		PrintValue(const T* v) : format(addr(v)) {}
+
+		// vals is a helper to build composite value lists.
+		// vals returns the full, sequential list of printf argument values used
+		// to print all the provided variadic values.
+		// vals() is intended to be used by implementations of
+		// PrintValue::Ty<>::vals() to help declare aggregate types.
+		// For example, if you were declaring a PrintValue::Ty<> specialization
+		// for a custom Mat4x4 matrix formed from four Vector4 values, you'd
+		// write:
+		//
+		// namespace rr
+		// {
+		//		template <> struct PrintValue::Ty<Mat4x4>
+		//		{
+		//			static std::string fmt(const Mat4x4& v)
+		//			{
+		//				return	"[a: <%f, %f, %f, %f>,"
+		//				        " b: <%f, %f, %f, %f>,"
+		//				        " c: <%f, %f, %f, %f>,"
+		//				        " d: <%f, %f, %f, %f>]";
+		//			}
+		//			static std::vector<rr::Value*> val(const Mat4x4& v)
+		//			{
+		//				return PrintValue::vals(v.a, v.b, v.c, v.d);
+		//			}
+		//		};
+		//	}
+		template<typename ... ARGS>
+		static std::vector<Value*> vals(ARGS... v)
+		{
+			std::vector< std::vector<Value*> > lists = {val(v)...};
+			std::vector<Value*> joined;
+			for (const auto& list : lists)
+			{
+				joined.insert(joined.end(), list.begin(), list.end());
+			}
+			return joined;
+		}
+
+		// returns the printf format specifier for the given type via the
+		// PrintValue::Ty<T> specialization.
+		template <typename T>
+		static std::string fmt(const T& v) { return Ty<T>::fmt(v); }
+
+		// returns the printf value for the given type with a
+		// PrintValue::Ty<T> specialization.
+		template <typename T>
+		static std::vector<Value*> val(const T& v) { return Ty<T>::val(v); }
+	};
+
+	// PrintValue::Ty<T> specializations for basic types.
+	template <> struct PrintValue::Ty<const char*>
+	{
+		static std::string fmt(const char* v) { return "%s"; }
+		static std::vector<Value*> val(const char* v);
+	};
+	template <> struct PrintValue::Ty<std::string>
+	{
+		static std::string fmt(const std::string& v) { return PrintValue::Ty<const char*>::fmt(v.c_str()); }
+		static std::vector<Value*> val(const std::string& v) { return PrintValue::Ty<const char*>::val(v.c_str()); }
+	};
+
+	// PrintValue::Ty<T> specializations for standard Reactor types.
+	template <> struct PrintValue::Ty<Bool>
+	{
+		static std::string fmt(const RValue<Bool>& v) { return "%d"; }
+		static std::vector<Value*> val(const RValue<Bool>& v) { return {v.value}; }
+	};
+	template <> struct PrintValue::Ty<Byte>
+	{
+		static std::string fmt(const RValue<Byte>& v) { return "%d"; }
+		static std::vector<Value*> val(const RValue<Byte>& v);
+	};
+	template <> struct PrintValue::Ty<Byte4>
+	{
+		static std::string fmt(const RValue<Byte4>& v) { return "[%d, %d, %d, %d]"; }
+		static std::vector<Value*> val(const RValue<Byte4>& v);
+	};
+	template <> struct PrintValue::Ty<Int>
+	{
+		static std::string fmt(const RValue<Int>& v) { return "%d"; }
+		static std::vector<Value*> val(const RValue<Int>& v);
+	};
+	template <> struct PrintValue::Ty<Int2>
+	{
+		static std::string fmt(const RValue<Int>& v) { return "[%d, %d]"; }
+		static std::vector<Value*> val(const RValue<Int2>& v);
+	};
+	template <> struct PrintValue::Ty<Int4>
+	{
+		static std::string fmt(const RValue<Int4>& v) { return "[%d, %d, %d, %d]"; }
+		static std::vector<Value*> val(const RValue<Int4>& v);
+	};
+	template <> struct PrintValue::Ty<UInt>
+	{
+		static std::string fmt(const RValue<UInt>& v) { return "%u"; }
+		static std::vector<Value*> val(const RValue<UInt>& v);
+	};
+	template <> struct PrintValue::Ty<UInt2>
+	{
+		static std::string fmt(const RValue<UInt>& v) { return "[%u, %u]"; }
+		static std::vector<Value*> val(const RValue<UInt2>& v);
+	};
+	template <> struct PrintValue::Ty<UInt4>
+	{
+		static std::string fmt(const RValue<UInt4>& v) { return "[%u, %u, %u, %u]"; }
+		static std::vector<Value*> val(const RValue<UInt4>& v);
+	};
+	template <> struct PrintValue::Ty<Short>
+	{
+		static std::string fmt(const RValue<Short>& v) { return "%d"; }
+		static std::vector<Value*> val(const RValue<Short>& v);
+	};
+	template <> struct PrintValue::Ty<Short4>
+	{
+		static std::string fmt(const RValue<Short4>& v) { return "[%d, %d, %d, %d]"; }
+		static std::vector<Value*> val(const RValue<Short4>& v);
+	};
+	template <> struct PrintValue::Ty<UShort>
+	{
+		static std::string fmt(const RValue<UShort>& v) { return "%u"; }
+		static std::vector<Value*> val(const RValue<UShort>& v);
+	};
+	template <> struct PrintValue::Ty<UShort4>
+	{
+		static std::string fmt(const RValue<UShort4>& v) { return "[%u, %u, %u, %u]"; }
+		static std::vector<Value*> val(const RValue<UShort4>& v);
+	};
+	template <> struct PrintValue::Ty<Float>
+	{
+		static std::string fmt(const RValue<Float>& v) { return "[%f]"; }
+		static std::vector<Value*> val(const RValue<Float>& v);
+	};
+	template <> struct PrintValue::Ty<Float4>
+	{
+		static std::string fmt(const RValue<Float4>& v) { return "[%f, %f, %f, %f]"; }
+		static std::vector<Value*> val(const RValue<Float4>& v);
+	};
+	template <> struct PrintValue::Ty<Long>
+	{
+		static std::string fmt(const RValue<Long>& v) { return "%lld"; }
+		static std::vector<Value*> val(const RValue<Long>& v) { return {v.value}; }
+	};
+	template <typename T> struct PrintValue::Ty< Pointer<T> >
+	{
+		static std::string fmt(const RValue<Pointer<T>>& v) { return "%p"; }
+		static std::vector<Value*> val(const RValue<Pointer<T>>& v) { return {v.value}; }
+	};
+	template <typename T> struct PrintValue::Ty< Reference<T> >
+	{
+		static std::string fmt(const Reference<T>& v) { return PrintValue::Ty<T>::fmt(v); }
+		static std::vector<Value*> val(const Reference<T>& v) { return PrintValue::Ty<T>::val(v); }
+	};
+	template <typename T> struct PrintValue::Ty< RValue<T> >
+	{
+		static std::string fmt(const RValue<T>& v) { return PrintValue::Ty<T>::fmt(v); }
+		static std::vector<Value*> val(const RValue<T>& v) { return PrintValue::Ty<T>::val(v); }
+	};
+
+	// Printv emits a call to printf() using the function, file and line,
+	// message and optional values.
+	// See Printv below.
+	void Printv(const char* function, const char* file, int line, const char* msg, std::initializer_list<PrintValue> vals);
+
+	// Printv emits a call to printf() using the provided message and optional
+	// values.
+	// Printf replaces any bracketed indices in the message with string
+	// representations of the corresponding value in vals.
+	// For example:
+	//   Printv("{0} and {1}", "red", "green");
+	// Would print the string:
+	//   "red and green"
+	// Arguments can be indexed in any order.
+	// Invalid indices are not substituted.
+	inline void Printv(const char* msg, std::initializer_list<PrintValue> vals)
+	{
+		Printv(nullptr, nullptr, 0, msg, vals);
+	}
+
+	// Print is a wrapper over Printv that wraps the variadic arguments into an
+	// initializer_list before calling Printv.
+	template <typename ... ARGS>
+	void Print(const char* msg, const ARGS& ... vals) { Printv(msg, {vals...}); }
+
+	// Print is a wrapper over Printv that wraps the variadic arguments into an
+	// initializer_list before calling Printv.
+	template <typename ... ARGS>
+	void Print(const char* function, const char* file, int line, const char* msg, const ARGS& ... vals)
+	{
+		Printv(function, file, line, msg, {vals...});
+	}
+
+	// RR_LOG is a macro that calls Print(), automatically populating the
+	// function, file and line parameters and appending a newline to the string.
+	//
+	// RR_LOG() is intended to be used for debugging JIT compiled code, and is
+	// not intended for production use.
+	#if defined(_WIN32)
+		#define RR_LOG(msg, ...) Print(__FUNCSIG__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
+	#else
+		#define RR_LOG(msg, ...) Print(__PRETTY_FUNCTION__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
+	#endif
+
+	// Macro magic to perform variadic dispatch.
+	// See: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
+	// Note, this doesn't attempt to use the ##__VA_ARGS__ trick to handle 0
+	#define RR_MSVC_EXPAND_BUG(X) X // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler.
+	#define RR_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
+	#define RR_COUNT_ARGUMENTS(...) RR_MSVC_EXPAND_BUG(RR_GET_NTH_ARG(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+	static_assert(1 == RR_COUNT_ARGUMENTS(a), "RR_COUNT_ARGUMENTS broken"); // Sanity checks.
+	static_assert(2 == RR_COUNT_ARGUMENTS(a, b), "RR_COUNT_ARGUMENTS broken");
+	static_assert(3 == RR_COUNT_ARGUMENTS(a, b, c), "RR_COUNT_ARGUMENTS broken");
+
+	// RR_WATCH_FMT(...) resolves to a string literal that lists all the
+	// arguments by name. This string can be passed to LOG() to print each of
+	// the arguments with their name and value.
+	//
+	// RR_WATCH_FMT(...) uses the RR_COUNT_ARGUMENTS helper macro to delegate to a
+	// corresponding RR_WATCH_FMT_n specialization macro below.
+	#define RR_WATCH_CONCAT(a, b) a ## b
+	#define RR_WATCH_CONCAT2(a, b) RR_WATCH_CONCAT(a, b)
+	#define RR_WATCH_FMT(...) RR_MSVC_EXPAND_BUG(RR_WATCH_CONCAT2(RR_WATCH_FMT_, RR_COUNT_ARGUMENTS(__VA_ARGS__))(__VA_ARGS__))
+	#define RR_WATCH_FMT_1(_1) "\n  " #_1 ": {0}"
+	#define RR_WATCH_FMT_2(_1, _2)                                             RR_WATCH_FMT_1(_1) "\n  " #_2 ": {1}"
+	#define RR_WATCH_FMT_3(_1, _2, _3)                                         RR_WATCH_FMT_2(_1, _2) "\n  " #_3 ": {2}"
+	#define RR_WATCH_FMT_4(_1, _2, _3, _4)                                     RR_WATCH_FMT_3(_1, _2, _3) "\n  " #_4 ": {3}"
+	#define RR_WATCH_FMT_5(_1, _2, _3, _4, _5)                                 RR_WATCH_FMT_4(_1, _2, _3, _4) "\n  " #_5 ": {4}"
+	#define RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6)                             RR_WATCH_FMT_5(_1, _2, _3, _4, _5) "\n  " #_6 ": {5}"
+	#define RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7)                         RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) "\n  " #_7 ": {6}"
+	#define RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8)                     RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) "\n  " #_8 ": {7}"
+	#define RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9)                 RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) "\n  " #_9 ": {8}"
+	#define RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)           RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) "\n  " #_10 ": {9}"
+	#define RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)      RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) "\n  " #_11 ": {10}"
+	#define RR_WATCH_FMT_12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) "\n  " #_12 ": {11}"
+
+	// RR_WATCH() is a helper that prints the name and value of all the supplied
+	// arguments.
+	// For example, if you had the Int and bool variables 'foo' and 'bar' that
+	// you want to print, you can simply write:
+	//    RR_WATCH(foo, bar)
+	// When this JIT compiled code is executed, it will print the string
+	// "foo: 1, bar: true" to stdout.
+	//
+	// RR_WATCH() is intended to be used for debugging JIT compiled code, and
+	// is not intended for production use.
+	#define RR_WATCH(...) RR_LOG(RR_WATCH_FMT(__VA_ARGS__), __VA_ARGS__)
+
+}  // namespace rr
+
+#endif  // ENABLE_RR_PRINT
+
+#endif  // rr_Print_hpp
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 5997132..e4b6be0 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -23,16 +23,11 @@
 #include <cstddef>
 #include <cstdio>
 
-#include <string>
 #include <tuple>
 #include <unordered_set>
 
 #undef Bool // b/127920555
 
-#if !defined(NDEBUG)
-#define ENABLE_RR_PRINT 1 // Enables RR_PRINT(), RR_WATCH()
-#endif // !defined(NDEBUG)
-
 #ifdef ENABLE_RR_DEBUG_INFO
 	// Functions used for generating JIT debug info.
 	// See docs/ReactorDebugInfo.md for more information.
@@ -3324,344 +3319,6 @@
 	// This can be used to stop an attached debugger at the given call.
 	void Breakpoint();
 
-#ifdef ENABLE_RR_PRINT
-	// PrintValue holds the printf format and value(s) for a single argument
-	// to Print(). A single argument can be expanded into multiple printf
-	// values - for example a Float4 will expand to "%f %f %f %f" and four
-	// scalar values.
-	// The PrintValue constructor accepts the following:
-	//   * Reactor LValues, RValues, Pointers.
-	//   * Standard Plain-Old-Value types (int, float, bool, etc)
-	//   * Custom types that specialize the PrintValue::Ty template struct.
-	//   * Static arrays in the form T[N] where T can be any of the above.
-	class PrintValue
-	{
-		// Ty is a template that can be specialized for printing type T.
-		// Each specialization must expose:
-		//  * A 'static std::string fmt(const T& v)' method that provides the
-		//    printf format specifier.
-		//  * A 'static std::vector<rr::Value*> val(const T& v)' method that
-		//    returns all the printf format values.
-		template <typename T> struct Ty
-		{
-			// static std::string fmt(const T& v);
-			// static std::vector<rr::Value*> val(const T& v);
-		};
-
-		// returns the printf values for all the values in the given array.
-		template <typename T>
-		static std::vector<Value*> val(const T* list, int count) {
-			std::vector<Value*> values;
-			values.reserve(count);
-			for (int i = 0; i < count; i++)
-			{
-				auto v = val(list[i]);
-				values.insert(values.end(), v.begin(), v.end());
-			}
-			return values;
-		}
-
-		// fmt returns the comma-delimited list of printf format strings for
-		// every element in the provided list, all enclosed in square brackets.
-		template <typename T>
-		static std::string fmt(const T* list, int count)
-		{
-			std::string out = "[";
-			for (int i = 0; i < count; i++)
-			{
-				if (i > 0) { out += ", "; }
-				out += fmt(list[i]);
-			}
-			return out + "]";
-		}
-
-		static std::string addr(const void* ptr)
-		{
-			char buf[32];
-			snprintf(buf, sizeof(buf), "%p", ptr);
-			return buf;
-		}
-
-	public:
-		const std::string format;
-		const std::vector<Value*> values;
-
-		// Constructs a PrintValue for the given value.
-		template <typename T>
-		PrintValue(const T& v) : format(fmt(v)), values(val(v)) {}
-
-		// Constructs a PrintValue for the given static array.
-		template <typename T, int N>
-		PrintValue(const T (&v)[N]) : format(fmt(&v[0], N)), values(val(&v[0], N)) {}
-
-		// Constructs a PrintValue for the given array starting at arr of length
-		// len.
-		template <typename T>
-		PrintValue(const T* arr, int len) : format(fmt(arr, len)), values(val(arr, len)) {}
-
-		// PrintValue constructors for plain-old-data values.
-		PrintValue(bool v) : format(v ? "true" : "false") {}
-		PrintValue(int8_t v) : format(std::to_string(v)) {}
-		PrintValue(uint8_t v) : format(std::to_string(v)) {}
-		PrintValue(int16_t v) : format(std::to_string(v)) {}
-		PrintValue(uint16_t v) : format(std::to_string(v)) {}
-		PrintValue(int32_t v) : format(std::to_string(v)) {}
-		PrintValue(uint32_t v) : format(std::to_string(v)) {}
-		PrintValue(int64_t v) : format(std::to_string(v)) {}
-		PrintValue(uint64_t v) : format(std::to_string(v)) {}
-		PrintValue(float v) : format(std::to_string(v)) {}
-		PrintValue(double v) : format(std::to_string(v)) {}
-
-		template <typename T>
-		PrintValue(const T* v) : format(addr(v)) {}
-
-		// vals is a helper to build composite value lists.
-		// vals returns the full, sequential list of printf argument values used
-		// to print all the provided variadic values.
-		// vals() is intended to be used by implementations of
-		// PrintValue::Ty<>::vals() to help declare aggregate types.
-		// For example, if you were declaring a PrintValue::Ty<> specialization
-		// for a custom Mat4x4 matrix formed from four Vector4 values, you'd
-		// write:
-		//
-		// namespace rr
-		// {
-		//		template <> struct PrintValue::Ty<Mat4x4>
-		//		{
-		//			static std::string fmt(const Mat4x4& v)
-		//			{
-		//				return	"[a: <%f, %f, %f, %f>,"
-		//				        " b: <%f, %f, %f, %f>,"
-		//				        " c: <%f, %f, %f, %f>,"
-		//				        " d: <%f, %f, %f, %f>]";
-		//			}
-		//			static std::vector<rr::Value*> val(const Mat4x4& v)
-		//			{
-		//				return PrintValue::vals(v.a, v.b, v.c, v.d);
-		//			}
-		//		};
-		//	}
-		template<typename ... ARGS>
-		static std::vector<Value*> vals(ARGS... v)
-		{
-			std::vector< std::vector<Value*> > lists = {val(v)...};
-			std::vector<Value*> joined;
-			for (const auto& list : lists)
-			{
-				joined.insert(joined.end(), list.begin(), list.end());
-			}
-			return joined;
-		}
-
-		// returns the printf format specifier for the given type via the
-		// PrintValue::Ty<T> specialization.
-		template <typename T>
-		static std::string fmt(const T& v) { return Ty<T>::fmt(v); }
-
-		// returns the printf value for the given type with a
-		// PrintValue::Ty<T> specialization.
-		template <typename T>
-		static std::vector<Value*> val(const T& v) { return Ty<T>::val(v); }
-	};
-
-	// PrintValue::Ty<T> specializations for basic types.
-	template <> struct PrintValue::Ty<const char*>
-	{
-		static std::string fmt(const char* v) { return "%s"; }
-		static std::vector<Value*> val(const char* v);
-	};
-	template <> struct PrintValue::Ty<std::string>
-	{
-		static std::string fmt(const std::string& v) { return PrintValue::Ty<const char*>::fmt(v.c_str()); }
-		static std::vector<Value*> val(const std::string& v) { return PrintValue::Ty<const char*>::val(v.c_str()); }
-	};
-
-	// PrintValue::Ty<T> specializations for standard Reactor types.
-	template <> struct PrintValue::Ty<Bool>
-	{
-		static std::string fmt(const RValue<Bool>& v) { return "%d"; }
-		static std::vector<Value*> val(const RValue<Bool>& v) { return {v.value}; }
-	};
-	template <> struct PrintValue::Ty<Byte>
-	{
-		static std::string fmt(const RValue<Byte>& v) { return "%d"; }
-		static std::vector<Value*> val(const RValue<Byte>& v);
-	};
-	template <> struct PrintValue::Ty<Byte4>
-	{
-		static std::string fmt(const RValue<Byte4>& v) { return "[%d, %d, %d, %d]"; }
-		static std::vector<Value*> val(const RValue<Byte4>& v);
-	};
-	template <> struct PrintValue::Ty<Int>
-	{
-		static std::string fmt(const RValue<Int>& v) { return "%d"; }
-		static std::vector<Value*> val(const RValue<Int>& v);
-	};
-	template <> struct PrintValue::Ty<Int2>
-	{
-		static std::string fmt(const RValue<Int>& v) { return "[%d, %d]"; }
-		static std::vector<Value*> val(const RValue<Int2>& v);
-	};
-	template <> struct PrintValue::Ty<Int4>
-	{
-		static std::string fmt(const RValue<Int4>& v) { return "[%d, %d, %d, %d]"; }
-		static std::vector<Value*> val(const RValue<Int4>& v);
-	};
-	template <> struct PrintValue::Ty<UInt>
-	{
-		static std::string fmt(const RValue<UInt>& v) { return "%u"; }
-		static std::vector<Value*> val(const RValue<UInt>& v);
-	};
-	template <> struct PrintValue::Ty<UInt2>
-	{
-		static std::string fmt(const RValue<UInt>& v) { return "[%u, %u]"; }
-		static std::vector<Value*> val(const RValue<UInt2>& v);
-	};
-	template <> struct PrintValue::Ty<UInt4>
-	{
-		static std::string fmt(const RValue<UInt4>& v) { return "[%u, %u, %u, %u]"; }
-		static std::vector<Value*> val(const RValue<UInt4>& v);
-	};
-	template <> struct PrintValue::Ty<Short>
-	{
-		static std::string fmt(const RValue<Short>& v) { return "%d"; }
-		static std::vector<Value*> val(const RValue<Short>& v);
-	};
-	template <> struct PrintValue::Ty<Short4>
-	{
-		static std::string fmt(const RValue<Short4>& v) { return "[%d, %d, %d, %d]"; }
-		static std::vector<Value*> val(const RValue<Short4>& v);
-	};
-	template <> struct PrintValue::Ty<UShort>
-	{
-		static std::string fmt(const RValue<UShort>& v) { return "%u"; }
-		static std::vector<Value*> val(const RValue<UShort>& v);
-	};
-	template <> struct PrintValue::Ty<UShort4>
-	{
-		static std::string fmt(const RValue<UShort4>& v) { return "[%u, %u, %u, %u]"; }
-		static std::vector<Value*> val(const RValue<UShort4>& v);
-	};
-	template <> struct PrintValue::Ty<Float>
-	{
-		static std::string fmt(const RValue<Float>& v) { return "[%f]"; }
-		static std::vector<Value*> val(const RValue<Float>& v);
-	};
-	template <> struct PrintValue::Ty<Float4>
-	{
-		static std::string fmt(const RValue<Float4>& v) { return "[%f, %f, %f, %f]"; }
-		static std::vector<Value*> val(const RValue<Float4>& v);
-	};
-	template <> struct PrintValue::Ty<Long>
-	{
-		static std::string fmt(const RValue<Long>& v) { return "%lld"; }
-		static std::vector<Value*> val(const RValue<Long>& v) { return {v.value}; }
-	};
-	template <typename T> struct PrintValue::Ty< Pointer<T> >
-	{
-		static std::string fmt(const RValue<Pointer<T>>& v) { return "%p"; }
-		static std::vector<Value*> val(const RValue<Pointer<T>>& v) { return {v.value}; }
-	};
-	template <typename T> struct PrintValue::Ty< Reference<T> >
-	{
-		static std::string fmt(const Reference<T>& v) { return PrintValue::Ty<T>::fmt(v); }
-		static std::vector<Value*> val(const Reference<T>& v) { return PrintValue::Ty<T>::val(v); }
-	};
-	template <typename T> struct PrintValue::Ty< RValue<T> >
-	{
-		static std::string fmt(const RValue<T>& v) { return PrintValue::Ty<T>::fmt(v); }
-		static std::vector<Value*> val(const RValue<T>& v) { return PrintValue::Ty<T>::val(v); }
-	};
-
-	// Printv emits a call to printf() using the function, file and line,
-	// message and optional values.
-	// See Printv below.
-	void Printv(const char* function, const char* file, int line, const char* msg, std::initializer_list<PrintValue> vals);
-
-	// Printv emits a call to printf() using the provided message and optional
-	// values.
-	// Printf replaces any bracketed indices in the message with string
-	// representations of the corresponding value in vals.
-	// For example:
-	//   Printv("{0} and {1}", "red", "green");
-	// Would print the string:
-	//   "red and green"
-	// Arguments can be indexed in any order.
-	// Invalid indices are not substituted.
-	inline void Printv(const char* msg, std::initializer_list<PrintValue> vals)
-	{
-		Printv(nullptr, nullptr, 0, msg, vals);
-	}
-
-	// Print is a wrapper over Printv that wraps the variadic arguments into an
-	// initializer_list before calling Printv.
-	template <typename ... ARGS>
-	void Print(const char* msg, const ARGS& ... vals) { Printv(msg, {vals...}); }
-
-	// Print is a wrapper over Printv that wraps the variadic arguments into an
-	// initializer_list before calling Printv.
-	template <typename ... ARGS>
-	void Print(const char* function, const char* file, int line, const char* msg, const ARGS& ... vals)
-	{
-		Printv(function, file, line, msg, {vals...});
-	}
-
-	// RR_LOG is a macro that calls Print(), automatically populating the
-	// function, file and line parameters and appending a newline to the string.
-	//
-	// RR_LOG() is intended to be used for debugging JIT compiled code, and is
-	// not intended for production use.
-	#if defined(_WIN32)
-		#define RR_LOG(msg, ...) Print(__FUNCSIG__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
-	#else
-		#define RR_LOG(msg, ...) Print(__PRETTY_FUNCTION__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
-	#endif
-
-	// Macro magic to perform variadic dispatch.
-	// See: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
-	// Note, this doesn't attempt to use the ##__VA_ARGS__ trick to handle 0
-	#define RR_MSVC_EXPAND_BUG(X) X // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler.
-	#define RR_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
-	#define RR_COUNT_ARGUMENTS(...) RR_MSVC_EXPAND_BUG(RR_GET_NTH_ARG(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
-	static_assert(1 == RR_COUNT_ARGUMENTS(a), "RR_COUNT_ARGUMENTS broken"); // Sanity checks.
-	static_assert(2 == RR_COUNT_ARGUMENTS(a, b), "RR_COUNT_ARGUMENTS broken");
-	static_assert(3 == RR_COUNT_ARGUMENTS(a, b, c), "RR_COUNT_ARGUMENTS broken");
-
-	// RR_WATCH_FMT(...) resolves to a string literal that lists all the
-	// arguments by name. This string can be passed to LOG() to print each of
-	// the arguments with their name and value.
-	//
-	// RR_WATCH_FMT(...) uses the RR_COUNT_ARGUMENTS helper macro to delegate to a
-	// corresponding RR_WATCH_FMT_n specialization macro below.
-	#define RR_WATCH_CONCAT(a, b) a ## b
-	#define RR_WATCH_CONCAT2(a, b) RR_WATCH_CONCAT(a, b)
-	#define RR_WATCH_FMT(...) RR_MSVC_EXPAND_BUG(RR_WATCH_CONCAT2(RR_WATCH_FMT_, RR_COUNT_ARGUMENTS(__VA_ARGS__))(__VA_ARGS__))
-	#define RR_WATCH_FMT_1(_1) "\n  " #_1 ": {0}"
-	#define RR_WATCH_FMT_2(_1, _2)                                             RR_WATCH_FMT_1(_1) "\n  " #_2 ": {1}"
-	#define RR_WATCH_FMT_3(_1, _2, _3)                                         RR_WATCH_FMT_2(_1, _2) "\n  " #_3 ": {2}"
-	#define RR_WATCH_FMT_4(_1, _2, _3, _4)                                     RR_WATCH_FMT_3(_1, _2, _3) "\n  " #_4 ": {3}"
-	#define RR_WATCH_FMT_5(_1, _2, _3, _4, _5)                                 RR_WATCH_FMT_4(_1, _2, _3, _4) "\n  " #_5 ": {4}"
-	#define RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6)                             RR_WATCH_FMT_5(_1, _2, _3, _4, _5) "\n  " #_6 ": {5}"
-	#define RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7)                         RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) "\n  " #_7 ": {6}"
-	#define RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8)                     RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) "\n  " #_8 ": {7}"
-	#define RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9)                 RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) "\n  " #_9 ": {8}"
-	#define RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)           RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) "\n  " #_10 ": {9}"
-	#define RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)      RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) "\n  " #_11 ": {10}"
-	#define RR_WATCH_FMT_12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) "\n  " #_12 ": {11}"
-
-	// RR_WATCH() is a helper that prints the name and value of all the supplied
-	// arguments.
-	// For example, if you had the Int and bool variables 'foo' and 'bar' that
-	// you want to print, you can simply write:
-	//    RR_WATCH(foo, bar)
-	// When this JIT compiled code is executed, it will print the string
-	// "foo: 1, bar: true" to stdout.
-	//
-	// RR_WATCH() is intended to be used for debugging JIT compiled code, and
-	// is not intended for production use.
-	#define RR_WATCH(...) RR_LOG(RR_WATCH_FMT(__VA_ARGS__), __VA_ARGS__)
-#endif // ENABLE_RR_PRINT
-
 	class ForData
 	{
 	public:
diff --git a/src/Reactor/Reactor.vcxproj b/src/Reactor/Reactor.vcxproj
index 9859409..4f6ef61 100644
--- a/src/Reactor/Reactor.vcxproj
+++ b/src/Reactor/Reactor.vcxproj
@@ -300,6 +300,7 @@
     <ClInclude Include="ExecutableMemory.hpp" />

     <ClInclude Include="MutexLock.hpp" />

     <ClInclude Include="Nucleus.hpp" />

+    <ClInclude Include="Print.hpp" />

     <ClInclude Include="Reactor.hpp" />

     <ClInclude Include="Routine.hpp" />

     <ClInclude Include="Thread.hpp" />

diff --git a/src/Reactor/Reactor.vcxproj.filters b/src/Reactor/Reactor.vcxproj.filters
index 32900aa..22c1a6b 100644
--- a/src/Reactor/Reactor.vcxproj.filters
+++ b/src/Reactor/Reactor.vcxproj.filters
@@ -41,6 +41,9 @@
     <ClInclude Include="Nucleus.hpp">

       <Filter>Header Files</Filter>

     </ClInclude>

+    <ClInclude Include="Print.hpp">

+      <Filter>Header Files</Filter>

+    </ClInclude>

     <ClInclude Include="Reactor.hpp">

       <Filter>Header Files</Filter>

     </ClInclude>