Commit 3d26cfc4 by Nicolas Capens Committed by Nicolas Capens

Finalize Reactor Function creation at Routine acquisition

This enables generating multiple functions within the same scope, as excercised by the Trampoline unit test. Also adds a unit test for functions which are never finalized (useful for when a code path is not supported and we want to fall back to a C++ implementation). Also adds a unit test for the common pattern of deriving from Function<> and using Reactor variables as members. Bug: b/177999324 Change-Id: I269946e9c8a791eab84ff756c9c588ca8ce26337 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/51988Tested-by: 's avatarNicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent 8b4cf1c2
......@@ -154,9 +154,8 @@ protected:
template<typename Return, typename... Arguments>
Coroutine<Return(Arguments...)>::Coroutine()
: core(new Nucleus())
{
core.reset(new Nucleus());
std::vector<Type *> types = { CToReactorT<Arguments>::type()... };
for(auto type : types)
{
......
......@@ -124,7 +124,13 @@ Variable::Variable(Type *type, int arraySize)
Variable::~Variable()
{
unmaterializedVariables->remove(this);
// `unmaterializedVariables` can be null at this point due to the function
// already having been finalized, while classes derived from `Function<>`
// can have member `Variable` fields which are destructed afterwards.
if(unmaterializedVariables)
{
unmaterializedVariables->remove(this);
}
}
void Variable::materialize() const
......
......@@ -2610,8 +2610,6 @@ class Function<Return(Arguments...)>
public:
Function();
virtual ~Function();
template<int index>
Argument<typename std::tuple_element<index, std::tuple<Arguments...>>::type> Arg() const
{
......@@ -2623,7 +2621,7 @@ public:
std::shared_ptr<Routine> operator()(const Config::Edit &cfg, const char *name, ...);
protected:
Nucleus *core;
std::unique_ptr<Nucleus> core;
std::vector<Type *> arguments;
};
......@@ -3175,9 +3173,8 @@ RValue<T> IfThenElse(RValue<Bool> condition, const T &ifTrue, const T &ifFalse)
template<typename Return, typename... Arguments>
Function<Return(Arguments...)>::Function()
: core(new Nucleus())
{
core = new Nucleus();
Type *types[] = { Arguments::type()... };
for(Type *type : types)
{
......@@ -3191,12 +3188,6 @@ Function<Return(Arguments...)>::Function()
}
template<typename Return, typename... Arguments>
Function<Return(Arguments...)>::~Function()
{
delete core;
}
template<typename Return, typename... Arguments>
std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const char *name, ...)
{
char fullName[1024 + 1];
......@@ -3206,7 +3197,10 @@ std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const char *
vsnprintf(fullName, 1024, name, vararg);
va_end(vararg);
return core->acquireRoutine(fullName, Config::Edit::None);
auto routine = core->acquireRoutine(fullName, Config::Edit::None);
core.reset(nullptr);
return routine;
}
template<typename Return, typename... Arguments>
......@@ -3219,7 +3213,10 @@ std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const Config
vsnprintf(fullName, 1024, name, vararg);
va_end(vararg);
return core->acquireRoutine(fullName, cfg);
auto routine = core->acquireRoutine(fullName, cfg);
core.reset(nullptr);
return routine;
}
template<class T, class S>
......
......@@ -117,23 +117,21 @@ TEST(ReactorUnitTests, Trampoline)
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);
FunctionT<PrimaryFunc> primary;
{
Int x = primary.Arg<0>();
Int y = primary.Arg<1>();
Int z = primary.Arg<2>();
Return(r);
}
Pointer<Byte> secondary = Call(secondaryGenerator, z);
Int r = Call<SecondaryFunc>(secondary, x, y);
routine = primary((testName() + "_primary").c_str());
Return(r);
}
auto routine = primary((testName() + "_primary").c_str());
int result = routine(100, 20, -3);
EXPECT_EQ(result, 80);
}
......@@ -202,6 +200,72 @@ TEST(ReactorUnitTests, Unreachable)
EXPECT_EQ(result, 20);
}
// Stopping in the middle of a `Function<>` is supported and should not affect
// subsequent complete ones.
TEST(ReactorUnitTests, UnfinishedFunction)
{
do
{
FunctionT<int(int)> function;
{
Int a = function.Arg<0>();
Int z = 4;
break; // Terminate do-while early.
Return(a + z);
}
} while(true);
FunctionT<int(int)> function;
{
Int a = function.Arg<0>();
Int z = 4;
Return(a - z);
}
auto routine = function(testName().c_str());
int result = routine(16);
EXPECT_EQ(result, 12);
}
// Deriving from `Function<>` and using Reactor variables as members can be a
// convenient way to 'name' function arguments and compose complex functions
// with helper methods. This test checks the interactions between the lifetime
// of the `Function<>` and the variables belonging to the derived class.
struct FunctionMembers : FunctionT<int(int)>
{
FunctionMembers()
: level(Arg<0>())
{
For(Int i = 0, i < 3, i++)
{
pourSomeMore();
}
Return(level);
}
void pourSomeMore()
{
level += 2;
}
Int level;
};
TEST(ReactorUnitTests, FunctionMembers)
{
FunctionMembers function;
auto routine = function(testName().c_str());
int result = routine(3);
EXPECT_EQ(result, 9);
}
TEST(ReactorUnitTests, VariableAddress)
{
FunctionT<int(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