Implement non-void indirect Reactor Call() support

Previously the return value of the function called through the
Pointer<Byte> argument was not returned from the rr::Call(). This
change implements proper support for both non-void and void returning
function signatures.

This change also adds a unit test which demonstrates the use of a
'trampoline', which makes use of the new non-void indirect call.

Bug: b/175830790
Change-Id: I100588c6319d0c45797c48a068e1e46fa9f441ba
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/51308
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index d3e1d5a..40a596a 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -3392,10 +3392,52 @@
 	             CastToReactor(std::forward<RArgs>(args))...);
 }
 
-// Calls the Reactor function pointer fptr with the signature
-// FUNCTION_SIGNATURE and arguments.
+// NonVoidFunction<F> and VoidFunction<F> are helper classes which define ReturnType
+// when F matches a non-void fuction signature or void function signature, respectively,
+// as the function's return type.
+template<typename F>
+struct NonVoidFunction
+{};
+
+template<typename Return, typename... Arguments>
+struct NonVoidFunction<Return(Arguments...)>
+{
+	using ReturnType = Return;
+};
+
+template<typename... Arguments>
+struct NonVoidFunction<void(Arguments...)>
+{
+};
+
+template<typename F>
+using NonVoidFunctionReturnType = typename NonVoidFunction<F>::ReturnType;
+
+template<typename F>
+struct VoidFunction
+{};
+
+template<typename... Arguments>
+struct VoidFunction<void(Arguments...)>
+{
+	using ReturnType = void;
+};
+
+template<typename F>
+using VoidFunctionReturnType = typename VoidFunction<F>::ReturnType;
+
+// Calls the Reactor function pointer fptr with the signature FUNCTION_SIGNATURE and arguments.
+// Overload for calling functions with non-void return type.
 template<typename FUNCTION_SIGNATURE, typename... RArgs>
-inline void Call(Pointer<Byte> fptr, RArgs &&... args)
+inline CToReactorT<NonVoidFunctionReturnType<FUNCTION_SIGNATURE>> Call(Pointer<Byte> fptr, RArgs &&... args)
+{
+	return CallHelper<FUNCTION_SIGNATURE>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
+}
+
+// Calls the Reactor function pointer fptr with the signature FUNCTION_SIGNATURE and arguments.
+// Overload for calling functions with void return type.
+template<typename FUNCTION_SIGNATURE, typename... RArgs>
+inline VoidFunctionReturnType<FUNCTION_SIGNATURE> Call(Pointer<Byte> fptr, RArgs &&... args)
 {
 	CallHelper<FUNCTION_SIGNATURE>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
 }
diff --git a/tests/ReactorUnitTests/ReactorUnitTests.cpp b/tests/ReactorUnitTests/ReactorUnitTests.cpp
index 1f01e7c..fb7da84 100644
--- a/tests/ReactorUnitTests/ReactorUnitTests.cpp
+++ b/tests/ReactorUnitTests/ReactorUnitTests.cpp
@@ -27,7 +27,7 @@
 
 using namespace rr;
 
-std::string testName()
+static std::string testName()
 {
 	auto info = ::testing::UnitTest::GetInstance()->current_test_info();
 	return std::string{ info->test_suite_name() } + "_" + info->name();
@@ -78,6 +78,66 @@
 	EXPECT_EQ(result, reference(&one[1], 2));
 }
 
+// This test demonstrates the use of a 'trampoline', where a routine calls
+// a static function which then generates another routine during the execution
+// of the first routine. Also note the code generated for the second routine
+// depends on a parameter passed to the first routine.
+TEST(ReactorUnitTests, Trampoline)
+{
+	using SecondaryFunc = int(int, int);
+
+	static auto generateSecondary = [](int upDown) {
+		FunctionT<SecondaryFunc> secondary;
+		{
+			Int x = secondary.Arg<0>();
+			Int y = secondary.Arg<1>();
+			Int r;
+
+			if(upDown > 0)
+			{
+				r = x + y;
+			}
+			else if(upDown < 0)
+			{
+				r = x - y;
+			}
+			else
+			{
+				r = 0;
+			}
+
+			Return(r);
+		}
+
+		static auto routine = secondary((testName() + "_secondary").c_str());
+		return routine.getEntry();
+	};
+
+	using SecondaryGeneratorFunc = SecondaryFunc *(*)(int);
+	SecondaryGeneratorFunc secondaryGenerator = (SecondaryGeneratorFunc)generateSecondary;
+
+	using PrimaryFunc = int(int, int, int);
+	RoutineT<PrimaryFunc> routine;
+	{
+		FunctionT<PrimaryFunc> primary;
+		{
+			Int x = primary.Arg<0>();
+			Int y = primary.Arg<1>();
+			Int z = primary.Arg<2>();
+
+			Pointer<Byte> secondary = Call(secondaryGenerator, z);
+			Int r = Call<SecondaryFunc>(secondary, x, y);
+
+			Return(r);
+		}
+
+		routine = primary((testName() + "_primary").c_str());
+	}
+
+	int result = routine(100, 20, -3);
+	EXPECT_EQ(result, 80);
+}
+
 TEST(ReactorUnitTests, Uninitialized)
 {
 	FunctionT<int()> function;