Lime Parser Generator 0.1.0
Runtime-extensible LALR(1) parser with SIMD tokenization and LLVM JIT
Loading...
Searching...
No Matches
jit_llvm_compat.h
1/*
2** jit_llvm_compat.h -- LLVM C API compatibility shims for Lime.
3**
4** Lime declares a minimum LLVM version of 14. Three LLVM C APIs that
5** Lime uses changed across that range, so we hide the version split
6** here:
7**
8** * New PassBuilder API (LLVMRunPasses, LLVMPassBuilderOptionsRef)
9** is present from LLVM 16 onward. On LLVM 14-15 we fall back to
10** the legacy LLVMPassManagerBuilder + LLVMPassManager combo.
11** LLVMPassManagerBuilder itself was removed from the C API in
12** LLVM 17, so these are complementary: legacy for 14-15, modern
13** for 16+.
14**
15** * LLVMOrcCreateNewThreadSafeContextFromLLVMContext() was added in
16** LLVM 15. On LLVM 14 we have to create the ThreadSafeContext
17** first and then extract its internal LLVMContextRef. In both
18** cases the ThreadSafeContext owns the LLVMContext, so teardown
19** is just LLVMOrcDisposeThreadSafeContext().
20**
21** * LLVMOrcLLJITLookup() takes an LLVMOrcJITTargetAddress * in
22** LLVM 14 and an LLVMOrcExecutorAddress * in LLVM 15+. Both are
23** uint64_t, just differently named. LimeJitAddress aliases to
24** whichever name the current LLVM exposes.
25**
26** Any code that runs the O2 pass pipeline, creates a thread-safe
27** context, or calls LLVMOrcLLJITLookup should use the helpers defined
28** here instead of the underlying LLVM symbols directly.
29*/
30
31#ifndef LIME_JIT_LLVM_COMPAT_H
32#define LIME_JIT_LLVM_COMPAT_H
33
34#ifndef LIME_NO_JIT
35
36/* LLVM_VERSION_MAJOR / _MINOR / _PATCH come from here. The header
37** lives under the C++ include path but contains only #defines, so it
38** is usable from C translation units. */
39#include <llvm/Config/llvm-config.h>
40
41#include <stdbool.h>
42#include <stddef.h>
43
44#include <llvm-c/Core.h>
45#include <llvm-c/Orc.h>
46
47#if LLVM_VERSION_MAJOR >= 16
48#include <llvm-c/Transforms/PassBuilder.h>
49#else
50#include <llvm-c/Transforms/PassManagerBuilder.h>
51#endif
52
53/*
54** LIME_JIT_RUN_O2_PASSES(module)
55**
56** Run the -O2 optimisation pipeline over the given LLVM module.
57** Evaluates `module` exactly once. Void-returning; does not signal
58** failure (the legacy path has no status channel, and the new path's
59** LLVMErrorRef return is ignored to keep the call-site symmetrical --
60** revisit if we ever care about pipeline setup errors).
61*/
62#if LLVM_VERSION_MAJOR >= 16
63
64#define LIME_JIT_RUN_O2_PASSES(module) \
65 do { \
66 LLVMModuleRef _lime_mod = (module); \
67 LLVMPassBuilderOptionsRef _lime_opts = \
68 LLVMCreatePassBuilderOptions(); \
69 LLVMErrorRef _lime_err = \
70 LLVMRunPasses(_lime_mod, "default<O2>", NULL, _lime_opts); \
71 if (_lime_err != LLVMErrorSuccess) { \
72 char *_lime_msg = LLVMGetErrorMessage(_lime_err); \
73 LLVMDisposeErrorMessage(_lime_msg); \
74 } \
75 LLVMDisposePassBuilderOptions(_lime_opts); \
76 } while (0)
77
78#else /* LLVM 14 / 15 -- legacy PassManagerBuilder */
79
80#define LIME_JIT_RUN_O2_PASSES(module) \
81 do { \
82 LLVMModuleRef _lime_mod = (module); \
83 LLVMPassManagerBuilderRef _lime_pmb = \
84 LLVMPassManagerBuilderCreate(); \
85 LLVMPassManagerBuilderSetOptLevel(_lime_pmb, 2); \
86 LLVMPassManagerRef _lime_pm = LLVMCreatePassManager(); \
87 LLVMPassManagerBuilderPopulateModulePassManager(_lime_pmb, \
88 _lime_pm); \
89 LLVMRunPassManager(_lime_pm, _lime_mod); \
90 LLVMDisposePassManager(_lime_pm); \
91 LLVMPassManagerBuilderDispose(_lime_pmb); \
92 } while (0)
93
94#endif /* LLVM_VERSION_MAJOR >= 16 */
95
96/*
97** LimeJitAddress -- the uint64_t-sized type LLVMOrcLLJITLookup writes
98** its result into. Use this type at every LLVMOrcLLJITLookup call
99** site; it resolves to whichever name the current LLVM headers
100** expose.
101*/
102#if LLVM_VERSION_MAJOR >= 15
103typedef LLVMOrcExecutorAddress LimeJitAddress;
104#else
105typedef LLVMOrcJITTargetAddress LimeJitAddress;
106#endif
107
108/*
109** lime_jit_create_ts_ctx()
110**
111** Create a ThreadSafeContext and return both it and its internal
112** LLVMContextRef. On success, *ts_ctx_out owns the returned
113** llvm_ctx_out -- callers must dispose only *ts_ctx_out during
114** teardown. Returns false on allocation failure, in which case
115** neither out-parameter is touched.
116*/
117static inline bool lime_jit_create_ts_ctx(
118 LLVMOrcThreadSafeContextRef *ts_ctx_out,
119 LLVMContextRef *llvm_ctx_out)
120{
121#if LLVM_VERSION_MAJOR >= 15
122 LLVMContextRef llvm_ctx = LLVMContextCreate();
123 if (llvm_ctx == NULL) {
124 return false;
125 }
126 LLVMOrcThreadSafeContextRef ts_ctx =
127 LLVMOrcCreateNewThreadSafeContextFromLLVMContext(llvm_ctx);
128 if (ts_ctx == NULL) {
129 LLVMContextDispose(llvm_ctx);
130 return false;
131 }
132#else
133 /* LLVM 14: no way to wrap an externally-created context; the
134 ** ThreadSafeContext creates and owns its own LLVMContext, which
135 ** we then fetch via the getter. */
136 LLVMOrcThreadSafeContextRef ts_ctx = LLVMOrcCreateNewThreadSafeContext();
137 if (ts_ctx == NULL) {
138 return false;
139 }
140 LLVMContextRef llvm_ctx = LLVMOrcThreadSafeContextGetContext(ts_ctx);
141 if (llvm_ctx == NULL) {
142 LLVMOrcDisposeThreadSafeContext(ts_ctx);
143 return false;
144 }
145#endif
146 *ts_ctx_out = ts_ctx;
147 *llvm_ctx_out = llvm_ctx;
148 return true;
149}
150
151#endif /* !LIME_NO_JIT */
152
153#endif /* LIME_JIT_LLVM_COMPAT_H */