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