Commit d853c12d by Ben Clayton

Reactor: Add support for calling C functions.

Bug: b/130746922 Change-Id: I0255460280d126e471dea107ffe976a1d765a218 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29335 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent c790416b
...@@ -3271,6 +3271,28 @@ namespace rr ...@@ -3271,6 +3271,28 @@ namespace rr
return RValue<Long>(V(::builder->CreateCall(rdtsc))); return RValue<Long>(V(::builder->CreateCall(rdtsc)));
} }
RValue<Pointer<Byte>> ConstantPointer(void const * ptr)
{
// Note: this should work for 32-bit pointers as well because 'inttoptr'
// is defined to truncate (and zero extend) if necessary.
auto ptrAsInt = ::llvm::ConstantInt::get(::llvm::Type::getInt64Ty(*::context), reinterpret_cast<uintptr_t>(ptr));
return RValue<Pointer<Byte>>(V(::builder->CreateIntToPtr(ptrAsInt, T(Pointer<Byte>::getType()))));
}
Value* Call(RValue<Pointer<Byte>> fptr, Type* retTy, std::initializer_list<Value*> args, std::initializer_list<Type*> argTys)
{
::llvm::SmallVector<::llvm::Type*, 8> paramTys;
for (auto ty : argTys) { paramTys.push_back(T(ty)); }
auto funcTy = ::llvm::FunctionType::get(T(retTy), paramTys, false);
auto funcPtrTy = funcTy->getPointerTo();
auto funcPtr = ::builder->CreatePointerCast(V(fptr.value), funcPtrTy);
::llvm::SmallVector<::llvm::Value*, 8> arguments;
for (auto arg : args) { arguments.push_back(V(arg)); }
return V(::builder->CreateCall(funcPtr, arguments));
}
} }
namespace rr namespace rr
......
...@@ -2959,6 +2959,97 @@ namespace rr ...@@ -2959,6 +2959,97 @@ namespace rr
return ReinterpretCast<T>(val); return ReinterpretCast<T>(val);
} }
template <typename T>
inline Value* valueOf(RValue<T> v) { return v.value; }
template <typename T>
inline Value* valueOf(LValue<T> v) { return valueOf(RValue<T>(v.loadValue())); }
template<typename T>
struct CToReactor;
template<> struct CToReactor<void> { using type = Void; };
template<> struct CToReactor<int> { using type = Int; };
template<> struct CToReactor<float> { using type = Float; };
template<> struct CToReactor<int*> { using type = Pointer<Int>; };
template<> struct CToReactor<float*> { using type = Pointer<Float>; };
// Pointers to non-reactor types are treated as uint8_t*.
template<typename T>
struct CToReactor<T*> { using type = Pointer<Byte>; };
// 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
// and parameter types. Returns the call's return value if the function has
// a non-void return type.
Value* Call(RValue<Pointer<Byte>> fptr, Type* retTy, std::initializer_list<Value*> args, std::initializer_list<Type*> paramTys);
template <typename F>
class CallHelper {};
template<typename Return, typename ... Arguments>
class CallHelper<Return(Arguments...)>
{
public:
using RReturn = typename CToReactor<Return>::type;
static inline RReturn Call(Return(fptr)(Arguments...), typename CToReactor<Arguments>::type... args)
{
return RValue<RReturn>(rr::Call(
ConstantPointer(reinterpret_cast<void*>(fptr)),
RReturn::getType(),
{ valueOf(args) ... },
{ CToReactor<Arguments>::type::getType() ... }));
}
static inline RReturn Call(Pointer<Byte> fptr, typename CToReactor<Arguments>::type... args)
{
return RValue<RReturn>(rr::Call(
fptr,
RReturn::getType(),
{ valueOf(args) ... },
{ CToReactor<Arguments>::type::getType() ... }));
}
};
template<typename ... Arguments>
class CallHelper<void(Arguments...)>
{
public:
static inline void Call(void(fptr)(Arguments...), typename CToReactor<Arguments>::type... args)
{
rr::Call(ConstantPointer(reinterpret_cast<void*>(fptr)),
Void::getType(),
{ valueOf(args) ... },
{ CToReactor<Arguments>::type::getType() ... });
}
static inline void Call(Pointer<Byte> fptr, typename CToReactor<Arguments>::type... args)
{
rr::Call(fptr,
Void::getType(),
{ valueOf(args) ... },
{ CToReactor<Arguments>::type::getType() ... });
}
};
// Calls the function pointer fptr with the given arguments args.
template<typename Return, typename ... Arguments>
inline typename CToReactor<Return>::type Call(Return(fptr)(Arguments...), typename CToReactor<Arguments>::type... args)
{
return CallHelper<Return(Arguments...)>::Call(fptr, args...);
}
// Calls the function pointer fptr with the signature FUNCTION_SIGNATURE and
// arguments.
template<typename FUNCTION_SIGNATURE, typename ... Arguments>
inline void Call(Pointer<Byte> fptr, Arguments ... args)
{
CallHelper<FUNCTION_SIGNATURE>::Call(fptr, args...);
}
#ifdef ENABLE_RR_PRINT #ifdef ENABLE_RR_PRINT
// PrintValue holds the printf format and value(s) for a single argument // PrintValue holds the printf format and value(s) for a single argument
// to Print(). A single argument can be expanded into multiple printf // to Print(). A single argument can be expanded into multiple printf
......
...@@ -1088,6 +1088,57 @@ TEST(ReactorUnitTests, MulAdd) ...@@ -1088,6 +1088,57 @@ TEST(ReactorUnitTests, MulAdd)
delete routine; delete routine;
} }
TEST(ReactorUnitTests, Call)
{
if (!rr::Caps.CallSupported)
{
SUCCEED() << "rr::Call() not supported";
return;
}
Routine *routine = nullptr;
struct Class
{
static int Callback(uint8_t *p, int i, float f)
{
auto c = reinterpret_cast<Class*>(p);
c->i = i;
c->f = f;
return i + int(f);
}
int i = 0;
float f = 0.0f;
};
{
Function<Int(Pointer<Byte>)> function;
{
Pointer<Byte> c = function.Arg<0>();
auto res = Call(Class::Callback, c, 10, 20.0f);
Return(res);
}
routine = function("one");
if(routine)
{
int(*callable)(void*) = (int(*)(void*))routine->getEntry();
Class c;
int res = callable(&c);
EXPECT_EQ(res, 30);
EXPECT_EQ(c.i, 10);
EXPECT_EQ(c.f, 20.0f);
}
}
delete routine;
}
// Check that a complex generated function which utilizes all 8 or 16 XMM // Check that a complex generated function which utilizes all 8 or 16 XMM
// registers computes the correct result. // registers computes the correct result.
// (Note that due to MSC's lack of support for inline assembly in x64, // (Note that due to MSC's lack of support for inline assembly in x64,
......
...@@ -3381,6 +3381,28 @@ namespace rr ...@@ -3381,6 +3381,28 @@ namespace rr
return Long(Int(0)); return Long(Int(0));
} }
RValue<Pointer<Byte>> ConstantPointer(void const * ptr)
{
return RValue<Pointer<Byte>>(V(::context->getConstantInt64(reinterpret_cast<intptr_t>(ptr))));
}
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.
Ice::Variable *ret = nullptr;
if (retTy != nullptr)
{
ret = ::function->makeVariable(T(retTy));
}
auto call = Ice::InstCall::create(::function, args.size(), ret, V(fptr.value), false);
for (auto arg : args)
{
call->addArg(V(arg));
}
::basicBlock->appendInst(call);
return V(ret);
}
// Below are functions currently unimplemented for the Subzero backend. // Below are functions currently unimplemented for the Subzero backend.
// They are stubbed to satisfy the linker. // They are stubbed to satisfy the linker.
RValue<Float4> Sin(RValue<Float4> x) { UNIMPLEMENTED("Subzero Sin()"); return Float4(0); } RValue<Float4> Sin(RValue<Float4> x) { UNIMPLEMENTED("Subzero Sin()"); return Float4(0); }
......
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