Go to the documentation of this file.
13 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
14 #define LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
20 #include <type_traits>
89 "Cannot get data for out-of-band error value");
96 "Cannot get data for out-of-band error value");
103 "Cannot get data for out-of-band error value");
143 char *Tmp = (
char *)malloc(strlen(
Msg) + 1);
162 R.Data.ValuePtr =
nullptr;
166 CWrapperFunctionResult R;
171 template <
typename SPSArgListT,
typename... ArgTs>
172 WrapperFunctionResult
176 if (!SPSArgListT::serialize(
OB,
Args...))
178 "Error serializing arguments to blob in call");
184 template <
typename HandlerT,
typename ArgTupleT, std::size_t...
I>
185 static decltype(
auto)
call(HandlerT &&
H, ArgTupleT &
Args,
186 std::index_sequence<
I...>) {
187 return std::forward<HandlerT>(
H)(std::get<I>(
Args)...);
193 template <
typename HandlerT,
typename ArgTupleT, std::size_t...
I>
195 std::index_sequence<I...>) {
196 std::forward<HandlerT>(
H)(std::get<I>(
Args)...);
201 template <
typename WrapperFunctionImplT,
202 template <
typename>
class ResultSerializer,
typename... SPSTagTs>
205 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
206 ResultSerializer, SPSTagTs...> {};
208 template <
typename RetT,
typename... ArgTs,
213 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
214 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
216 template <
typename HandlerT>
222 "Could not deserialize arguments for wrapper function call");
232 template <std::size_t...
I>
233 static bool deserialize(
const char *ArgData,
size_t ArgSize, ArgTuple &
Args,
234 std::index_sequence<I...>) {
241 template <
typename RetT,
typename... ArgTs,
242 template <
typename>
class ResultSerializer,
typename... SPSTagTs>
249 template <
typename ClassT,
typename RetT,
typename... ArgTs,
257 template <
typename ClassT,
typename RetT,
typename... ArgTs,
264 template <
typename WrapperFunctionImplT,
268 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
269 ResultSerializer, SPSTagTs...> {};
271 template <
typename RetT,
typename SendResultT,
typename... ArgTs,
276 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
277 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
279 template <
typename HandlerT,
typename SendWrapperFunctionResultT>
281 SendWrapperFunctionResultT &&SendWrapperFunctionResult,
282 const char *ArgData,
size_t ArgSize) {
286 "Could not deserialize arguments for wrapper function call"));
291 [SendWFR =
std::move(SendWrapperFunctionResult)](
auto Result)
mutable {
292 using ResultT = decltype(Result);
301 template <std::size_t...
I>
302 static bool deserialize(
const char *ArgData,
size_t ArgSize, ArgTuple &
Args,
303 std::index_sequence<I...>) {
308 template <
typename HandlerT,
typename SerializeAndSendResultT,
309 typename ArgTupleT, std::size_t...
I>
310 static void callAsync(HandlerT &&
H,
311 SerializeAndSendResultT &&SerializeAndSendResult,
312 ArgTupleT
Args, std::index_sequence<I...>) {
314 return std::forward<HandlerT>(
H)(
std::move(SerializeAndSendResult),
320 template <
typename RetT,
typename... ArgTs,
321 template <
typename>
class ResultSerializer,
typename... SPSTagTs>
328 template <
typename ClassT,
typename RetT,
typename... ArgTs,
336 template <
typename ClassT,
typename RetT,
typename... ArgTs,
346 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
354 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
359 template <
typename SPSRetTagT>
363 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
368 template <
typename SPSRetTagT,
typename T>
372 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
385 return make_error<StringError>(
386 "Error deserializing return value from blob in call",
401 return make_error<StringError>(
402 "Error deserializing return value from blob in call",
409 template <
typename SPSTagT,
typename T>
420 return make_error<StringError>(
421 "Error deserializing return value from blob in call",
436 template <
typename SPSRetTagT,
typename... SPSTagTs>
439 template <
typename RetT>
445 template <
typename CallerFn,
typename RetT,
typename... ArgTs>
447 const ArgTs &...
Args) {
457 if (
const char *ErrMsg = ArgBuffer.getOutOfBandError())
461 Caller(ArgBuffer.data(), ArgBuffer.size());
466 Result, ResultBuffer.
data(), ResultBuffer.
size());
473 template <
typename AsyncCallerFn,
typename SendDeserializedResultFn,
476 SendDeserializedResultFn &&SendDeserializedResult,
477 const ArgTs &...
Args) {
478 using RetT =
typename std::tuple_element<
480 std::remove_reference_t<SendDeserializedResultFn>,
486 if (
auto *ErrMsg = ArgBuffer.getOutOfBandError()) {
487 SendDeserializedResult(
493 auto SendSerializedResult = [
SDR =
std::move(SendDeserializedResult)](
498 if (
auto *ErrMsg = R.getOutOfBandError()) {
506 RetVal, R.data(), R.size()))
512 Caller(
std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size());
516 template <
typename HandlerT>
518 HandlerT &&Handler) {
522 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
526 template <
typename HandlerT,
typename SendResultT>
528 HandlerT &&Handler, SendResultT &&SendResult) {
531 WFAHH::applyAsync(std::forward<HandlerT>(Handler),
532 std::forward<SendResultT>(SendResult), ArgData, ArgSize);
536 template <
typename T>
static const T &makeSerializable(
const T &
Value) {
540 static detail::SPSSerializableError makeSerializable(
Error Err) {
544 template <
typename T>
545 static detail::SPSSerializableExpected<T> makeSerializable(
Expected<T> E) {
550 template <
typename... SPSTagTs>
555 template <
typename CallerFn,
typename... ArgTs>
561 template <
typename AsyncCallerFn,
typename SendDeserializedResultFn,
564 SendDeserializedResultFn &&SendDeserializedResult,
565 const ArgTs &...
Args) {
567 std::forward<AsyncCallerFn>(Caller),
601 template <
typename RetT,
typename ClassT,
typename... ArgTs>
607 return (ObjAddr.
toPtr<ClassT*>()->*M)(std::forward<ArgTs>(
Args)...);
615 template <
typename RetT,
typename ClassT,
typename... ArgTs>
616 MethodWrapperHandler<RetT, ClassT, ArgTs...>
634 template <
typename SPSSerializer,
typename... ArgTs>
636 const ArgTs &...
Args) {
641 if (SPSSerializer::serialize(
OB,
Args...))
643 return make_error<StringError>(
"Cannot serialize arguments for "
652 : FnAddr(FnAddr), ArgData(
std::
move(ArgData)) {}
661 explicit operator bool()
const {
return !!FnAddr; }
668 FnAddr.
toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
672 template <
typename SPSRetT,
typename RetT>
673 std::enable_if_t<!std::is_same<SPSRetT, void>::value,
Error>
676 if (
const char *ErrMsg = WFR.getOutOfBandError())
680 return make_error<StringError>(
"Could not deserialize result from "
681 "serialized wrapper function call",
687 template <
typename SPSRetT>
688 std::enable_if_t<std::is_same<SPSRetT, void>::value,
Error>
691 return runWithSPSRet<shared::SPSEmpty>(
E);
698 if (
auto Err = runWithSPSRet<SPSError>(RetErr))
719 return SPSWrapperFunctionCall::AsArgList::serialize(
OB, WFC.
getCallee(),
726 if (!SPSWrapperFunctionCall::AsArgList::deserialize(
IB, FnAddr, ArgData))
737 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
Represents an address in the executor process.
This is an optimization pass for GlobalISel generic memory operations.
static void handleAsync(const char *ArgData, size_t ArgSize, HandlerT &&Handler, SendResultT &&SendResult)
Handle a call to an async wrapper function.
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
static void makeSafe(Error &Err)
static WrapperFunctionResult createOutOfBandError(const std::string &Msg)
Create an out-of-band error by copying the given string.
WrapperFunctionResult()
Create a default WrapperFunctionResult.
static void callAsync(AsyncCallerFn &&Caller, SendDeserializedResultFn &&SendDeserializedResult, const ArgTs &...Args)
Specialize to describe how to serialize/deserialize to/from the given concrete type.
static WrapperFunctionResult serialize(ErrorSuccess Err)
shared::WrapperFunctionResult run() const
Run call returning raw WrapperFunctionResult.
WrapperFunctionResult & operator=(const WrapperFunctionResult &)=delete
Output char buffer with overflow check.
static WrapperFunctionResult allocate(size_t Size)
Create a WrapperFunctionResult with the given size and return a pointer to the underlying memory.
static ErrorSuccess success()
Create a success value.
static Error call(const CallerFn &Caller, RetT &Result, const ArgTs &...Args)
Call a wrapper function.
static WrapperFunctionResult copyFrom(const std::string &Source)
Copy from the given std::string (includes the null terminator).
bool empty() const
Returns true if this value is equivalent to a default-constructed WrapperFunctionResult.
static decltype(auto) call(HandlerT &&H, ArgTupleT &Args, std::index_sequence< I... >)
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
std::enable_if_t<!std::is_same< SPSRetT, void >::value, Error > runWithSPSRet(RetT &RetVal) const
Run call and deserialize result using SPS.
static SPSEmpty call(HandlerT &&H, ArgTupleT &Args, std::index_sequence< I... >)
std::tuple< std::decay_t< ArgTs >... > ArgTuple
Tagged union holding either a T or a Error.
then ret i32 result Tail recursion elimination should handle
static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize)
static WrapperFunctionResult copyFrom(const char *Source, size_t Size)
Copy from the given char range.
static WrapperFunctionResult copyFrom(const char *Source)
Copy from the given null-terminated string (includes the null-terminator).
void apply(Opt *O, const Mod &M, const Mods &... Ms)
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const ArgDataBufferType & getArgData() const
Returns the argument data.
Error fromSPSSerializable(SPSSerializableError BSE)
static Expected< T > makeValue()
static void applyAsync(HandlerT &&H, SendWrapperFunctionResultT &&SendWrapperFunctionResult, const char *ArgData, size_t ArgSize)
Helper type for serializing Errors.
WrapperFunctionResult(CWrapperFunctionResult R)
Create a WrapperFunctionResult by taking ownership of a CWrapperFunctionResult.
MethodWrapperHandler(MethodT M)
const ExecutorAddr & getCallee() const
Returns the address to be called.
WrapperFunctionResult & operator=(WrapperFunctionResult &&Other)
static void callAsync(AsyncCallerFn &&Caller, SendDeserializedResultFn &&SendDeserializedResult, const ArgTs &...Args)
Call an async wrapper function.
static WrapperFunctionResult serialize(RetT Result)
std::tuple< std::decay_t< ArgTs >... > ArgTuple
Error runWithSPSRetErrorMerged() const
Run call and deserialize an SPSError result.
static size_t size(const WrapperFunctionCall &WFC)
WrapperFunctionResult serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args)
C++ wrapper function result: Same as CWrapperFunctionResult but auto-releases memory.
static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData, size_t ArgSize)
AMD64 Optimization Manual has some nice information about optimizing integer multiplication by a constant How much of it applies to Intel s X86 implementation There are definite trade offs to xmm0 cvttss2siq rdx jb L3 subss xmm0 rax cvttss2siq rdx xorq rdx rax ret instead of xmm1 cvttss2siq rcx movaps xmm2 subss xmm2 cvttss2siq rax rdx xorq rax ucomiss xmm0 cmovb rax ret Seems like the jb branch has high likelihood of being taken It would have saved a few instructions It s not possible to reference and DH registers in an instruction requiring REX prefix divb and mulb both produce results in AH If isel emits a CopyFromReg which gets turned into a movb and that can be allocated a r8b r15b To get around isel emits a CopyFromReg from AX and then right shift it down by and truncate it It s not pretty but it works We need some register allocation magic to make the hack go which would often require a callee saved register Callees usually need to keep this value live for most of their body so it doesn t add a significant burden on them We currently implement this in however this is suboptimal because it means that it would be quite awkward to implement the optimization for callers A better implementation would be to relax the LLVM IR rules for sret arguments to allow a function with an sret argument to have a non void return type
static WrapperFunctionResult serialize(Error Err)
WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
Create a WrapperFunctionCall from a target function and arg buffer.
std::make_index_sequence< std::tuple_size< ArgTuple >::value > ArgIndices
static Error call(const CallerFn &Caller, const ArgTs &...Args)
char * data()
Get a pointer to the data contained in this instance.
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
SPS tag type for expecteds, which are either a T or a string representing an error.
Subclass of Error for the sole purpose of identifying the success path in the type system.
S is passed via registers r2 But gcc stores them to the and then reload them to and r3 before issuing the call(r0 contains the address of the format string)
Represents a serialized wrapper function call.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
RetT(ClassT::*)(ArgTs...) MethodT
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
std::make_index_sequence< std::tuple_size< ArgTuple >::value > ArgIndices
static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC)
size_t size() const
Returns the size of the data contained in this instance.
const char * getOutOfBandError() const
If this value is an out-of-band error then this returns the error message, otherwise returns nullptr.
const char * data() const
Get a const pointer to the data contained in this instance.
static void makeSafe(RetT &Result)
static void makeSafe(Expected< T > &E)
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
char Value[sizeof(ValuePtr)]
static WrapperFunctionResult serialize(Expected< T > E)
const CustomOperand< const MCSubtargetInfo & > Msg[]
static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize, HandlerT &&Handler)
Handle a call to a wrapper function.
static Error deserialize(Expected< T > &E, const char *ArgData, size_t ArgSize)
CWrapperFunctionResultDataUnion Data
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
WrapperFunctionCall()=default
static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC)
RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args)
Lightweight error class with error context and mandatory checking.
SPSSerializableError toSPSSerializable(Error Err)
Helper type for serializing Expected<T>s.
static WrapperFunctionResult createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
std::optional< std::vector< StOtherPiece > > Other
SmallVector< char, 24 > ArgDataBufferType
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
CWrapperFunctionResult release()
Release ownership of the contained CWrapperFunctionResult.
static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize)
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
std::enable_if_t< std::is_same< SPSRetT, void >::value, Error > runWithSPSRet() const
Overload for SPS functions returning void.
LLVM Value Representation.
A utility class for serializing to a blob from a variadic list.
A function object that takes an ExecutorAddr as its first argument, casts that address to a ClassT*,...
WrapperFunctionResult(WrapperFunctionResult &&Other)