Branch data Line data Source code
1 : : /*
2 : : * llvmjit_emit.h
3 : : * Helpers to make emitting LLVM IR a bit more concise and pgindent proof.
4 : : *
5 : : * Copyright (c) 2018-2026, PostgreSQL Global Development Group
6 : : *
7 : : * src/include/jit/llvmjit_emit.h
8 : : */
9 : : #ifndef LLVMJIT_EMIT_H
10 : : #define LLVMJIT_EMIT_H
11 : :
12 : : /*
13 : : * To avoid breaking cpluspluscheck, allow including the file even when LLVM
14 : : * is not available.
15 : : */
16 : : #ifdef USE_LLVM
17 : :
18 : : #include <llvm-c/Core.h>
19 : : #include <llvm-c/Target.h>
20 : :
21 : : #include "jit/llvmjit.h"
22 : :
23 : :
24 : : /*
25 : : * Emit a non-LLVM pointer as an LLVM constant.
26 : : */
27 : : static inline LLVMValueRef
28 : 0 : l_ptr_const(void *ptr, LLVMTypeRef type)
29 : : {
30 : 0 : LLVMValueRef c = LLVMConstInt(TypeSizeT, (uintptr_t) ptr, false);
31 : :
32 : 0 : return LLVMConstIntToPtr(c, type);
33 : : }
34 : :
35 : : /*
36 : : * Emit pointer.
37 : : */
38 : : static inline LLVMTypeRef
39 : 0 : l_ptr(LLVMTypeRef t)
40 : : {
41 : 0 : return LLVMPointerType(t, 0);
42 : : }
43 : :
44 : : /*
45 : : * Emit constant integer.
46 : : */
47 : : static inline LLVMValueRef
48 : 0 : l_int8_const(LLVMContextRef lc, int8 i)
49 : : {
50 : 0 : return LLVMConstInt(LLVMInt8TypeInContext(lc), i, false);
51 : : }
52 : :
53 : : /*
54 : : * Emit constant integer.
55 : : */
56 : : static inline LLVMValueRef
57 : 0 : l_int16_const(LLVMContextRef lc, int16 i)
58 : : {
59 : 0 : return LLVMConstInt(LLVMInt16TypeInContext(lc), i, false);
60 : : }
61 : :
62 : : /*
63 : : * Emit constant integer.
64 : : */
65 : : static inline LLVMValueRef
66 : 0 : l_int32_const(LLVMContextRef lc, int32 i)
67 : : {
68 : 0 : return LLVMConstInt(LLVMInt32TypeInContext(lc), i, false);
69 : : }
70 : :
71 : : /*
72 : : * Emit constant integer.
73 : : */
74 : : static inline LLVMValueRef
75 : 0 : l_int64_const(LLVMContextRef lc, int64 i)
76 : : {
77 : 0 : return LLVMConstInt(LLVMInt64TypeInContext(lc), i, false);
78 : : }
79 : :
80 : : /*
81 : : * Emit constant integer.
82 : : */
83 : : static inline LLVMValueRef
84 : 0 : l_sizet_const(size_t i)
85 : : {
86 : 0 : return LLVMConstInt(TypeSizeT, i, false);
87 : : }
88 : :
89 : : /*
90 : : * Emit constant integer.
91 : : */
92 : : static inline LLVMValueRef
93 : 0 : l_datum_const(Datum i)
94 : : {
95 : 0 : return LLVMConstInt(TypeDatum, i, false);
96 : : }
97 : :
98 : : /*
99 : : * Emit constant boolean, as used for storage (e.g. global vars, structs).
100 : : */
101 : : static inline LLVMValueRef
102 : 0 : l_sbool_const(bool i)
103 : : {
104 : 0 : return LLVMConstInt(TypeStorageBool, (int) i, false);
105 : : }
106 : :
107 : : /*
108 : : * Emit constant boolean, as used for parameters (e.g. function parameters).
109 : : */
110 : : static inline LLVMValueRef
111 : : l_pbool_const(bool i)
112 : : {
113 : : return LLVMConstInt(TypeParamBool, (int) i, false);
114 : : }
115 : :
116 : : static inline LLVMValueRef
117 : 0 : l_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
118 : : {
119 : 0 : return LLVMBuildStructGEP2(b, t, v, idx, "");
120 : : }
121 : :
122 : : static inline LLVMValueRef
123 : 0 : l_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef *indices, int32 nindices, const char *name)
124 : : {
125 : 0 : return LLVMBuildGEP2(b, t, v, indices, nindices, name);
126 : : }
127 : :
128 : : static inline LLVMValueRef
129 : 0 : l_load(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, const char *name)
130 : : {
131 : 0 : return LLVMBuildLoad2(b, t, v, name);
132 : : }
133 : :
134 : : static inline LLVMValueRef
135 : 0 : l_call(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef fn, LLVMValueRef *args, int32 nargs, const char *name)
136 : : {
137 : 0 : return LLVMBuildCall2(b, t, fn, args, nargs, name);
138 : : }
139 : :
140 : : /*
141 : : * Load a pointer member idx from a struct.
142 : : */
143 : : static inline LLVMValueRef
144 : 0 : l_load_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
145 : : {
146 : 0 : return l_load(b,
147 : : LLVMStructGetTypeAtIndex(t, idx),
148 : : l_struct_gep(b, t, v, idx, ""),
149 : : name);
150 : : }
151 : :
152 : : /*
153 : : * Load value of a pointer, after applying one index operation.
154 : : */
155 : : static inline LLVMValueRef
156 : 0 : l_load_gep1(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef idx, const char *name)
157 : : {
158 : 0 : return l_load(b, t, l_gep(b, t, v, &idx, 1, ""), name);
159 : : }
160 : :
161 : : /* separate, because pg_attribute_printf(2, 3) can't appear in definition */
162 : : static inline LLVMBasicBlockRef l_bb_before_v(LLVMBasicBlockRef r, const char *fmt, ...) pg_attribute_printf(2, 3);
163 : :
164 : : /*
165 : : * Insert a new basic block, just before r, the name being determined by fmt
166 : : * and arguments.
167 : : */
168 : : static inline LLVMBasicBlockRef
169 : 0 : l_bb_before_v(LLVMBasicBlockRef r, const char *fmt, ...)
170 : : {
171 : : char buf[512];
172 : : va_list args;
173 : : LLVMContextRef lc;
174 : :
175 : 0 : va_start(args, fmt);
176 : 0 : vsnprintf(buf, sizeof(buf), fmt, args);
177 : 0 : va_end(args);
178 : :
179 : 0 : lc = LLVMGetTypeContext(LLVMTypeOf(LLVMGetBasicBlockParent(r)));
180 : :
181 : 0 : return LLVMInsertBasicBlockInContext(lc, r, buf);
182 : : }
183 : :
184 : : /* separate, because pg_attribute_printf(2, 3) can't appear in definition */
185 : : static inline LLVMBasicBlockRef l_bb_append_v(LLVMValueRef f, const char *fmt, ...) pg_attribute_printf(2, 3);
186 : :
187 : : /*
188 : : * Insert a new basic block after previous basic blocks, the name being
189 : : * determined by fmt and arguments.
190 : : */
191 : : static inline LLVMBasicBlockRef
192 : 0 : l_bb_append_v(LLVMValueRef f, const char *fmt, ...)
193 : : {
194 : : char buf[512];
195 : : va_list args;
196 : : LLVMContextRef lc;
197 : :
198 : 0 : va_start(args, fmt);
199 : 0 : vsnprintf(buf, sizeof(buf), fmt, args);
200 : 0 : va_end(args);
201 : :
202 : 0 : lc = LLVMGetTypeContext(LLVMTypeOf(f));
203 : :
204 : 0 : return LLVMAppendBasicBlockInContext(lc, f, buf);
205 : : }
206 : :
207 : : /*
208 : : * Mark a callsite as readonly.
209 : : */
210 : : static inline void
211 : 0 : l_callsite_ro(LLVMValueRef f)
212 : : {
213 : 0 : const char argname[] = "readonly";
214 : : LLVMAttributeRef ref;
215 : :
216 : 0 : ref = LLVMCreateStringAttribute(LLVMGetTypeContext(LLVMTypeOf(f)),
217 : : argname,
218 : : sizeof(argname) - 1,
219 : : NULL, 0);
220 : :
221 : 0 : LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, ref);
222 : 0 : }
223 : :
224 : : /*
225 : : * Mark a callsite as alwaysinline.
226 : : */
227 : : static inline void
228 : 0 : l_callsite_alwaysinline(LLVMValueRef f)
229 : : {
230 : 0 : const char argname[] = "alwaysinline";
231 : : int id;
232 : : LLVMAttributeRef attr;
233 : :
234 : 0 : id = LLVMGetEnumAttributeKindForName(argname,
235 : : sizeof(argname) - 1);
236 : 0 : attr = LLVMCreateEnumAttribute(LLVMGetTypeContext(LLVMTypeOf(f)), id, 0);
237 : 0 : LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, attr);
238 : 0 : }
239 : :
240 : : /*
241 : : * Emit code to switch memory context.
242 : : */
243 : : static inline LLVMValueRef
244 : 0 : l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
245 : : {
246 : 0 : const char *cmc = "CurrentMemoryContext";
247 : : LLVMValueRef cur;
248 : : LLVMValueRef ret;
249 : :
250 [ # # ]: 0 : if (!(cur = LLVMGetNamedGlobal(mod, cmc)))
251 : 0 : cur = LLVMAddGlobal(mod, l_ptr(StructMemoryContextData), cmc);
252 : 0 : ret = l_load(b, l_ptr(StructMemoryContextData), cur, cmc);
253 : 0 : LLVMBuildStore(b, nc, cur);
254 : :
255 : 0 : return ret;
256 : : }
257 : :
258 : : /*
259 : : * Return pointer to the argno'th argument nullness.
260 : : */
261 : : static inline LLVMValueRef
262 : 0 : l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
263 : : {
264 : : LLVMValueRef v_args;
265 : : LLVMValueRef v_argn;
266 : :
267 : 0 : v_args = l_struct_gep(b,
268 : : StructFunctionCallInfoData,
269 : : v_fcinfo,
270 : : FIELDNO_FUNCTIONCALLINFODATA_ARGS,
271 : : "");
272 : 0 : v_argn = l_struct_gep(b,
273 : : LLVMArrayType(StructNullableDatum, 0),
274 : : v_args,
275 : : argno,
276 : : "");
277 : 0 : return l_struct_gep(b,
278 : : StructNullableDatum,
279 : : v_argn,
280 : : FIELDNO_NULLABLE_DATUM_ISNULL,
281 : : "");
282 : : }
283 : :
284 : : /*
285 : : * Return pointer to the argno'th argument datum.
286 : : */
287 : : static inline LLVMValueRef
288 : 0 : l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
289 : : {
290 : : LLVMValueRef v_args;
291 : : LLVMValueRef v_argn;
292 : :
293 : 0 : v_args = l_struct_gep(b,
294 : : StructFunctionCallInfoData,
295 : : v_fcinfo,
296 : : FIELDNO_FUNCTIONCALLINFODATA_ARGS,
297 : : "");
298 : 0 : v_argn = l_struct_gep(b,
299 : : LLVMArrayType(StructNullableDatum, 0),
300 : : v_args,
301 : : argno,
302 : : "");
303 : 0 : return l_struct_gep(b,
304 : : StructNullableDatum,
305 : : v_argn,
306 : : FIELDNO_NULLABLE_DATUM_DATUM,
307 : : "");
308 : : }
309 : :
310 : : /*
311 : : * Return argno'th argument nullness.
312 : : */
313 : : static inline LLVMValueRef
314 : 0 : l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
315 : : {
316 : 0 : return l_load(b, TypeStorageBool, l_funcnullp(b, v_fcinfo, argno), "");
317 : : }
318 : :
319 : : /*
320 : : * Return argno'th argument datum.
321 : : */
322 : : static inline LLVMValueRef
323 : 0 : l_funcvalue(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
324 : : {
325 : 0 : return l_load(b, TypeDatum, l_funcvaluep(b, v_fcinfo, argno), "");
326 : : }
327 : :
328 : : #endif /* USE_LLVM */
329 : : #endif
|