aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc')
-rw-r--r--content/2022-06-18-libclang-c-to-llvm-ir/gen-ir.cc97
1 files changed, 97 insertions, 0 deletions
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 <clang/Basic/DiagnosticOptions.h>
+#include <clang/CodeGen/CodeGenAction.h>
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Frontend/TextDiagnosticPrinter.h>
+#include <clang/Lex/PreprocessorOptions.h>
+
+#include <llvm/IR/Module.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/TargetSelect.h>
+
+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<DiagnosticOptions> 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<DiagnosticConsumer> diag_print =
+ std::make_unique<TextDiagnosticPrinter>(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<DiagnosticsEngine>(
+ 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<const char*>({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<MemoryBuffer> 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;
+}