PostgreSQL Source Code  git master
llvmjit_emit.h
Go to the documentation of this file.
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 l_ptr_const(void *ptr, LLVMTypeRef type)
29 {
30  LLVMValueRef c = LLVMConstInt(TypeSizeT, (uintptr_t) ptr, false);
31 
32  return LLVMConstIntToPtr(c, type);
33 }
34 
35 /*
36  * Emit pointer.
37  */
38 static inline LLVMTypeRef
39 l_ptr(LLVMTypeRef t)
40 {
41  return LLVMPointerType(t, 0);
42 }
43 
44 /*
45  * Emit constant integer.
46  */
47 static inline LLVMValueRef
48 l_int8_const(LLVMContextRef lc, int8 i)
49 {
50  return LLVMConstInt(LLVMInt8TypeInContext(lc), i, false);
51 }
52 
53 /*
54  * Emit constant integer.
55  */
56 static inline LLVMValueRef
57 l_int16_const(LLVMContextRef lc, int16 i)
58 {
59  return LLVMConstInt(LLVMInt16TypeInContext(lc), i, false);
60 }
61 
62 /*
63  * Emit constant integer.
64  */
65 static inline LLVMValueRef
66 l_int32_const(LLVMContextRef lc, int32 i)
67 {
68  return LLVMConstInt(LLVMInt32TypeInContext(lc), i, false);
69 }
70 
71 /*
72  * Emit constant integer.
73  */
74 static inline LLVMValueRef
75 l_int64_const(LLVMContextRef lc, int64 i)
76 {
77  return LLVMConstInt(LLVMInt64TypeInContext(lc), i, false);
78 }
79 
80 /*
81  * Emit constant integer.
82  */
83 static inline LLVMValueRef
84 l_sizet_const(size_t i)
85 {
86  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 l_sbool_const(bool i)
94 {
95  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 l_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
109 {
110 #if LLVM_VERSION_MAJOR < 16
111  return LLVMBuildStructGEP(b, v, idx, "");
112 #else
113  return LLVMBuildStructGEP2(b, t, v, idx, "");
114 #endif
115 }
116 
117 static inline LLVMValueRef
118 l_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef *indices, int32 nindices, const char *name)
119 {
120 #if LLVM_VERSION_MAJOR < 16
121  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 l_load(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, const char *name)
129 {
130 #if LLVM_VERSION_MAJOR < 16
131  return LLVMBuildLoad(b, v, name);
132 #else
133  return LLVMBuildLoad2(b, t, v, name);
134 #endif
135 }
136 
137 static inline LLVMValueRef
138 l_call(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef fn, LLVMValueRef *args, int32 nargs, const char *name)
139 {
140 #if LLVM_VERSION_MAJOR < 16
141  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 l_load_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
152 {
153  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 l_load_gep1(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef idx, const char *name)
164 {
165  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 l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...)
177 {
178  char buf[512];
179  va_list args;
180  LLVMContextRef lc;
181 
182  va_start(args, fmt);
183  vsnprintf(buf, sizeof(buf), fmt, args);
184  va_end(args);
185 
186  lc = LLVMGetTypeContext(LLVMTypeOf(LLVMGetBasicBlockParent(r)));
187 
188  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 l_bb_append_v(LLVMValueRef f, const char *fmt,...)
200 {
201  char buf[512];
202  va_list args;
203  LLVMContextRef lc;
204 
205  va_start(args, fmt);
206  vsnprintf(buf, sizeof(buf), fmt, args);
207  va_end(args);
208 
209  lc = LLVMGetTypeContext(LLVMTypeOf(f));
210 
211  return LLVMAppendBasicBlockInContext(lc, f, buf);
212 }
213 
214 /*
215  * Mark a callsite as readonly.
216  */
217 static inline void
218 l_callsite_ro(LLVMValueRef f)
219 {
220  const char argname[] = "readonly";
221  LLVMAttributeRef ref;
222 
223  ref = LLVMCreateStringAttribute(LLVMGetTypeContext(LLVMTypeOf(f)),
224  argname,
225  sizeof(argname) - 1,
226  NULL, 0);
227 
228  LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, ref);
229 }
230 
231 /*
232  * Mark a callsite as alwaysinline.
233  */
234 static inline void
235 l_callsite_alwaysinline(LLVMValueRef f)
236 {
237  const char argname[] = "alwaysinline";
238  int id;
239  LLVMAttributeRef attr;
240 
241  id = LLVMGetEnumAttributeKindForName(argname,
242  sizeof(argname) - 1);
243  attr = LLVMCreateEnumAttribute(LLVMGetTypeContext(LLVMTypeOf(f)), id, 0);
244  LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, attr);
245 }
246 
247 /*
248  * Emit code to switch memory context.
249  */
250 static inline LLVMValueRef
251 l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
252 {
253  const char *cmc = "CurrentMemoryContext";
254  LLVMValueRef cur;
255  LLVMValueRef ret;
256 
257  if (!(cur = LLVMGetNamedGlobal(mod, cmc)))
258  cur = LLVMAddGlobal(mod, l_ptr(StructMemoryContextData), cmc);
259  ret = l_load(b, l_ptr(StructMemoryContextData), cur, cmc);
260  LLVMBuildStore(b, nc, cur);
261 
262  return ret;
263 }
264 
265 /*
266  * Return pointer to the argno'th argument nullness.
267  */
268 static inline LLVMValueRef
269 l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
270 {
271  LLVMValueRef v_args;
272  LLVMValueRef v_argn;
273 
274  v_args = l_struct_gep(b,
276  v_fcinfo,
278  "");
279  v_argn = l_struct_gep(b,
280  LLVMArrayType(StructNullableDatum, 0),
281  v_args,
282  argno,
283  "");
284  return l_struct_gep(b,
286  v_argn,
288  "");
289 }
290 
291 /*
292  * Return pointer to the argno'th argument datum.
293  */
294 static inline LLVMValueRef
295 l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
296 {
297  LLVMValueRef v_args;
298  LLVMValueRef v_argn;
299 
300  v_args = l_struct_gep(b,
302  v_fcinfo,
304  "");
305  v_argn = l_struct_gep(b,
306  LLVMArrayType(StructNullableDatum, 0),
307  v_args,
308  argno,
309  "");
310  return l_struct_gep(b,
312  v_argn,
314  "");
315 }
316 
317 /*
318  * Return argno'th argument nullness.
319  */
320 static inline LLVMValueRef
321 l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
322 {
323  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 l_funcvalue(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
331 {
332  return l_load(b, TypeSizeT, l_funcvaluep(b, v_fcinfo, argno), "");
333 }
334 
335 #endif /* USE_LLVM */
336 #endif
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
signed char int8
Definition: c.h:492
signed short int16
Definition: c.h:493
signed int int32
Definition: c.h:494
#define pg_attribute_printf(f, a)
Definition: c.h:191
struct cursor * cur
Definition: ecpg.c:28
#define FIELDNO_FUNCTIONCALLINFODATA_ARGS
Definition: fmgr.h:94
int b
Definition: isn.c:70
int i
Definition: isn.c:73
static void const char * fmt
va_end(args)
va_start(args, fmt)
LLVMTypeRef StructFunctionCallInfoData
Definition: llvmjit.c:77
LLVMTypeRef TypeParamBool
Definition: llvmjit.c:65
LLVMTypeRef StructMemoryContextData
Definition: llvmjit.c:76
LLVMTypeRef TypeSizeT
Definition: llvmjit.c:64
LLVMTypeRef TypeStorageBool
Definition: llvmjit.c:66
LLVMTypeRef StructNullableDatum
Definition: llvmjit.c:68
static char * buf
Definition: pg_test_fsync.c:73
#define vsnprintf
Definition: port.h:237
#define FIELDNO_NULLABLE_DATUM_ISNULL
Definition: postgres.h:76
#define FIELDNO_NULLABLE_DATUM_DATUM
Definition: postgres.h:74
char * c
static void * fn(void *arg)
Definition: thread-alloc.c:119
const char * type
const char * name