Commit 22f14a87 by Nicolas Capens Committed by Nicolas Capens

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: 's avatarNicolas Capens <nicolascapens@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent 16bec866
......@@ -3392,10 +3392,52 @@ inline void Call(void (Class::*fptr)(CArgs...), C &&object, RArgs &&... args)
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 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 void Call(Pointer<Byte> fptr, RArgs &&... args)
inline VoidFunctionReturnType<FUNCTION_SIGNATURE> Call(Pointer<Byte> fptr, RArgs &&... args)
{
CallHelper<FUNCTION_SIGNATURE>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
}
......
......@@ -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 @@ TEST(ReactorUnitTests, Sample)
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment