LLVM  14.0.0git
SimpleRemoteEPCServer.cpp
Go to the documentation of this file.
1 //===------- SimpleEPCServer.cpp - EPC over simple abstract channel -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
13 #include "llvm/Support/Host.h"
14 #include "llvm/Support/Process.h"
15 
16 #include "OrcRTBootstrap.h"
17 
18 #define DEBUG_TYPE "orc"
19 
20 using namespace llvm::orc::shared;
21 
22 namespace llvm {
23 namespace orc {
24 
26 
28 
29 #if LLVM_ENABLE_THREADS
31  unique_function<void()> Work) {
32  {
33  std::lock_guard<std::mutex> Lock(DispatchMutex);
34  if (!Running)
35  return;
36  ++Outstanding;
37  }
38 
39  std::thread([this, Work = std::move(Work)]() mutable {
40  Work();
41  std::lock_guard<std::mutex> Lock(DispatchMutex);
42  --Outstanding;
43  OutstandingCV.notify_all();
44  }).detach();
45 }
46 
48  std::unique_lock<std::mutex> Lock(DispatchMutex);
49  Running = false;
50  OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
51 }
52 #endif
53 
57  return DBS;
58 }
59 
62  ExecutorAddr TagAddr,
64 
65  LLVM_DEBUG({
66  dbgs() << "SimpleRemoteEPCServer::handleMessage: opc = ";
67  switch (OpC) {
69  dbgs() << "Setup";
70  assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
71  assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Setup?");
72  break;
74  dbgs() << "Hangup";
75  assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
76  assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Hangup?");
77  break;
79  dbgs() << "Result";
80  assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Result?");
81  break;
83  dbgs() << "CallWrapper";
84  break;
85  }
86  dbgs() << ", seqno = " << SeqNo
87  << ", tag-addr = " << formatv("{0:x}", TagAddr.getValue())
88  << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
89  << " bytes\n";
90  });
91 
92  using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
93  if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
94  return make_error<StringError>("Unexpected opcode",
96 
97  // TODO: Clean detach message?
98  switch (OpC) {
100  return make_error<StringError>("Unexpected Setup opcode",
105  if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
106  return std::move(Err);
107  break;
109  handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
110  break;
111  }
112  return ContinueSession;
113 }
114 
116  std::unique_lock<std::mutex> Lock(ServerStateMutex);
117  ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
118  return std::move(ShutdownErr);
119 }
120 
122  PendingJITDispatchResultsMap TmpPending;
123 
124  {
125  std::lock_guard<std::mutex> Lock(ServerStateMutex);
126  std::swap(TmpPending, PendingJITDispatchResults);
127  RunState = ServerShuttingDown;
128  }
129 
130  // Send out-of-band errors to any waiting threads.
131  for (auto &KV : TmpPending)
132  KV.second->set_value(
134 
135  // Wait for dispatcher to clear.
136  D->shutdown();
137 
138  // Shut down services.
139  while (!Services.empty()) {
140  ShutdownErr =
141  joinErrors(std::move(ShutdownErr), Services.back()->shutdown());
142  Services.pop_back();
143  }
144 
145  std::lock_guard<std::mutex> Lock(ServerStateMutex);
146  ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err));
147  RunState = ServerShutDown;
148  ShutdownCV.notify_all();
149 }
150 
151 Error SimpleRemoteEPCServer::sendMessage(SimpleRemoteEPCOpcode OpC,
152  uint64_t SeqNo, ExecutorAddr TagAddr,
153  ArrayRef<char> ArgBytes) {
154 
155  LLVM_DEBUG({
156  dbgs() << "SimpleRemoteEPCServer::sendMessage: opc = ";
157  switch (OpC) {
159  dbgs() << "Setup";
160  assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
161  assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Setup?");
162  break;
164  dbgs() << "Hangup";
165  assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
166  assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Hangup?");
167  break;
169  dbgs() << "Result";
170  assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Result?");
171  break;
173  dbgs() << "CallWrapper";
174  break;
175  }
176  dbgs() << ", seqno = " << SeqNo
177  << ", tag-addr = " << formatv("{0:x}", TagAddr.getValue())
178  << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
179  << " bytes\n";
180  });
181  auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
182  LLVM_DEBUG({
183  if (Err)
184  dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
185  });
186  return Err;
187 }
188 
189 Error SimpleRemoteEPCServer::sendSetupMessage(
190  StringMap<ExecutorAddr> BootstrapSymbols) {
191 
192  using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
193 
194  std::vector<char> SetupPacket;
195  SimpleRemoteEPCExecutorInfo EI;
196  EI.TargetTriple = sys::getProcessTriple();
197  if (auto PageSize = sys::Process::getPageSize())
198  EI.PageSize = *PageSize;
199  else
200  return PageSize.takeError();
201  EI.BootstrapSymbols = std::move(BootstrapSymbols);
202 
203  assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
204  "Dispatch context name should not be set");
205  assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
206  "Dispatch function name should not be set");
207  EI.BootstrapSymbols[ExecutorSessionObjectName] = ExecutorAddr::fromPtr(this);
208  EI.BootstrapSymbols[DispatchFnName] = ExecutorAddr::fromPtr(jitDispatchEntry);
209 
210  using SPSSerialize =
211  shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
212  auto SetupPacketBytes =
214  shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
215  if (!SPSSerialize::serialize(OB, EI))
216  return make_error<StringError>("Could not send setup packet",
218 
219  return sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(),
220  {SetupPacketBytes.data(), SetupPacketBytes.size()});
221 }
222 
223 Error SimpleRemoteEPCServer::handleResult(
224  uint64_t SeqNo, ExecutorAddr TagAddr,
226  std::promise<shared::WrapperFunctionResult> *P = nullptr;
227  {
228  std::lock_guard<std::mutex> Lock(ServerStateMutex);
229  auto I = PendingJITDispatchResults.find(SeqNo);
230  if (I == PendingJITDispatchResults.end())
231  return make_error<StringError>("No call for sequence number " +
232  Twine(SeqNo),
234  P = I->second;
235  PendingJITDispatchResults.erase(I);
236  releaseSeqNo(SeqNo);
237  }
238  auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size());
239  memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
240  P->set_value(std::move(R));
241  return Error::success();
242 }
243 
244 void SimpleRemoteEPCServer::handleCallWrapper(
245  uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
247  D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
248  using WrapperFnTy =
249  shared::CWrapperFunctionResult (*)(const char *, size_t);
250  auto *Fn = TagAddr.toPtr<WrapperFnTy>();
251  shared::WrapperFunctionResult ResultBytes(
252  Fn(ArgBytes.data(), ArgBytes.size()));
253  if (auto Err = sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
254  ExecutorAddr(),
255  {ResultBytes.data(), ResultBytes.size()}))
256  ReportError(std::move(Err));
257  });
258 }
259 
260 shared::WrapperFunctionResult
261 SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
262  size_t ArgSize) {
263  uint64_t SeqNo;
264  std::promise<shared::WrapperFunctionResult> ResultP;
265  auto ResultF = ResultP.get_future();
266  {
267  std::lock_guard<std::mutex> Lock(ServerStateMutex);
268  if (RunState != ServerRunning)
270  "jit_dispatch not available (EPC server shut down)");
271 
272  SeqNo = getNextSeqNo();
273  assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
274  PendingJITDispatchResults[SeqNo] = &ResultP;
275  }
276 
277  if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
278  ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize}))
279  ReportError(std::move(Err));
280 
281  return ResultF.get();
282 }
283 
284 shared::CWrapperFunctionResult
285 SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
286  const char *ArgData, size_t ArgSize) {
287  return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
288  ->doJITDispatch(FnTag, ArgData, ArgSize)
289  .release();
290 }
291 
292 } // end namespace orc
293 } // end namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:37
llvm::orc::rt_bootstrap::addTo
void addTo(StringMap< ExecutorAddr > &M)
Definition: OrcRTBootstrap.cpp:59
llvm::orc::SimpleRemoteEPCServer::defaultBootstrapSymbols
static StringMap< ExecutorAddr > defaultBootstrapSymbols()
Definition: SimpleRemoteEPCServer.cpp:54
TargetProcessControlTypes.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::orc::SimpleRemoteEPCOpcode
SimpleRemoteEPCOpcode
Definition: SimpleRemoteEPCUtils.h:37
llvm::lltok::Error
@ Error
Definition: LLToken.h:21
llvm::unique_function
unique_function is a type-erasing functor similar to std::function.
Definition: FunctionExtras.h:56
T
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
Host.h
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1168
llvm::orc::shared::WrapperFunctionResult::allocate
static WrapperFunctionResult allocate(size_t Size)
Create a WrapperFunctionResult with the given size and return a pointer to the underlying memory.
Definition: WrapperFunctionUtils.h:113
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::orc::ExecutorAddr::getValue
uint64_t getValue() const
Definition: ExecutorAddress.h:60
llvm::orc::shared
Definition: ELFNixPlatform.h:243
llvm::orc::SimpleRemoteEPCServer::handleMessage
Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, SimpleRemoteEPCArgBytesVector ArgBytes) override
Call to handle an incoming message.
Definition: SimpleRemoteEPCServer.cpp:61
OrcRTBootstrap.h
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::orc::ExecutorBootstrapService::~ExecutorBootstrapService
virtual ~ExecutorBootstrapService()
Definition: SimpleRemoteEPCServer.cpp:25
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:207
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::Lock
static sys::Mutex Lock
Definition: NVPTXUtilities.cpp:39
SimpleRemoteEPCServer.h
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:250
Process.h
PageSize
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
llvm::orc::SimpleRemoteEPCOpcode::Result
@ Result
llvm::orc::SimpleRemoteEPCDefaultBootstrapSymbolNames::ExecutorSessionObjectName
const char * ExecutorSessionObjectName
Definition: SimpleRemoteEPCUtils.cpp:40
llvm::orc::ExecutorAddr::fromPtr
static ExecutorAddr fromPtr(T *Value)
Create an ExecutorAddr from the given pointer.
Definition: ExecutorAddress.h:46
FormatVariadic.h
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:108
llvm::orc::SimpleRemoteEPCOpcode::Hangup
@ Hangup
uint64_t
D
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
move
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
Definition: README.txt:546
llvm::DenseMap< uint64_t, std::promise< shared::WrapperFunctionResult > * >
I
#define I(x, y, z)
Definition: MD5.cpp:59
llvm::sys::Process::getPageSize
static Expected< unsigned > getPageSize()
Get the process's page size.
size
i< reg-> size
Definition: README.txt:166
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:428
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::swap
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:840
memcpy
<%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(<
llvm::orc::SimpleRemoteEPCServer::ThreadDispatcher::shutdown
void shutdown() override
llvm::ArrayRef< char >
llvm::orc::SimpleRemoteEPCArgBytesVector
SmallVector< char, 128 > SimpleRemoteEPCArgBytesVector
Definition: SimpleRemoteEPCUtils.h:51
llvm::orc::SimpleRemoteEPCServer::ThreadDispatcher::dispatch
void dispatch(unique_function< void()> Work) override
llvm::inconvertibleErrorCode
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:77
llvm::sys::getProcessTriple
std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
Definition: Host.cpp:1758
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::orc::SimpleRemoteEPCOpcode::CallWrapper
@ CallWrapper
llvm::orc::SimpleRemoteEPCServer::handleDisconnect
void handleDisconnect(Error Err) override
Handle a disconnection from the underlying transport.
Definition: SimpleRemoteEPCServer.cpp:121
llvm::orc::shared::WrapperFunctionResult::createOutOfBandError
static WrapperFunctionResult createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
Definition: WrapperFunctionUtils.h:140
llvm::orc::SimpleRemoteEPCDefaultBootstrapSymbolNames::DispatchFnName
const char * DispatchFnName
Definition: SimpleRemoteEPCUtils.cpp:42
llvm::orc::SimpleRemoteEPCOpcode::Setup
@ Setup
llvm::X86II::OB
@ OB
Definition: X86BaseInfo.h:801
llvm::ArrayRef::size
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:163
llvm::orc::SimpleRemoteEPCOpcode::LastOpC
@ LastOpC
llvm::orc::SimpleRemoteEPCServer::waitForDisconnect
Error waitForDisconnect()
Definition: SimpleRemoteEPCServer.cpp:115
llvm::orc::SimpleRemoteEPCTransportClient::EndSession
@ EndSession
Definition: SimpleRemoteEPCUtils.h:55
llvm::orc::SimpleRemoteEPCServer::Dispatcher::~Dispatcher
virtual ~Dispatcher()
Definition: SimpleRemoteEPCServer.cpp:27