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: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index fc9f5e9..9c453b7 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -3271,6 +3271,28 @@
 
 		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
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index e6f3ff2..b7dcaf3 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -2959,6 +2959,97 @@
 		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
 	// PrintValue holds the printf format and value(s) for a single argument
 	// to Print(). A single argument can be expanded into multiple printf
diff --git a/src/Reactor/ReactorUnitTests.cpp b/src/Reactor/ReactorUnitTests.cpp
index a5de4f9..b52b722 100644
--- a/src/Reactor/ReactorUnitTests.cpp
+++ b/src/Reactor/ReactorUnitTests.cpp
@@ -1088,6 +1088,57 @@
 	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
 // registers computes the correct result.
 // (Note that due to MSC's lack of support for inline assembly in x64,
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index c30a419..731e682 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -3381,6 +3381,28 @@
 		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.
 	// They are stubbed to satisfy the linker.
 	RValue<Float4> Sin(RValue<Float4> x) { UNIMPLEMENTED("Subzero Sin()"); return Float4(0); }