aboutsummaryrefslogtreecommitdiff
path: root/tools/driver/EmbeddedRunner.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 03:54:49 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 03:54:49 +0000
commite28cbb2efac9ed6e56cd9ab6eb1a3f16810d575a (patch)
treea0402247ba92259f6b7f3a2ad2c8ed0ca8eab3de /tools/driver/EmbeddedRunner.cc
parentba1b65f4a20566405c53d4ded90b483ec9aa7d09 (diff)
feat: embed a statically linked LLVM execution engine
Add EMBEDDED mode to run generated modules in-process without lli or PATH lookup. Link LLVM and support archives plus the C++ runtime statically, while retaining the system C runtime on Linux. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'tools/driver/EmbeddedRunner.cc')
-rw-r--r--tools/driver/EmbeddedRunner.cc45
1 files changed, 45 insertions, 0 deletions
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc
new file mode 100644
index 0000000..81a2265
--- /dev/null
+++ b/tools/driver/EmbeddedRunner.cc
@@ -0,0 +1,45 @@
+#include "EmbeddedRunner.h"
+#include "cps/CodeGen.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+int runEmbedded(const cps::CodeGen &CG) {
+ if (llvm::InitializeNativeTarget() || llvm::InitializeNativeTargetAsmPrinter()) {
+ llvm::errs() << "Error: cannot initialize the embedded LLVM target\n";
+ return 1;
+ }
+ std::string Error;
+ if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &Error)) {
+ llvm::errs() << "Error: cannot load process symbols: " << Error << "\n";
+ return 1;
+ }
+ // Keep CodeGen's module and context alive while the engine owns its clone.
+ auto Module = llvm::CloneModule(CG.getModule());
+ Module->setTargetTriple(llvm::sys::getProcessTriple());
+ llvm::EngineBuilder Builder(std::move(Module));
+ Builder.setEngineKind(llvm::EngineKind::JIT);
+ Builder.setErrorStr(&Error);
+ Builder.setMCJITMemoryManager(std::make_unique<llvm::SectionMemoryManager>());
+ std::unique_ptr<llvm::ExecutionEngine> Engine(Builder.create());
+ if (!Engine) {
+ llvm::errs() << "Error: cannot create the embedded LLVM engine: " << Error << "\n";
+ return 1;
+ }
+ Engine->finalizeObject();
+ if (Engine->hasError()) {
+ llvm::errs() << "Error: embedded LLVM execution failed: " << Engine->getErrorMessage() << "\n";
+ return 1;
+ }
+ auto MainAddress = Engine->getFunctionAddress("main");
+ if (!MainAddress) {
+ llvm::errs() << "Error: embedded LLVM could not resolve main\n";
+ return 1;
+ }
+ auto Main = reinterpret_cast<int (*)()>(MainAddress);
+ return Main();
+}