Skip to content

Commit 83e24a4

Browse files
committed
llvm backend part 2
1 parent c2ae1a4 commit 83e24a4

File tree

4 files changed

+136
-157
lines changed

4 files changed

+136
-157
lines changed

src/shell/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ find_package(Threads REQUIRED)
2323
# see https://github.com/llvm/llvm-project/issues/75108
2424
# and https://github.com/ericniebler/range-v3/blob/f013aef2ae81f3661a560e7922a968665bedebff/include/meta/meta_fwd.hpp#L37
2525
target_compile_definitions(Shell PUBLIC META_WORKAROUND_LLVM_28385)
26+
target_compile_definitions(Shell PUBLIC ENDO_VERSION_STRING="0.0.1")
2627
set(shell_libs
2728
fmt::fmt-header-only
2829
vtparser

src/shell/LLVMBackend.cpp

+83-138
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
module;
22

3+
#include <crispy/logstore.h>
4+
5+
#include <fmt/core.h>
6+
37
#include <algorithm>
48
#include <cassert>
59
#include <cctype>
610
#include <cstdint>
711
#include <cstdio>
812
#include <cstdlib>
13+
#include <filesystem>
914
#include <iostream>
1015
#include <map>
1116
#include <memory>
1217
#include <ranges>
1318
#include <string>
1419
#include <utility>
1520
#include <vector>
16-
#include <fmt/core.h>
21+
1722
#include <sys/wait.h>
1823

1924
#include <unistd.h>
@@ -58,11 +63,15 @@ module;
5863
#include <llvm/Transforms/Scalar/SimplifyCFG.h>
5964
#include <llvm/Transforms/Utils.h>
6065

66+
using std::unique_ptr;
67+
6168
using namespace llvm;
6269
using namespace llvm::orc;
6370

6471
export module LLVMBackend;
6572

73+
auto inline llvmLog = logstore::category("llvm", "Debug log", logstore::category::state::Enabled);
74+
6675
class TestJIT
6776
{
6877
private:
@@ -145,20 +154,21 @@ std::vector<std::string> tokenizer(const std::string& p_pcstStr, char delim)
145154
return tokens;
146155
}
147156

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)
149158
{
150-
151159
std::vector<const char*> argv;
152160
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);
154166

155167
pid_t const pid = fork();
156168

157-
fmt::print("program to execute {} with args: {} \b", prog, params);
158-
159169
switch (pid)
160170
{
161-
case -1: fmt::print("Failed to fork(): {} \n", strerror(errno)); return;
171+
case -1: llvmLog()("Failed to fork(): {} \n", strerror(errno)); return;
162172
case 0: {
163173
// child process
164174
if (stdinFd != STDIN_FILENO)
@@ -170,185 +180,120 @@ extern "C" void execute_llvmbackend(const char* prog, const char* params, int st
170180
default: {
171181
// parent process
172182
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;
183193
}
184194
}
185195
}
186196

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-
250197
std::tuple<std::string, std::string> SeparateProg(const std::string input)
251198
{
252199

253200
std::stringstream inStream(input);
254-
std::string prog;
201+
std::string program;
255202
std::string args;
256-
getline(inStream, prog, ' ');
203+
getline(inStream, program, ' ');
257204
getline(inStream, args, '\n');
258205

259-
return { prog, args };
206+
return { "/usr/bin/" + program, args };
260207
}
261208

262209
export class LLVMBackend
263210
{
211+
264212
public:
265213
LLVMBackend()
266214
{
267215
InitializeNativeTarget();
268216
InitializeNativeTargetAsmPrinter();
217+
InitializeNativeTargetAsmParser();
269218
// Create an LLJIT instance.
219+
_jit = ExitOnErr(TestJIT::Create());
270220
}
271221

272-
auto exec(std::string const& input, const int stdinFd, const int stdoutFd)
222+
void initializeModule()
273223
{
224+
_context = std::make_unique<LLVMContext>();
225+
_builder = std::make_unique<IRBuilder<>>(*_context);
274226

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+
}
303230

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+
{
308233

309-
auto byteptr = builder->getPtrTy();
310-
auto inttype = builder->getInt64Ty();
234+
auto byteptr = _builder->getPtrTy();
235+
auto inttype = _builder->getInt64Ty();
311236
// 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);
314239

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);
316244

317245
Function* F =
318-
Function::Create(FunctionType, Function::ExternalLinkage, "__anon_expr", TheModule.get());
246+
Function::Create(_mainFunctionType, Function::ExternalLinkage, "__anon_expr", _module.get());
319247

320248
// Add a basic block to the function. As before, it automatically inserts
321249
// because of the last argument.
322-
BasicBlock* BB = BasicBlock::Create(*Context, "EntryBlock", F);
250+
BasicBlock* BB = BasicBlock::Create(*_context, "EntryBlock", F);
323251

324-
builder->SetInsertPoint(BB);
252+
_builder->SetInsertPoint(BB);
325253

326254
// Get pointers to the constant `1'.
327255

328256
const auto [prog, args] = SeparateProg(input);
329257

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) });
335263

336-
// Value *One = builder.getInt32(1);
337-
// Value *Add = builder.CreateAdd(One, One);
264+
_builder->CreateRet(_builder->getInt32(1));
265+
}
338266

339-
builder->CreateRet(builder->getInt32(1));
267+
auto exec(std::string const& input, const int stdinFd, const int stdoutFd)
268+
{
269+
initializeModule();
340270

341-
auto RT = J->getMainJITDylib().createResourceTracker();
271+
HandleExternalCall(input, stdinFd, stdoutFd);
342272

343-
auto M = ThreadSafeModule(std::move(TheModule), std::move(Context));
273+
auto RT = _jit->getMainJITDylib().createResourceTracker();
344274

345-
M.getModuleUnlocked()->print(llvm::outs(), nullptr);
275+
auto M = ThreadSafeModule(std::move(_module), std::move(_context));
346276

347-
ExitOnErr(J->addModule(std::move(M), RT));
277+
M.getModuleUnlocked()->print(llvm::outs(), nullptr);
348278

279+
ExitOnErr(_jit->addModule(std::move(M), RT));
349280
// 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"));
352282
(ExprSymbol.getAddress().toPtr<void (*)()>())();
283+
284+
// Delete the anonymous expression module from the JIT.
285+
ExitOnErr(RT->remove());
353286
}
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(); }
354299
};

0 commit comments

Comments
 (0)