1
1
module;
2
2
3
+ #include < crispy/logstore.h>
4
+
5
+ #include < fmt/core.h>
6
+
3
7
#include < algorithm>
4
8
#include < cassert>
5
9
#include < cctype>
6
10
#include < cstdint>
7
11
#include < cstdio>
8
12
#include < cstdlib>
13
+ #include < filesystem>
9
14
#include < iostream>
10
15
#include < map>
11
16
#include < memory>
12
17
#include < ranges>
13
18
#include < string>
14
19
#include < utility>
15
20
#include < vector>
16
- # include < fmt/core.h >
21
+
17
22
#include < sys/wait.h>
18
23
19
24
#include < unistd.h>
@@ -58,11 +63,15 @@ module;
58
63
#include < llvm/Transforms/Scalar/SimplifyCFG.h>
59
64
#include < llvm/Transforms/Utils.h>
60
65
66
+ using std::unique_ptr;
67
+
61
68
using namespace llvm ;
62
69
using namespace llvm ::orc;
63
70
64
71
export module LLVMBackend;
65
72
73
+ auto inline llvmLog = logstore::category(" llvm" , " Debug log" , logstore::category::state::Enabled);
74
+
66
75
class TestJIT
67
76
{
68
77
private:
@@ -145,20 +154,21 @@ std::vector<std::string> tokenizer(const std::string& p_pcstStr, char delim)
145
154
return tokens;
146
155
}
147
156
148
- extern " C" void execute_llvmbackend (const char * prog, const char * params, int stdinFd, int stdoutFd)
157
+ extern " C" void execute (const char * prog, const char * params, int stdinFd, int stdoutFd)
149
158
{
150
-
151
159
std::vector<const char *> argv;
152
160
argv.push_back (prog);
153
- argv.push_back (params);
161
+ if (strlen (params) > 0 )
162
+ argv.push_back (params);
163
+ argv.push_back (nullptr );
164
+
165
+ fmt::print (" program to execute {} with args: {} \n " , prog, params);
154
166
155
167
pid_t const pid = fork ();
156
168
157
- fmt::print (" program to execute {} with args: {} \b " , prog, params);
158
-
159
169
switch (pid)
160
170
{
161
- case -1 : fmt::print (" Failed to fork(): {} \n " , strerror (errno)); return ;
171
+ case -1 : llvmLog () (" Failed to fork(): {} \n " , strerror (errno)); return ;
162
172
case 0 : {
163
173
// child process
164
174
if (stdinFd != STDIN_FILENO)
@@ -170,185 +180,120 @@ extern "C" void execute_llvmbackend(const char* prog, const char* params, int st
170
180
default : {
171
181
// parent process
172
182
int wstatus = 0 ;
173
- waitpid (pid, &wstatus, 0 );
174
- if (WIFSIGNALED (wstatus))
175
- fmt::print (" child process exited with signal {} \n " , WTERMSIG (wstatus));
176
- else if (WIFEXITED (wstatus))
177
- fmt::print (" child process exited with code {} \n " , WEXITSTATUS (wstatus));
178
- else if (WIFSTOPPED (wstatus))
179
- fmt::print (" child process stopped with signal {} \n " , WSTOPSIG (wstatus));
180
- else
181
- fmt::print (" child process exited with unknown status {} \n " , wstatus);
182
- break ;
183
+ waitpid (pid, &wstatus, 0 );
184
+ if (WIFSIGNALED (wstatus))
185
+ llvmLog () (" child process exited with signal {} \n " , WTERMSIG (wstatus));
186
+ else if (WIFEXITED (wstatus))
187
+ llvmLog () (" child process exited with code {} \n " , WEXITSTATUS (wstatus));
188
+ else if (WIFSTOPPED (wstatus))
189
+ llvmLog () (" child process stopped with signal {} \n " , WSTOPSIG (wstatus));
190
+ else
191
+ llvmLog () (" child process exited with unknown status {} \n " , wstatus);
192
+ break ;
183
193
}
184
194
}
185
195
}
186
196
187
- // int jitPart(std::string input)
188
- // {
189
- // using namespace llvm;
190
- // using namespace llvm::orc;
191
-
192
- // std::unique_ptr<IRBuilder<>> builder;
193
-
194
- // // Create an LLJIT instance.
195
- // ExitOnError ExitOnErr;
196
- // auto J = ExitOnErr(TestJIT::Create());
197
-
198
- // auto Context = std::make_unique<LLVMContext>();
199
-
200
- // builder = std::make_unique<IRBuilder<>>(*Context);
201
-
202
- // auto TheModule = std::make_unique<Module>("test", *Context);
203
- // TheModule->setDataLayout(J->getDataLayout());
204
-
205
- // auto byteptr = builder->getPtrTy();
206
- // // llvm::Type::getInt8Ty(*Context)->getPo;
207
- // auto FunctionType = llvm::FunctionType::get(llvm::Type::getVoidTy(*Context), { byteptr, byteptr },
208
- // false);
209
-
210
- // auto fun = TheModule->getOrInsertFunction("execute", FunctionType);
211
-
212
- // Function* F = Function::Create(FunctionType, Function::ExternalLinkage, "__anon_expr",
213
- // TheModule.get());
214
-
215
- // // Add a basic block to the function. As before, it automatically inserts
216
- // // because of the last argument.
217
- // BasicBlock* BB = BasicBlock::Create(*Context, "EntryBlock", F);
218
-
219
- // builder->SetInsertPoint(BB);
220
-
221
- // // Get pointers to the constant `1'.
222
-
223
- // const auto [prog, args] = SeparateProg(input);
224
-
225
- // auto CalRes =
226
- // builder->CreateCall(fun, { builder->CreateGlobalString(prog), builder->CreateGlobalString(args) });
227
-
228
- // // Value *One = builder.getInt32(1);
229
- // // Value *Add = builder.CreateAdd(One, One);
230
-
231
- // builder->CreateRet(builder->getInt32(1));
232
-
233
- // auto RT = J->getMainJITDylib().createResourceTracker();
234
-
235
- // auto M = ThreadSafeModule(std::move(TheModule), std::move(Context));
236
-
237
- // M.getModuleUnlocked()->print(llvm::outs(), nullptr);
238
-
239
- // ExitOnErr(J->addModule(std::move(M), RT));
240
-
241
- // // Look up the JIT'd function, cast it to a function pointer, then call it.
242
- // auto ExprSymbol = ExitOnErr(J->lookup("__anon_expr"));
243
-
244
- // void (*FP)() = ExprSymbol.getAddress().toPtr<void (*)()>();
245
- // FP();
246
-
247
- // return EXIT_SUCCESS;
248
- // }
249
-
250
197
std::tuple<std::string, std::string> SeparateProg (const std::string input)
251
198
{
252
199
253
200
std::stringstream inStream (input);
254
- std::string prog ;
201
+ std::string program ;
255
202
std::string args;
256
- getline (inStream, prog , ' ' );
203
+ getline (inStream, program , ' ' );
257
204
getline (inStream, args, ' \n ' );
258
205
259
- return { prog , args };
206
+ return { " /usr/bin/ " + program , args };
260
207
}
261
208
262
209
export class LLVMBackend
263
210
{
211
+
264
212
public:
265
213
LLVMBackend ()
266
214
{
267
215
InitializeNativeTarget ();
268
216
InitializeNativeTargetAsmPrinter ();
217
+ InitializeNativeTargetAsmParser ();
269
218
// Create an LLJIT instance.
219
+ _jit = ExitOnErr (TestJIT::Create ());
270
220
}
271
221
272
- auto exec (std::string const & input, const int stdinFd, const int stdoutFd )
222
+ void initializeModule ( )
273
223
{
224
+ _context = std::make_unique<LLVMContext>();
225
+ _builder = std::make_unique<IRBuilder<>>(*_context);
274
226
275
- using namespace llvm ;
276
- using namespace llvm ::orc;
277
- std::unique_ptr<IRBuilder<>> builder;
278
-
279
- // Create an LLJIT instance.
280
- ExitOnError ExitOnErr;
281
- auto J = ExitOnErr (TestJIT::Create ());
282
-
283
- auto Context = std::make_unique<LLVMContext>();
284
-
285
- builder = std::make_unique<IRBuilder<>>(*Context);
286
-
287
- auto TheModule = std::make_unique<Module>(" test" , *Context);
288
- TheModule->setDataLayout (J->getDataLayout ());
289
-
290
- // Create new pass and analysis managers.
291
- auto TheFPM = std::make_unique<FunctionPassManager>();
292
- auto TheLAM = std::make_unique<LoopAnalysisManager>();
293
- auto TheFAM = std::make_unique<FunctionAnalysisManager>();
294
- auto TheCGAM = std::make_unique<CGSCCAnalysisManager>();
295
- auto TheMAM = std::make_unique<ModuleAnalysisManager>();
296
- auto ThePIC = std::make_unique<PassInstrumentationCallbacks>();
297
- auto TheSI = std::make_unique<StandardInstrumentations>(*Context, /* DebugLogging*/ true );
298
- TheSI->registerCallbacks (*ThePIC, TheMAM.get ());
299
-
300
- TheFPM->addPass (ReassociatePass ());
301
- TheFPM->addPass (GVNPass ());
302
- TheFPM->addPass (SimplifyCFGPass ());
227
+ _module = std::make_unique<Module>(" test" , *_context);
228
+ _module->setDataLayout (_jit->getDataLayout ());
229
+ }
303
230
304
- PassBuilder PB;
305
- PB.registerModuleAnalyses (*TheMAM);
306
- PB.registerFunctionAnalyses (*TheFAM);
307
- PB.crossRegisterProxies (*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
231
+ void HandleExternalCall (std::string const & input, const int stdinFd, const int stdoutFd)
232
+ {
308
233
309
- auto byteptr = builder ->getPtrTy ();
310
- auto inttype = builder ->getInt64Ty ();
234
+ auto byteptr = _builder ->getPtrTy ();
235
+ auto inttype = _builder ->getInt64Ty ();
311
236
// llvm::Type::getInt8Ty(*Context)->getPo;
312
- auto FunctionType = llvm::FunctionType::get (
313
- llvm::Type::getVoidTy (*Context ), { byteptr, byteptr, inttype, inttype }, false );
237
+ _execvpFunctionType = llvm::FunctionType::get (
238
+ llvm::Type::getVoidTy (*_context ), { byteptr, byteptr, inttype, inttype }, false );
314
239
315
- auto fun = TheModule->getOrInsertFunction (" execute_llvmbackend" , FunctionType);
240
+ _mainFunctionType = llvm::FunctionType::get (
241
+ llvm::Type::getVoidTy (*_context), { llvm::Type::getVoidTy (*_context) }, false );
242
+
243
+ auto fun = _module->getOrInsertFunction (" execute" , _execvpFunctionType);
316
244
317
245
Function* F =
318
- Function::Create (FunctionType , Function::ExternalLinkage, " __anon_expr" , TheModule .get ());
246
+ Function::Create (_mainFunctionType , Function::ExternalLinkage, " __anon_expr" , _module .get ());
319
247
320
248
// Add a basic block to the function. As before, it automatically inserts
321
249
// because of the last argument.
322
- BasicBlock* BB = BasicBlock::Create (*Context , " EntryBlock" , F);
250
+ BasicBlock* BB = BasicBlock::Create (*_context , " EntryBlock" , F);
323
251
324
- builder ->SetInsertPoint (BB);
252
+ _builder ->SetInsertPoint (BB);
325
253
326
254
// Get pointers to the constant `1'.
327
255
328
256
const auto [prog, args] = SeparateProg (input);
329
257
330
- auto CalRes = builder ->CreateCall (fun,
331
- { builder ->CreateGlobalString (prog),
332
- builder ->CreateGlobalString (args),
333
- builder ->getInt64 (stdinFd),
334
- builder ->getInt64 (stdoutFd) });
258
+ auto CalRes = _builder ->CreateCall (fun,
259
+ { _builder ->CreateGlobalString (prog),
260
+ _builder ->CreateGlobalString (args),
261
+ _builder ->getInt64 (stdinFd),
262
+ _builder ->getInt64 (stdoutFd) });
335
263
336
- // Value *One = builder. getInt32(1);
337
- // Value *Add = builder.CreateAdd(One, One);
264
+ _builder-> CreateRet (_builder-> getInt32 (1 ) );
265
+ }
338
266
339
- builder->CreateRet (builder->getInt32 (1 ));
267
+ auto exec (std::string const & input, const int stdinFd, const int stdoutFd)
268
+ {
269
+ initializeModule ();
340
270
341
- auto RT = J-> getMainJITDylib (). createResourceTracker ( );
271
+ HandleExternalCall (input, stdinFd, stdoutFd );
342
272
343
- auto M = ThreadSafeModule ( std::move (TheModule), std::move (Context) );
273
+ auto RT = _jit-> getMainJITDylib (). createResourceTracker ( );
344
274
345
- M. getModuleUnlocked ()-> print ( llvm::outs ( ), nullptr );
275
+ auto M = ThreadSafeModule ( std::move (_module ), std::move (_context) );
346
276
347
- ExitOnErr (J-> addModule ( std::move (M ), RT) );
277
+ M. getModuleUnlocked ()-> print ( llvm::outs ( ), nullptr );
348
278
279
+ ExitOnErr (_jit->addModule (std::move (M), RT));
349
280
// Look up the JIT'd function, cast it to a function pointer, then call it.
350
- auto ExprSymbol = ExitOnErr (J->lookup (" __anon_expr" ));
351
-
281
+ auto ExprSymbol = ExitOnErr (_jit->lookup (" __anon_expr" ));
352
282
(ExprSymbol.getAddress ().toPtr <void (*)()>())();
283
+
284
+ // Delete the anonymous expression module from the JIT.
285
+ ExitOnErr (RT->remove ());
353
286
}
287
+
288
+ std::unique_ptr<LLVMContext> _context;
289
+ std::unique_ptr<IRBuilder<>> _builder;
290
+ std::unique_ptr<TestJIT> _jit;
291
+ std::unique_ptr<Module> _module;
292
+ ExitOnError ExitOnErr;
293
+
294
+ // types of some functions
295
+ llvm::FunctionType* _execvpFunctionType;
296
+ llvm::FunctionType* _mainFunctionType;
297
+
298
+ ~LLVMBackend () { llvm::llvm_shutdown (); }
354
299
};
0 commit comments