Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
jit.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <lxsameer@lxsameer.com>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19/** @file
20
21 The JIT engine's C interface.
22
23 The implementation is a C++ translation unit built on LLVM's ORCv2 API. That
24 C++ and every LLVM type it touches stay behind this header, the rest of the
25 runtime, and any program embedding the runtime, see only the opaque handles
26 and the free functions declared here. We intentionally didn't use the C api
27 of ORC as it lags behind usually and the documentation of the C++ is way better.
28
29 Code enters the JIT as a buffer of LLVM IR rather than through an IR-building
30 interface, so producers hand over bytes and never link against LLVM. A producer
31 stamps its module with the target data layout and triple reported by `srn_jit_data_layout`
32 and `srn_jit_triple`, a module whose layout disagrees with the JIT is rejected.
33
34 The compile and run cycle is: create a JIT, register the runtime symbols that
35 generated code calls (`srn_jit_define`), add one or more IR modules
36 (`srn_jit_add_ir`), then look a compiled symbol up by name (`srn_jit_lookup`)
37 and call it through the address returned. Adding and looking up are safe to
38 drive from more than one thread.
39*/
40
41#pragma once
42
43#include <stddef.h>
44
45#include "serene/rt/errors.h"
46
47#ifdef __cplusplus
48extern "C" {
49#endif
50
51typedef struct srn_mm_t srn_mm_t;
52
53/**
54 * An opaque handle to a live JIT engine, owning the underlying llvm orc session.
55 */
56typedef struct srn_jit_t srn_jit_t;
57
58/**
59 * An opaque handle to our object cache that utilizes llvm's ObjectCache
60 */
62
63/**
64 * An opaque handle to one unit of code added to the JIT. Returned by the add
65 * functions and passed back to `srn_jit_remove` to unload that unit. A module
66 * handle stays valid until it is removed or the owning JIT is destroyed.
67 */
69
70/**
71 * Tuning for a JIT engine, passed to `srn_jit_create`. A null config selects
72 * the defaults (optimisation level 2, default pipeline installed).
73 */
74typedef struct srn_jit_config_t {
75 /// Optimisation level applied to added modules, 0 (none) through 3.
77 /// When true, the default middle-end optimisation pipeline runs over each
78 /// module before it is compiled; when false, modules are compiled as
79 /// emitted.
82
83/**
84 * Create a JIT engine backed by a fresh ORC session, allocating from `mm`.
85 * `config` may be null to take the defaults. Returns null when the native
86 * target cannot be initialised or the engine cannot be built.
87 */
88[[gnu::nonnull(1)]]
90
91/**
92 * Destroy `jit`, tearing down its ORC session and releasing every module it
93 * still holds. A null `jit` is a no-op.
94 */
96
97/**
98 * The target data-layout string the JIT compiles against. A producer must
99 * stamp every module it adds with this layout. The string is owned by `jit`
100 * and stays valid until the engine is destroyed.
101 */
102[[gnu::nonnull(1)]]
104
105/**
106 * The target triple the JIT compiles for. Owned by `jit` and valid until the
107 * engine is destroyed.
108 */
109[[gnu::nonnull(1)]]
110const char *srn_jit_triple(srn_jit_t *jit);
111
112/**
113 * Parse the textual LLVM IR in `ir` (of length `len`) and add it to `jit` for
114 * compilation. On success returns null; when `out` is non-null it receives a
115 * handle to the added module. On failure returns an error allocated in `ctx`
116 * and leaves `out` untouched.
117 */
118[[gnu::nonnull(1, 2, 3)]]
120 srn_jit_t *jit, srn_context_t *ctx, const char *ir, size_t len, srn_jit_module_t **out
121);
122
123/**
124 * Add the LLVM bitcode in `buf` (of length `len`) to `jit` for compilation.
125 * Behaves like `srn_jit_add_ir` but reads the binary bitcode encoding rather
126 * than text.
127 */
128[[gnu::nonnull(1, 2, 3)]]
130 srn_jit_t *jit, srn_context_t *ctx, const void *buf, size_t len, srn_jit_module_t **out
131);
132
133/**
134 * Define the absolute symbol `name` in the JIT as resolving to `addr`, so
135 * generated code can call a runtime function or reach a piece of runtime data
136 * by that name. Returns null on success, or an error allocated in `ctx` when
137 * the symbol already exists.
138 */
139[[gnu::nonnull(1, 2, 3, 4)]]
140srn_error_t *srn_jit_define(srn_jit_t *jit, srn_context_t *ctx, const char *name, void *addr);
141
142/**
143 * Make the symbols already linked into the running process resolvable from
144 * generated code, so runtime functions need not be registered one at a time.
145 * Returns null on success or an error allocated in `ctx`.
146 */
147[[gnu::nonnull(1, 2)]]
149
150/**
151 * Look up the compiled symbol `name`, forcing its module to compile if it has
152 * not already, and write its address to `*out_addr`. The caller casts that
153 * address to the matching function or data pointer. Returns null on success,
154 * or an error allocated in `ctx` when the symbol is absent.
155 */
156[[gnu::nonnull(1, 2, 3, 4)]]
157srn_error_t *srn_jit_lookup(srn_jit_t *jit, srn_context_t *ctx, const char *name, void **out_addr);
158
159/**
160 * Unload `module` from `jit`, removing the symbols it defined and freeing the
161 * code it compiled. Returns null on success or an error allocated in `ctx`.
162 */
163[[gnu::nonnull(1, 2, 3)]]
165
166#ifdef __cplusplus
167}
168#endif
Error handling for the runtime.
srn_jit_t * srn_jit_create(srn_mm_t *mm, const srn_jit_config_t *config)
Create a JIT engine backed by a fresh ORC session, allocating from mm.
srn_error_t * srn_jit_add_bitcode(srn_jit_t *jit, srn_context_t *ctx, const void *buf, size_t len, srn_jit_module_t **out)
Add the LLVM bitcode in buf (of length len) to jit for compilation.
struct srn_jit_t srn_jit_t
An opaque handle to a live JIT engine, owning the underlying llvm orc session.
Definition jit.h:56
const char * srn_jit_data_layout(srn_jit_t *jit)
The target data-layout string the JIT compiles against.
const char * srn_jit_triple(srn_jit_t *jit)
The target triple the JIT compiles for.
srn_error_t * srn_jit_lookup(srn_jit_t *jit, srn_context_t *ctx, const char *name, void **out_addr)
Look up the compiled symbol name, forcing its module to compile if it has not already,...
void srn_jit_destroy(srn_jit_t *jit)
Destroy jit, tearing down its ORC session and releasing every module it still holds.
srn_error_t * srn_jit_remove(srn_jit_t *jit, srn_context_t *ctx, srn_jit_module_t *module)
Unload module from jit, removing the symbols it defined and freeing the code it compiled.
srn_error_t * srn_jit_expose_process_symbols(srn_jit_t *jit, srn_context_t *ctx)
Make the symbols already linked into the running process resolvable from generated code,...
srn_error_t * srn_jit_define(srn_jit_t *jit, srn_context_t *ctx, const char *name, void *addr)
Define the absolute symbol name in the JIT as resolving to addr, so generated code can call a runtime...
struct srn_jit_module_t srn_jit_module_t
An opaque handle to one unit of code added to the JIT.
Definition jit.h:68
struct srn_object_cache_t srn_object_cache_t
An opaque handle to our object cache that utilizes llvm's ObjectCache.
Definition jit.h:61
srn_error_t * srn_jit_add_ir(srn_jit_t *jit, srn_context_t *ctx, const char *ir, size_t len, srn_jit_module_t **out)
Parse the textual LLVM IR in ir (of length len) and add it to jit for compilation.
A runtime error, a tag classifying the failure and a human-readable message.
Definition errors.h:147
Tuning for a JIT engine, passed to srn_jit_create.
Definition jit.h:74
int opt_level
Optimisation level applied to added modules, 0 (none) through 3.
Definition jit.h:76
bool install_default_pipeline
When true, the default middle-end optimisation pipeline runs over each module before it is compiled; ...
Definition jit.h:80
Main memory manager structure that will own all the allocated blocks and data.
Definition interface.h:110