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