From a599959a61e2a9ae313b851b2b63c0a2b97d3cb5 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Tue, 19 Dec 2023 18:53:31 +0100 Subject: llvm-orc-jit: migrate to llvm17 --- content/2022-07-07-llvm-orc-jit/.clang-format | 6 ++--- content/2022-07-07-llvm-orc-jit/.gitignore | 3 +++ content/2022-07-07-llvm-orc-jit/CMakeLists.txt | 30 +++++++++++++++++++++++ content/2022-07-07-llvm-orc-jit/Makefile | 30 +++++++++-------------- content/2022-07-07-llvm-orc-jit/ccompiler.h | 9 ++++--- content/2022-07-07-llvm-orc-jit/index.md | 13 +++++++--- content/2022-07-07-llvm-orc-jit/jit.h | 33 +++++++++++++++----------- content/2022-07-07-llvm-orc-jit/main.cc | 27 ++++++++++++--------- 8 files changed, 96 insertions(+), 55 deletions(-) create mode 100644 content/2022-07-07-llvm-orc-jit/.gitignore create mode 100644 content/2022-07-07-llvm-orc-jit/CMakeLists.txt (limited to 'content/2022-07-07-llvm-orc-jit') 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= + # 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 #include -#include #include +#include 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 M; }; - Expected compile(const char *code) const { + Expected 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 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 #include #include +#include #include #include #include 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 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(); }), - CompileLayer(*this->ES, ObjectLayer, - std::make_unique(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(); }), + CompileLayer(*this->ES, ObjectLayer, + std::make_unique(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(std::move(ES), std::move(JTMB), std::move(DL)); } - // Error addModule(ThreadSafeModule TSM) { Expected addModule(ThreadSafeModule TSM) { auto RT = JD.createResourceTracker(); if (auto E = CompileLayer.add(RT, std::move(TSM))) { @@ -90,11 +95,11 @@ public: return RT; } - Expected lookup(StringRef Name) { + Expected 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(); 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"; } -- cgit v1.2.3