Commit b7eb3a8a by Ben Clayton

Reactor: Add ConstantData() and member function calling

rr::ConstantData() returns a Pointer<Byte> to an immutable copy of the provided data. Added two new variants of rr::Call() for calling member function pointers. Added tests. Bug: b/143479561 Change-Id: I5846fb313fbd81821bf4e9bb655414a5e0eaf133 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38408Tested-by: 's avatarBen Clayton <bclayton@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com>
parent 87894ca1
...@@ -3981,6 +3981,13 @@ namespace rr ...@@ -3981,6 +3981,13 @@ namespace rr
return RValue<Pointer<Byte>>(V(jit->builder->CreateIntToPtr(ptrAsInt, T(Pointer<Byte>::getType())))); return RValue<Pointer<Byte>>(V(jit->builder->CreateIntToPtr(ptrAsInt, T(Pointer<Byte>::getType()))));
} }
RValue<Pointer<Byte>> ConstantData(void const * data, size_t size)
{
auto str = ::llvm::StringRef(reinterpret_cast<const char*>(data), size);
auto ptr = jit->builder->CreateGlobalStringPtr(str);
return RValue<Pointer<Byte>>(V(ptr));
}
Value* Call(RValue<Pointer<Byte>> fptr, Type* retTy, std::initializer_list<Value*> args, std::initializer_list<Type*> argTys) Value* Call(RValue<Pointer<Byte>> fptr, Type* retTy, std::initializer_list<Value*> args, std::initializer_list<Type*> argTys)
{ {
::llvm::SmallVector<::llvm::Type*, 8> paramTys; ::llvm::SmallVector<::llvm::Type*, 8> paramTys;
......
...@@ -2880,6 +2880,12 @@ namespace rr ...@@ -2880,6 +2880,12 @@ namespace rr
return *this = rhs.operator RValue<Float4>(); return *this = rhs.operator RValue<Float4>();
} }
// Returns a reactor pointer to the fixed-address ptr.
RValue<Pointer<Byte>> ConstantPointer(void const * ptr);
// Returns a reactor pointer to an immutable copy of the data of size bytes.
RValue<Pointer<Byte>> ConstantData(void const * data, size_t size);
template<class T> template<class T>
Pointer<T>::Pointer(Argument<Pointer<T>> argument) : alignment(1) Pointer<T>::Pointer(Argument<Pointer<T>> argument) : alignment(1)
{ {
...@@ -3194,9 +3200,6 @@ namespace rr ...@@ -3194,9 +3200,6 @@ namespace rr
return ReinterpretCast<T>(val); return ReinterpretCast<T>(val);
} }
// Returns a reactor pointer to the fixed-address ptr.
RValue<Pointer<Byte>> ConstantPointer(void const * ptr);
// Calls the function pointer fptr with the given arguments, return type // Calls the function pointer fptr with the given arguments, return type
// and parameter types. Returns the call's return value if the function has // and parameter types. Returns the call's return value if the function has
// a non-void return type. // a non-void return type.
...@@ -3254,14 +3257,14 @@ namespace rr ...@@ -3254,14 +3257,14 @@ namespace rr
template <typename T> template <typename T>
inline ReactorTypeT<T> CastToReactor(const T& v) { return ReactorType<T>::cast(v); } inline ReactorTypeT<T> CastToReactor(const T& v) { return ReactorType<T>::cast(v); }
// Calls the function pointer fptr with the given arguments args. // Calls the static function pointer fptr with the given arguments args.
template<typename Return, typename ... CArgs, typename ... RArgs> template<typename Return, typename ... CArgs, typename ... RArgs>
inline CToReactorT<Return> Call(Return(fptr)(CArgs...), RArgs&&... args) inline CToReactorT<Return> Call(Return(fptr)(CArgs...), RArgs&&... args)
{ {
return CallHelper<Return(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...); return CallHelper<Return(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
} }
// Calls the function pointer fptr with the given arguments args. // Calls the static function pointer fptr with the given arguments args.
// Overload for calling functions with void return type. // Overload for calling functions with void return type.
template<typename ... CArgs, typename ... RArgs> template<typename ... CArgs, typename ... RArgs>
inline void Call(void(fptr)(CArgs...), RArgs&&... args) inline void Call(void(fptr)(CArgs...), RArgs&&... args)
...@@ -3269,8 +3272,49 @@ namespace rr ...@@ -3269,8 +3272,49 @@ namespace rr
CallHelper<void(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...); CallHelper<void(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
} }
// Calls the function pointer fptr with the signature FUNCTION_SIGNATURE and // Calls the member function pointer fptr with the given arguments args.
// arguments. // object can be a Class*, or a Pointer<Byte>.
template<typename Return, typename Class, typename C, typename ... CArgs, typename ... RArgs>
inline CToReactorT<Return> Call(Return(Class::* fptr)(CArgs...), C&& object, RArgs&&... args)
{
using Helper = CallHelper<Return(Class*, void*, CArgs...)>;
using fptrTy = decltype(fptr);
struct Static {
static inline Return Call(Class* object, void* fptrptr, CArgs... args)
{
auto fptr = *reinterpret_cast<fptrTy*>(fptrptr);
return (object->*fptr)(std::forward<CArgs>(args)...);
}
};
return Helper::Call(&Static::Call,
CastToReactor(object),
ConstantData(&fptr, sizeof(fptr)),
CastToReactor(std::forward<RArgs>(args))...);
}
// Calls the member function pointer fptr with the given arguments args.
// Overload for calling functions with void return type.
// object can be a Class*, or a Pointer<Byte>.
template<typename Class, typename C, typename ... CArgs, typename ... RArgs>
inline void Call(void(Class::* fptr)(CArgs...), C&& object, RArgs&&... args)
{
using Helper = CallHelper<void(Class*, void*, CArgs...)>;
using fptrTy = decltype(fptr);
struct Static {
static inline void Call(Class* object, void* fptrptr, CArgs... args)
{
auto fptr = *reinterpret_cast<fptrTy*>(fptrptr);
(object->*fptr)(std::forward<CArgs>(args)...);
}
};
Helper::Call(&Static::Call,
CastToReactor(object),
ConstantData(&fptr, sizeof(fptr)),
CastToReactor(std::forward<RArgs>(args))...);
}
// Calls the Reactor function pointer fptr with the signature
// FUNCTION_SIGNATURE and arguments.
template<typename FUNCTION_SIGNATURE, typename ... RArgs> template<typename FUNCTION_SIGNATURE, typename ... RArgs>
inline void Call(Pointer<Byte> fptr, RArgs&& ... args) inline void Call(Pointer<Byte> fptr, RArgs&& ... args)
{ {
......
...@@ -1171,6 +1171,80 @@ TEST(ReactorUnitTests, Call) ...@@ -1171,6 +1171,80 @@ TEST(ReactorUnitTests, Call)
EXPECT_EQ(c.f, 20.0f); EXPECT_EQ(c.f, 20.0f);
} }
TEST(ReactorUnitTests, CallMemberFunction)
{
if (!rr::Caps.CallSupported)
{
SUCCEED() << "rr::Call() not supported";
return;
}
struct Class
{
int Callback(int argI, float argF)
{
i = argI;
f = argF;
return i + int(f);
}
int i = 0;
float f = 0.0f;
};
Class c;
FunctionT<int()> function;
{
auto res = Call(&Class::Callback, &c, 10, 20.0f);
Return(res);
}
auto routine = function("one");
int res = routine();
EXPECT_EQ(res, 30);
EXPECT_EQ(c.i, 10);
EXPECT_EQ(c.f, 20.0f);
}
TEST(ReactorUnitTests, CallMemberFunctionIndirect)
{
if (!rr::Caps.CallSupported)
{
SUCCEED() << "rr::Call() not supported";
return;
}
struct Class
{
int Callback(int argI, float argF)
{
i = argI;
f = argF;
return i + int(f);
}
int i = 0;
float f = 0.0f;
};
FunctionT<int(void*)> function;
{
Pointer<Byte> c = function.Arg<0>();
auto res = Call(&Class::Callback, c, 10, 20.0f);
Return(res);
}
auto routine = function("one");
Class c;
int res = routine(&c);
EXPECT_EQ(res, 30);
EXPECT_EQ(c.i, 10);
EXPECT_EQ(c.f, 20.0f);
}
TEST(ReactorUnitTests, CallImplicitCast) TEST(ReactorUnitTests, CallImplicitCast)
{ {
if (!rr::Caps.CallSupported) if (!rr::Caps.CallSupported)
......
...@@ -53,6 +53,11 @@ ...@@ -53,6 +53,11 @@
#include <limits> #include <limits>
#include <iostream> #include <iostream>
namespace rr
{
class ELFMemoryStreamer;
}
namespace namespace
{ {
// Default configuration settings. Must be accessed under mutex lock. // Default configuration settings. Must be accessed under mutex lock.
...@@ -71,7 +76,7 @@ namespace ...@@ -71,7 +76,7 @@ namespace
Ice::Cfg *function = nullptr; Ice::Cfg *function = nullptr;
Ice::CfgNode *basicBlock = nullptr; Ice::CfgNode *basicBlock = nullptr;
Ice::CfgLocalAllocatorScope *allocator = nullptr; Ice::CfgLocalAllocatorScope *allocator = nullptr;
rr::Routine *routine = nullptr; rr::ELFMemoryStreamer *routine = nullptr;
std::mutex codegenMutex; std::mutex codegenMutex;
...@@ -543,10 +548,20 @@ namespace rr ...@@ -543,10 +548,20 @@ namespace rr
return entry; return entry;
} }
const void* addConstantData(const void* data, size_t size)
{
auto buf = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
memcpy(buf.get(), data, size);
auto ptr = buf.get();
constantData.emplace_back(std::move(buf));
return ptr;
}
private: private:
void *entry; void *entry;
std::vector<uint8_t, ExecutableAllocator<uint8_t>> buffer; std::vector<uint8_t, ExecutableAllocator<uint8_t>> buffer;
std::size_t position; std::size_t position;
std::vector<std::unique_ptr<uint8_t[]>> constantData;
#if defined(_WIN32) #if defined(_WIN32)
DWORD oldProtection; DWORD oldProtection;
...@@ -3497,6 +3512,13 @@ namespace rr ...@@ -3497,6 +3512,13 @@ namespace rr
} }
} }
RValue<Pointer<Byte>> ConstantData(void const * data, size_t size)
{
// TODO: Try to use Ice::VariableDeclaration::DataInitializer and
// getConstantSym instead of tagging data on the routine.
return ConstantPointer(::routine->addConstantData(data, size));
}
Value* Call(RValue<Pointer<Byte>> fptr, Type* retTy, std::initializer_list<Value*> args, std::initializer_list<Type*> argTys) Value* Call(RValue<Pointer<Byte>> fptr, Type* retTy, std::initializer_list<Value*> args, std::initializer_list<Type*> argTys)
{ {
// FIXME: This does not currently work on Windows. // FIXME: This does not currently work on Windows.
......
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