From 394366cf1c32aae428e588b262a9dc365d897a70 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Sat, 18 Jun 2022 19:41:38 +0200 Subject: clang: add post about in memory c -> llvm ir --- content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc (limited to 'content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc') diff --git a/content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc b/content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc new file mode 100644 index 0000000..a2055e4 --- /dev/null +++ b/content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +using clang::CompilerInstance; +using clang::CompilerInvocation; +using clang::DiagnosticConsumer; +using clang::DiagnosticOptions; +using clang::DiagnosticsEngine; +using clang::EmitLLVMOnlyAction; +using clang::TextDiagnosticPrinter; + +using llvm::ArrayRef; +using llvm::IntrusiveRefCntPtr; +using llvm::MemoryBuffer; + +int main() { + const char* code_fname = "jit.c"; + const char* code_input = + "struct S { int a; int b; };\n" + "void init(struct S* s) { s->a = 42; s->b = 1337; }\n"; + + // Setup custom diagnostic options. + IntrusiveRefCntPtr diag_opts(new DiagnosticOptions()); + diag_opts->ShowColors = 1; + + // Setup custom diagnostic consumer. + // + // We configure the consumer with our custom diagnostic options and set it + // up that diagnostic messages are printed to stderr. + std::unique_ptr diag_print = + std::make_unique(llvm::errs(), diag_opts.get()); + + // Create custom diagnostics engine. + // + // The engine will NOT take ownership of the DiagnosticConsumer object. + auto diag_eng = std::make_unique( + nullptr /* DiagnosticIDs */, diag_opts, diag_print.get(), + false /* own DiagnosticConsumer */); + + + // Create compiler instance. + CompilerInstance cc; + + // Setup compiler invocation. + // + // We are only passing a single argument, which is the pseudo file name for + // our code `code_fname`. We will be remapping this pseudo file name to an + // in-memory buffer via the preprocessor options below. + // + // The CompilerInvocation is a helper class which holds the data describing + // a compiler invocation (eg include paths, code generation options, + // warning flags, ..). + if (!CompilerInvocation::CreateFromArgs(cc.getInvocation(), + ArrayRef({code_fname}), + *diag_eng)) { + std::puts("Failed to create CompilerInvocation!"); + return 1; + } + + // Setup a TextDiagnosticPrinter printer with our diagnostic options to + // handle diagnostic messaged. + // + // The compiler will NOT take ownership of the DiagnosticConsumer object. + cc.createDiagnostics(diag_print.get(), false /* own DiagnosticConsumer */); + + // Create in-memory readonly buffer with pointing to our C code. + std::unique_ptr code_buffer = + MemoryBuffer::getMemBuffer(code_input); + // Configure remapping from pseudo file name to in-memory code buffer + // code_fname -> code_buffer. + // + // Ownership of the MemoryBuffer object is moved, except we would set + // `RetainRemappedFileBuffers = 1` in the PreprocessorOptions. + cc.getPreprocessorOpts().addRemappedFile(code_fname, code_buffer.release()); + + // Create action to generate LLVM IR. + EmitLLVMOnlyAction action; + // Run action against our compiler instance. + if (!cc.ExecuteAction(action)) { + std::puts("Failed to run EmitLLVMOnlyAction!"); + return 1; + } + + // Take generated LLVM IR module and print to stdout. + if (auto mod = action.takeModule()) { + mod->print(llvm::outs(), nullptr); + } + + return 0; +} -- cgit v1.2.3