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-2023, 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 124882 : l_ptr_const(void *ptr, LLVMTypeRef type)
29 : {
30 124882 : LLVMValueRef c = LLVMConstInt(TypeSizeT, (uintptr_t) ptr, false);
31 :
32 124882 : return LLVMConstIntToPtr(c, type);
33 : }
34 :
35 : /*
36 : * Emit pointer.
37 : */
38 : static inline LLVMTypeRef
39 158376 : l_ptr(LLVMTypeRef t)
40 : {
41 158376 : return LLVMPointerType(t, 0);
42 : }
43 :
44 : /*
45 : * Emit constant integer.
46 : */
47 : static inline LLVMValueRef
48 50694 : l_int8_const(LLVMContextRef lc, int8 i)
49 : {
50 50694 : return LLVMConstInt(LLVMInt8TypeInContext(lc), i, false);
51 : }
52 :
53 : /*
54 : * Emit constant integer.
55 : */
56 : static inline LLVMValueRef
57 71608 : l_int16_const(LLVMContextRef lc, int16 i)
58 : {
59 71608 : return LLVMConstInt(LLVMInt16TypeInContext(lc), i, false);
60 : }
61 :
62 : /*
63 : * Emit constant integer.
64 : */
65 : static inline LLVMValueRef
66 45424 : l_int32_const(LLVMContextRef lc, int32 i)
67 : {
68 45424 : return LLVMConstInt(LLVMInt32TypeInContext(lc), i, false);
69 : }
70 :
71 : /*
72 : * Emit constant integer.
73 : */
74 : static inline LLVMValueRef
75 10616 : l_int64_const(LLVMContextRef lc, int64 i)
76 : {
77 10616 : return LLVMConstInt(LLVMInt64TypeInContext(lc), i, false);
78 : }
79 :
80 : /*
81 : * Emit constant integer.
82 : */
83 : static inline LLVMValueRef
84 55594 : l_sizet_const(size_t i)
85 : {
86 55594 : 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 28684 : l_sbool_const(bool i)
94 : {
95 28684 : 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 300320 : l_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
109 : {
110 : #if LLVM_VERSION_MAJOR < 16
111 300320 : return LLVMBuildStructGEP(b, v, idx, "");
112 : #else
113 : return LLVMBuildStructGEP2(b, t, v, idx, "");
114 : #endif
115 : }
116 :
117 : static inline LLVMValueRef
118 131014 : l_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef *indices, int32 nindices, const char *name)
119 : {
120 : #if LLVM_VERSION_MAJOR < 16
121 131014 : 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 373634 : l_load(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, const char *name)
129 : {
130 : #if LLVM_VERSION_MAJOR < 16
131 373634 : return LLVMBuildLoad(b, v, name);
132 : #else
133 : return LLVMBuildLoad2(b, t, v, name);
134 : #endif
135 : }
136 :
137 : static inline LLVMValueRef
138 35862 : l_call(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef fn, LLVMValueRef *args, int32 nargs, const char *name)
139 : {
140 : #if LLVM_VERSION_MAJOR < 16
141 35862 : 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 210178 : l_load_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
152 : {
153 210178 : 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 42468 : l_load_gep1(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef idx, const char *name)
164 : {
165 42468 : 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 27132 : l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...)
177 : {
178 : char buf[512];
179 : va_list args;
180 : LLVMContextRef lc;
181 :
182 27132 : va_start(args, fmt);
183 27132 : vsnprintf(buf, sizeof(buf), fmt, args);
184 27132 : va_end(args);
185 :
186 27132 : lc = LLVMGetTypeContext(LLVMTypeOf(LLVMGetBasicBlockParent(r)));
187 :
188 27132 : 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 129782 : l_bb_append_v(LLVMValueRef f, const char *fmt,...)
200 : {
201 : char buf[512];
202 : va_list args;
203 : LLVMContextRef lc;
204 :
205 129782 : va_start(args, fmt);
206 129782 : vsnprintf(buf, sizeof(buf), fmt, args);
207 129782 : va_end(args);
208 :
209 129782 : lc = LLVMGetTypeContext(LLVMTypeOf(f));
210 :
211 129782 : return LLVMAppendBasicBlockInContext(lc, f, buf);
212 : }
213 :
214 : /*
215 : * Mark a callsite as readonly.
216 : */
217 : static inline void
218 1944 : l_callsite_ro(LLVMValueRef f)
219 : {
220 1944 : const char argname[] = "readonly";
221 : LLVMAttributeRef ref;
222 :
223 1944 : ref = LLVMCreateStringAttribute(LLVMGetTypeContext(LLVMTypeOf(f)),
224 : argname,
225 : sizeof(argname) - 1,
226 : NULL, 0);
227 :
228 1944 : LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, ref);
229 1944 : }
230 :
231 : /*
232 : * Mark a callsite as alwaysinline.
233 : */
234 : static inline void
235 1944 : l_callsite_alwaysinline(LLVMValueRef f)
236 : {
237 1944 : const char argname[] = "alwaysinline";
238 : int id;
239 : LLVMAttributeRef attr;
240 :
241 1944 : id = LLVMGetEnumAttributeKindForName(argname,
242 : sizeof(argname) - 1);
243 1944 : attr = LLVMCreateEnumAttribute(LLVMGetTypeContext(LLVMTypeOf(f)), id, 0);
244 1944 : LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, attr);
245 1944 : }
246 :
247 : /*
248 : * Emit code to switch memory context.
249 : */
250 : static inline LLVMValueRef
251 3174 : l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
252 : {
253 3174 : const char *cmc = "CurrentMemoryContext";
254 : LLVMValueRef cur;
255 : LLVMValueRef ret;
256 :
257 3174 : if (!(cur = LLVMGetNamedGlobal(mod, cmc)))
258 482 : cur = LLVMAddGlobal(mod, l_ptr(StructMemoryContextData), cmc);
259 3174 : ret = l_load(b, l_ptr(StructMemoryContextData), cur, cmc);
260 3174 : LLVMBuildStore(b, nc, cur);
261 :
262 3174 : return ret;
263 : }
264 :
265 : /*
266 : * Return pointer to the argno'th argument nullness.
267 : */
268 : static inline LLVMValueRef
269 8922 : l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
270 : {
271 : LLVMValueRef v_args;
272 : LLVMValueRef v_argn;
273 :
274 8922 : v_args = l_struct_gep(b,
275 : StructFunctionCallInfoData,
276 : v_fcinfo,
277 : FIELDNO_FUNCTIONCALLINFODATA_ARGS,
278 : "");
279 8922 : v_argn = l_struct_gep(b,
280 : LLVMArrayType(StructNullableDatum, 0),
281 : v_args,
282 : argno,
283 : "");
284 8922 : 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 1686 : l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
296 : {
297 : LLVMValueRef v_args;
298 : LLVMValueRef v_argn;
299 :
300 1686 : v_args = l_struct_gep(b,
301 : StructFunctionCallInfoData,
302 : v_fcinfo,
303 : FIELDNO_FUNCTIONCALLINFODATA_ARGS,
304 : "");
305 1686 : v_argn = l_struct_gep(b,
306 : LLVMArrayType(StructNullableDatum, 0),
307 : v_args,
308 : argno,
309 : "");
310 1686 : 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 7236 : l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
322 : {
323 7236 : 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
|