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: ...@@ -154,9 +154,8 @@ protected:
template<typename Return, typename... Arguments> template<typename Return, typename... Arguments>
Coroutine<Return(Arguments...)>::Coroutine() Coroutine<Return(Arguments...)>::Coroutine()
: core(new Nucleus())
{ {
core.reset(new Nucleus());
std::vector<Type *> types = { CToReactorT<Arguments>::type()... }; std::vector<Type *> types = { CToReactorT<Arguments>::type()... };
for(auto type : types) for(auto type : types)
{ {
......
...@@ -124,7 +124,13 @@ Variable::Variable(Type *type, int arraySize) ...@@ -124,7 +124,13 @@ Variable::Variable(Type *type, int arraySize)
Variable::~Variable() Variable::~Variable()
{ {
// `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); unmaterializedVariables->remove(this);
}
} }
void Variable::materialize() const void Variable::materialize() const
......
...@@ -2610,8 +2610,6 @@ class Function<Return(Arguments...)> ...@@ -2610,8 +2610,6 @@ class Function<Return(Arguments...)>
public: public:
Function(); Function();
virtual ~Function();
template<int index> template<int index>
Argument<typename std::tuple_element<index, std::tuple<Arguments...>>::type> Arg() const Argument<typename std::tuple_element<index, std::tuple<Arguments...>>::type> Arg() const
{ {
...@@ -2623,7 +2621,7 @@ public: ...@@ -2623,7 +2621,7 @@ public:
std::shared_ptr<Routine> operator()(const Config::Edit &cfg, const char *name, ...); std::shared_ptr<Routine> operator()(const Config::Edit &cfg, const char *name, ...);
protected: protected:
Nucleus *core; std::unique_ptr<Nucleus> core;
std::vector<Type *> arguments; std::vector<Type *> arguments;
}; };
...@@ -3175,9 +3173,8 @@ RValue<T> IfThenElse(RValue<Bool> condition, const T &ifTrue, const T &ifFalse) ...@@ -3175,9 +3173,8 @@ RValue<T> IfThenElse(RValue<Bool> condition, const T &ifTrue, const T &ifFalse)
template<typename Return, typename... Arguments> template<typename Return, typename... Arguments>
Function<Return(Arguments...)>::Function() Function<Return(Arguments...)>::Function()
: core(new Nucleus())
{ {
core = new Nucleus();
Type *types[] = { Arguments::type()... }; Type *types[] = { Arguments::type()... };
for(Type *type : types) for(Type *type : types)
{ {
...@@ -3191,12 +3188,6 @@ Function<Return(Arguments...)>::Function() ...@@ -3191,12 +3188,6 @@ Function<Return(Arguments...)>::Function()
} }
template<typename Return, typename... Arguments> 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, ...) std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const char *name, ...)
{ {
char fullName[1024 + 1]; char fullName[1024 + 1];
...@@ -3206,7 +3197,10 @@ std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const char * ...@@ -3206,7 +3197,10 @@ std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const char *
vsnprintf(fullName, 1024, name, vararg); vsnprintf(fullName, 1024, name, vararg);
va_end(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> template<typename Return, typename... Arguments>
...@@ -3219,7 +3213,10 @@ std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const Config ...@@ -3219,7 +3213,10 @@ std::shared_ptr<Routine> Function<Return(Arguments...)>::operator()(const Config
vsnprintf(fullName, 1024, name, vararg); vsnprintf(fullName, 1024, name, vararg);
va_end(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> template<class T, class S>
......
...@@ -117,8 +117,7 @@ TEST(ReactorUnitTests, Trampoline) ...@@ -117,8 +117,7 @@ TEST(ReactorUnitTests, Trampoline)
SecondaryGeneratorFunc secondaryGenerator = (SecondaryGeneratorFunc)generateSecondary; SecondaryGeneratorFunc secondaryGenerator = (SecondaryGeneratorFunc)generateSecondary;
using PrimaryFunc = int(int, int, int); using PrimaryFunc = int(int, int, int);
RoutineT<PrimaryFunc> routine;
{
FunctionT<PrimaryFunc> primary; FunctionT<PrimaryFunc> primary;
{ {
Int x = primary.Arg<0>(); Int x = primary.Arg<0>();
...@@ -131,8 +130,7 @@ TEST(ReactorUnitTests, Trampoline) ...@@ -131,8 +130,7 @@ TEST(ReactorUnitTests, Trampoline)
Return(r); Return(r);
} }
routine = primary((testName() + "_primary").c_str()); auto routine = primary((testName() + "_primary").c_str());
}
int result = routine(100, 20, -3); int result = routine(100, 20, -3);
EXPECT_EQ(result, 80); EXPECT_EQ(result, 80);
...@@ -202,6 +200,72 @@ TEST(ReactorUnitTests, Unreachable) ...@@ -202,6 +200,72 @@ TEST(ReactorUnitTests, Unreachable)
EXPECT_EQ(result, 20); 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) TEST(ReactorUnitTests, VariableAddress)
{ {
FunctionT<int(int)> function; 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