aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--content/2022-07-07-llvm-orc-jit/.clang-format6
-rw-r--r--content/2022-07-07-llvm-orc-jit/.gitignore3
-rw-r--r--content/2022-07-07-llvm-orc-jit/CMakeLists.txt30
-rw-r--r--content/2022-07-07-llvm-orc-jit/Makefile30
-rw-r--r--content/2022-07-07-llvm-orc-jit/ccompiler.h9
-rw-r--r--content/2022-07-07-llvm-orc-jit/index.md13
-rw-r--r--content/2022-07-07-llvm-orc-jit/jit.h33
-rw-r--r--content/2022-07-07-llvm-orc-jit/main.cc27
8 files changed, 96 insertions, 55 deletions
diff --git a/content/2022-07-07-llvm-orc-jit/.clang-format b/content/2022-07-07-llvm-orc-jit/.clang-format
index 9a0c292..784ecf3 100644
--- a/content/2022-07-07-llvm-orc-jit/.clang-format
+++ b/content/2022-07-07-llvm-orc-jit/.clang-format
@@ -54,7 +54,7 @@ BreakStringLiterals: true
ColumnLimit: 80
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
-ConstructorInitializerIndentWidth: 2
+ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
@@ -65,13 +65,13 @@ IncludeBlocks: Preserve
# Could use `IncludeCategories` to define rules for includes
IndentCaseLabels: true
IndentPPDirectives: AfterHash
-IndentWidth: 4
+IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
-NamespaceIndentation: All
+NamespaceIndentation: Inner
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
diff --git a/content/2022-07-07-llvm-orc-jit/.gitignore b/content/2022-07-07-llvm-orc-jit/.gitignore
new file mode 100644
index 0000000..50f1b95
--- /dev/null
+++ b/content/2022-07-07-llvm-orc-jit/.gitignore
@@ -0,0 +1,3 @@
+BUILD/
+compile_commands.json
+.cache
diff --git a/content/2022-07-07-llvm-orc-jit/CMakeLists.txt b/content/2022-07-07-llvm-orc-jit/CMakeLists.txt
new file mode 100644
index 0000000..04fe617
--- /dev/null
+++ b/content/2022-07-07-llvm-orc-jit/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.15)
+project(llvm-orc-jit)
+
+add_executable(main main.cc)
+
+# Enable warnings / warnings as errors.
+target_compile_options(main PRIVATE -Wall -Wextra -Werror)
+
+# -- LLVM/CLANG ----------------------------------------------------------------
+
+find_package(Clang HINTS "${CLANG_INSTALL_PREFIX}/lib/cmake/clang")
+
+if (NOT ${CLANG_INSTALL_PREFIX} STREQUAL "/")
+ # Treat custom LLVM/CLANG include path as system include path, such that
+ # warnings are suppressed for those header files.
+ target_include_directories(main SYSTEM PRIVATE ${CLANG_INCLUDE_DIRS})
+endif()
+
+target_link_libraries(main clang-cpp)
+
+# -- SANITIZER -----------------------------------------------------------------
+
+option(SANITIZER "Enable ASAN/LSAN/UBSAN" ON)
+
+if (SANITIZER)
+ target_compile_options(main PRIVATE -fsanitize=address -fsanitize=leak
+ -fsanitize=undefined -fno-rtti)
+ target_link_options(main PRIVATE -fsanitize=address -fsanitize=leak
+ -fsanitize=undefined)
+endif()
diff --git a/content/2022-07-07-llvm-orc-jit/Makefile b/content/2022-07-07-llvm-orc-jit/Makefile
index d292bf1..793d9db 100644
--- a/content/2022-07-07-llvm-orc-jit/Makefile
+++ b/content/2022-07-07-llvm-orc-jit/Makefile
@@ -1,27 +1,19 @@
-LIBS = $(shell llvm-config --libs)
-LIBS += -lclang-cpp
-
-CXXFLAGS = -Wall -Wextra -Werror
-CXXFLAGS += -O0
-CXXFLAGS += -g
-CXXFLAGS += -std=c++17
-
-SAN ?= 1
-ifeq ($(SAN),1)
-FLAGS = -fsanitize=address -fsanitize=leak -fsanitize=undefined
-endif
-
-run: main
+run: BUILD/main
./$^
-main: main.o
- $(CXX) -o $@ $^ $(LIBS) $(FLAGS)
+BUILD/main: BUILD/CMakeCache.txt main.cc jit.h ccompiler.h
+ ninja -C BUILD
-%.o: %.cc
- $(CXX) -o $@ -c $^ $(CXXFLAGS) $(FLAGS)
+BUILD/CMakeCache.txt: CMakeLists.txt
+ # When building against a specific LLVM/CLANG build use
+ # -DCLANG_INSTALL_PREFIX=<PATH>
+ # to configure the root of the installation.
+ cmake -B BUILD -S . -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=1
+ ln -sfn BUILD/compile_commands.json
+ touch $@
fmt:
clang-format -i *.cc *.h
clean:
- $(RM) main *.o
+ $(RM) -r BUILD compile_commands.json
diff --git a/content/2022-07-07-llvm-orc-jit/ccompiler.h b/content/2022-07-07-llvm-orc-jit/ccompiler.h
index 57a2b62..368fc21 100644
--- a/content/2022-07-07-llvm-orc-jit/ccompiler.h
+++ b/content/2022-07-07-llvm-orc-jit/ccompiler.h
@@ -8,8 +8,8 @@
#include <clang/Lex/PreprocessorOptions.h>
#include <llvm/IR/Module.h>
-#include <llvm/Support/Host.h>
#include <llvm/Support/TargetSelect.h>
+#include <llvm/TargetParser/Host.h>
namespace cc {
@@ -21,7 +21,6 @@ using clang::DiagnosticsEngine;
using clang::EmitLLVMOnlyAction;
using clang::TextDiagnosticPrinter;
-using llvm::cantFail;
using llvm::Expected;
using llvm::IntrusiveRefCntPtr;
using llvm::LLVMContext;
@@ -51,7 +50,7 @@ public:
std::unique_ptr<Module> M;
};
- Expected<CompileResult> compile(const char *code) const {
+ Expected<CompileResult> compile(const char* code) const {
using std::errc;
const auto err = [](errc ec) { return std::make_error_code(ec); };
@@ -77,7 +76,7 @@ public:
code_fname, MemoryBuffer::getMemBuffer(code).release());
// Configure codegen options.
- auto &CG = CC.getCodeGenOpts();
+ auto& CG = CC.getCodeGenOpts();
CG.OptimizationLevel = 3;
CG.setInlining(clang::CodeGenOptions::NormalInlining);
@@ -104,6 +103,6 @@ private:
std::unique_ptr<DiagnosticsEngine> DE;
};
-} // namespace cc
+} // namespace cc
#endif
diff --git a/content/2022-07-07-llvm-orc-jit/index.md b/content/2022-07-07-llvm-orc-jit/index.md
index 4b2add0..e453f0c 100644
--- a/content/2022-07-07-llvm-orc-jit/index.md
+++ b/content/2022-07-07-llvm-orc-jit/index.md
@@ -5,6 +5,9 @@ title = "Jit C in memory using LLVM ORC api"
tags = ["llvm", "clang", "c++"]
+++
+**EDIT**:
+- 2023-12-19: Migrate example to `llvm17`.
+
Based on the in-memory compiler shared in the last post ([C to LLVM IR in
memory using libclang](@/2022-06-18-libclang-c-to-llvm-ir/index.md)), this post
demonstrates a small *just in time (JIT)* compiler which allows to compile C
@@ -31,11 +34,15 @@ The sources are available under [llvm-orc-jit][post-src].
{{ include(path="content/2022-07-07-llvm-orc-jit/ccompiler.h") }}
```
-### Makefile
-```make
-{{ include(path="content/2022-07-07-llvm-orc-jit/Makefile") }}
+### CMakeLists.txt
+```cmake
+{{ include(path="content/2022-07-07-llvm-orc-jit/CMakeLists.txt") }}
```
+The following [Makefile][post-makefile] provides a convenience wrapper to
+configure, build, and run the example with a single `make` invocation.
+
[post-src]: https://git.memzero.de/blog/tree/content/2022-07-07-llvm-orc-jit?h=main
+[post-makefile]: https://git.memzero.de/blog/tree/content/2022-07-07-llvm-orc-jit/Makefile?h=main
[src-clang]: https://github.com/llvm/llvm-project/tree/main/clang
[blog-clang-in-memory]: https://blog.audio-tk.com/2018/09/18/compiling-c-code-in-memory-with-clang/
[llvm-jit-tut]: https://www.llvm.org/docs/tutorial/BuildingAJIT1.html
diff --git a/content/2022-07-07-llvm-orc-jit/jit.h b/content/2022-07-07-llvm-orc-jit/jit.h
index 10d6d4a..9ac7b0a 100644
--- a/content/2022-07-07-llvm-orc-jit/jit.h
+++ b/content/2022-07-07-llvm-orc-jit/jit.h
@@ -9,21 +9,25 @@
#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
#include <llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h>
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
+#include <llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/LLVMContext.h>
namespace jit {
-
+using llvm::cantFail;
using llvm::DataLayout;
using llvm::Expected;
using llvm::JITEvaluatedSymbol;
+using llvm::JITSymbolFlags;
using llvm::SectionMemoryManager;
using llvm::StringRef;
using llvm::orc::ConcurrentIRCompiler;
// using llvm::orc::DynamicLibrarySearchGenerator;
using llvm::orc::ExecutionSession;
+using llvm::orc::ExecutorAddr;
+using llvm::orc::ExecutorSymbolDef;
using llvm::orc::IRCompileLayer;
using llvm::orc::JITDylib;
using llvm::orc::JITTargetMachineBuilder;
@@ -45,23 +49,25 @@ private:
RTDyldObjectLinkingLayer ObjectLayer;
IRCompileLayer CompileLayer;
- JITDylib &JD;
+ JITDylib& JD;
public:
Jit(std::unique_ptr<ExecutionSession> ES, JITTargetMachineBuilder JTMB,
- DataLayout DL)
- : ES(std::move(ES)), DL(std::move(DL)), Mangle(*this->ES, this->DL),
- ObjectLayer(*this->ES,
- []() { return std::make_unique<SectionMemoryManager>(); }),
- CompileLayer(*this->ES, ObjectLayer,
- std::make_unique<ConcurrentIRCompiler>(std::move(JTMB))),
- JD(this->ES->createBareJITDylib("main")) {
+ DataLayout DL) :
+ ES(std::move(ES)),
+ DL(std::move(DL)), Mangle(*this->ES, this->DL),
+ ObjectLayer(*this->ES,
+ []() { return std::make_unique<SectionMemoryManager>(); }),
+ CompileLayer(*this->ES, ObjectLayer,
+ std::make_unique<ConcurrentIRCompiler>(std::move(JTMB))),
+ JD(this->ES->createBareJITDylib("main")) {
// https://www.llvm.org/docs/ORCv2.html#how-to-add-process-and-library-symbols-to-jitdylibs
// JD.addGenerator(
// cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(
// DL.getGlobalPrefix())));
- (void)JD.define(llvm::orc::absoluteSymbols(
- {{Mangle("libc_puts"), llvm::JITEvaluatedSymbol::fromPointer(&puts)}}));
+ cantFail(JD.define(llvm::orc::absoluteSymbols(
+ {{Mangle("libc_puts"),
+ {ExecutorAddr::fromPtr(&puts), JITSymbolFlags::Exported}}})));
}
~Jit() {
@@ -81,7 +87,6 @@ public:
return std::make_unique<Jit>(std::move(ES), std::move(JTMB), std::move(DL));
}
- // Error addModule(ThreadSafeModule TSM) {
Expected<ResourceTrackerSP> addModule(ThreadSafeModule TSM) {
auto RT = JD.createResourceTracker();
if (auto E = CompileLayer.add(RT, std::move(TSM))) {
@@ -90,11 +95,11 @@ public:
return RT;
}
- Expected<JITEvaluatedSymbol> lookup(StringRef Name) {
+ Expected<ExecutorSymbolDef> lookup(StringRef Name) {
return ES->lookup({&JD}, Mangle(Name.str()));
}
};
-} // namespace jit
+} // namespace jit
#endif
diff --git a/content/2022-07-07-llvm-orc-jit/main.cc b/content/2022-07-07-llvm-orc-jit/main.cc
index 1631990..a6ee67b 100644
--- a/content/2022-07-07-llvm-orc-jit/main.cc
+++ b/content/2022-07-07-llvm-orc-jit/main.cc
@@ -2,13 +2,14 @@
#include "jit.h"
int main() {
- const char code[] = "extern void libc_puts(const char*);"
- "struct S { int a; int b; };"
- "static void init_a(struct S* s) { s->a = 1111; }"
- "static void init_b(struct S* s) { s->b = 2222; }"
- "void init(struct S* s) {"
- "init_a(s); init_b(s);"
- "libc_puts(\"libc_puts()\"); }";
+ const char code[] =
+ "extern void libc_puts(const char*);"
+ "struct S { int a; int b; };"
+ "static void init_a(struct S* s) { s->a = 1111; }"
+ "static void init_b(struct S* s) { s->b = 2222; }"
+ "void init(struct S* s) {"
+ "init_a(s); init_b(s);"
+ "libc_puts(\"libc_puts()\"); }";
auto R = cc::CCompiler().compile(code);
// Abort if compilation failed.
@@ -30,12 +31,12 @@ int main() {
}
if (auto ADDR = JIT->lookup("init")) {
- std::printf("JIT ADDR 0x%lx\n", (*ADDR).getAddress());
+ std::printf("JIT ADDR 0x%lx\n", (*ADDR).getAddress().getValue());
struct S {
int a, b;
} state = {0, 0};
- auto JIT_FN = (void (*)(struct S *))(*ADDR).getAddress();
+ auto JIT_FN = (*ADDR).getAddress().toPtr<void(struct S*)>();
std::printf("S { a=%d b=%d }\n", state.a, state.b);
JIT_FN(&state);
@@ -43,10 +44,14 @@ int main() {
}
// Remove jitted code tracked by this RT.
- (void)(*RT)->remove();
+ cantFail((*RT)->remove());
if (auto E = JIT->lookup("init").takeError()) {
- llvm::errs() << "Expected error, we dropped removed code tracked by RT and "
+ // In ERROR state, as expected, consume the error.
+ llvm::consumeError(std::move(E));
+ } else {
+ // In SUCCESS state, not expected as code was dropped.
+ llvm::errs() << "Expected error, we removed code tracked by RT and "
"hence 'init' should be "
"removed from the JIT!\n";
}