From b14fce113fa45da85c8c3528552ae446ced340ca Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Sat, 5 Nov 2022 23:24:05 +0100 Subject: llvm: small ORCv2 jit example --- content/2022-07-07-llvm-orc-jit/ccompiler.h | 109 ++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 content/2022-07-07-llvm-orc-jit/ccompiler.h (limited to 'content/2022-07-07-llvm-orc-jit/ccompiler.h') diff --git a/content/2022-07-07-llvm-orc-jit/ccompiler.h b/content/2022-07-07-llvm-orc-jit/ccompiler.h new file mode 100644 index 0000000..57a2b62 --- /dev/null +++ b/content/2022-07-07-llvm-orc-jit/ccompiler.h @@ -0,0 +1,109 @@ +#ifndef CCOMPILER_H +#define CCOMPILER_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace cc { + +using clang::CompilerInstance; +using clang::CompilerInvocation; +using clang::DiagnosticConsumer; +using clang::DiagnosticOptions; +using clang::DiagnosticsEngine; +using clang::EmitLLVMOnlyAction; +using clang::TextDiagnosticPrinter; + +using llvm::cantFail; +using llvm::Expected; +using llvm::IntrusiveRefCntPtr; +using llvm::LLVMContext; +using llvm::MemoryBuffer; +using llvm::Module; +using llvm::StringError; + +class CCompiler { +public: + CCompiler() { + // Setup custom diagnostic options. + auto DO = IntrusiveRefCntPtr(new DiagnosticOptions()); + DO->ShowColors = 1; + + // Setup stderr custom diagnostic consumer. + DC = std::make_unique(llvm::errs(), DO.get()); + + // Create custom diagnostics engine. + // The engine will NOT take ownership of the DiagnosticConsumer object. + DE = std::make_unique( + nullptr /* DiagnosticIDs */, std::move(DO), DC.get(), + false /* own DiagnosticConsumer */); + } + + struct CompileResult { + std::unique_ptr C; + std::unique_ptr M; + }; + + Expected compile(const char *code) const { + using std::errc; + const auto err = [](errc ec) { return std::make_error_code(ec); }; + + const char code_fname[] = "jit.c"; + + // Create compiler instance. + CompilerInstance CC; + + // Setup compiler invocation. + bool ok = CompilerInvocation::CreateFromArgs(CC.getInvocation(), + {code_fname}, *DE); + // We control the arguments, so we assert. + assert(ok); + + // Setup custom diagnostic printer. + CC.createDiagnostics(DC.get(), false /* own DiagnosticConsumer */); + + // Configure remapping from pseudo file name to in-memory code buffer + // code_fname -> code_buffer. + // + // PreprocessorOptions take ownership of MemoryBuffer. + CC.getPreprocessorOpts().addRemappedFile( + code_fname, MemoryBuffer::getMemBuffer(code).release()); + + // Configure codegen options. + auto &CG = CC.getCodeGenOpts(); + CG.OptimizationLevel = 3; + CG.setInlining(clang::CodeGenOptions::NormalInlining); + + // Generate LLVM IR. + EmitLLVMOnlyAction A; + if (!CC.ExecuteAction(A)) { + return llvm::make_error( + "Failed to generate LLVM IR from C code!", + err(errc::invalid_argument)); + } + + // Take generated LLVM IR module and the LLVMContext. + auto M = A.takeModule(); + auto C = std::unique_ptr(A.takeLLVMContext()); + + // TODO: Can this become nullptr when the action succeeds? + assert(M); + + return CompileResult{std::move(C), std::move(M)}; + } + +private: + std::unique_ptr DC; + std::unique_ptr DE; +}; + +} // namespace cc + +#endif -- cgit v1.2.3