1 /*
2 * llvmjit_emit.h
3 * Helpers to make emitting LLVM IR a bit more concise and pgindent proof.
4 *
5 * Copyright (c) 2018-2021, 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
20 #include "jit/llvmjit.h"
21
22
23 /*
24 * Emit a non-LLVM pointer as an LLVM constant.
25 */
26 static inline LLVMValueRef
l_ptr_const(void * ptr,LLVMTypeRef type)27 l_ptr_const(void *ptr, LLVMTypeRef type)
28 {
29 LLVMValueRef c = LLVMConstInt(TypeSizeT, (uintptr_t) ptr, false);
30
31 return LLVMConstIntToPtr(c, type);
32 }
33
34 /*
35 * Emit pointer.
36 */
37 static inline LLVMTypeRef
l_ptr(LLVMTypeRef t)38 l_ptr(LLVMTypeRef t)
39 {
40 return LLVMPointerType(t, 0);
41 }
42
43 /*
44 * Emit constant integer.
45 */
46 static inline LLVMValueRef
l_int8_const(int8 i)47 l_int8_const(int8 i)
48 {
49 return LLVMConstInt(LLVMInt8Type(), i, false);
50 }
51
52 /*
53 * Emit constant integer.
54 */
55 static inline LLVMValueRef
l_int16_const(int16 i)56 l_int16_const(int16 i)
57 {
58 return LLVMConstInt(LLVMInt16Type(), i, false);
59 }
60
61 /*
62 * Emit constant integer.
63 */
64 static inline LLVMValueRef
l_int32_const(int32 i)65 l_int32_const(int32 i)
66 {
67 return LLVMConstInt(LLVMInt32Type(), i, false);
68 }
69
70 /*
71 * Emit constant integer.
72 */
73 static inline LLVMValueRef
l_int64_const(int64 i)74 l_int64_const(int64 i)
75 {
76 return LLVMConstInt(LLVMInt64Type(), i, false);
77 }
78
79 /*
80 * Emit constant integer.
81 */
82 static inline LLVMValueRef
l_sizet_const(size_t i)83 l_sizet_const(size_t i)
84 {
85 return LLVMConstInt(TypeSizeT, i, false);
86 }
87
88 /*
89 * Emit constant boolean, as used for storage (e.g. global vars, structs).
90 */
91 static inline LLVMValueRef
l_sbool_const(bool i)92 l_sbool_const(bool i)
93 {
94 return LLVMConstInt(TypeStorageBool, (int) i, false);
95 }
96
97 /*
98 * Emit constant boolean, as used for parameters (e.g. function parameters).
99 */
100 static inline LLVMValueRef
l_pbool_const(bool i)101 l_pbool_const(bool i)
102 {
103 return LLVMConstInt(TypeParamBool, (int) i, false);
104 }
105
106 /*
107 * Load a pointer member idx from a struct.
108 */
109 static inline LLVMValueRef
l_load_struct_gep(LLVMBuilderRef b,LLVMValueRef v,int32 idx,const char * name)110 l_load_struct_gep(LLVMBuilderRef b, LLVMValueRef v, int32 idx, const char *name)
111 {
112 LLVMValueRef v_ptr = LLVMBuildStructGEP(b, v, idx, "");
113
114 return LLVMBuildLoad(b, v_ptr, name);
115 }
116
117 /*
118 * Load value of a pointer, after applying one index operation.
119 */
120 static inline LLVMValueRef
l_load_gep1(LLVMBuilderRef b,LLVMValueRef v,LLVMValueRef idx,const char * name)121 l_load_gep1(LLVMBuilderRef b, LLVMValueRef v, LLVMValueRef idx, const char *name)
122 {
123 LLVMValueRef v_ptr = LLVMBuildGEP(b, v, &idx, 1, "");
124
125 return LLVMBuildLoad(b, v_ptr, name);
126 }
127
128 /* separate, because pg_attribute_printf(2, 3) can't appear in definition */
129 static inline LLVMBasicBlockRef l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...) pg_attribute_printf(2, 3);
130
131 /*
132 * Insert a new basic block, just before r, the name being determined by fmt
133 * and arguments.
134 */
135 static inline LLVMBasicBlockRef
l_bb_before_v(LLVMBasicBlockRef r,const char * fmt,...)136 l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...)
137 {
138 char buf[512];
139 va_list args;
140
141 va_start(args, fmt);
142 vsnprintf(buf, sizeof(buf), fmt, args);
143 va_end(args);
144
145 return LLVMInsertBasicBlock(r, buf);
146 }
147
148 /* separate, because pg_attribute_printf(2, 3) can't appear in definition */
149 static inline LLVMBasicBlockRef l_bb_append_v(LLVMValueRef f, const char *fmt,...) pg_attribute_printf(2, 3);
150
151 /*
152 * Insert a new basic block after previous basic blocks, the name being
153 * determined by fmt and arguments.
154 */
155 static inline LLVMBasicBlockRef
l_bb_append_v(LLVMValueRef f,const char * fmt,...)156 l_bb_append_v(LLVMValueRef f, const char *fmt,...)
157 {
158 char buf[512];
159 va_list args;
160
161 va_start(args, fmt);
162 vsnprintf(buf, sizeof(buf), fmt, args);
163 va_end(args);
164
165 return LLVMAppendBasicBlock(f, buf);
166 }
167
168 /*
169 * Mark a callsite as readonly.
170 */
171 static inline void
l_callsite_ro(LLVMValueRef f)172 l_callsite_ro(LLVMValueRef f)
173 {
174 const char argname[] = "readonly";
175 LLVMAttributeRef ref;
176
177 ref = LLVMCreateStringAttribute(LLVMGetGlobalContext(),
178 argname,
179 sizeof(argname) - 1,
180 NULL, 0);
181
182 LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, ref);
183 }
184
185 /*
186 * Mark a callsite as alwaysinline.
187 */
188 static inline void
l_callsite_alwaysinline(LLVMValueRef f)189 l_callsite_alwaysinline(LLVMValueRef f)
190 {
191 const char argname[] = "alwaysinline";
192 int id;
193 LLVMAttributeRef attr;
194
195 id = LLVMGetEnumAttributeKindForName(argname,
196 sizeof(argname) - 1);
197 attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), id, 0);
198 LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, attr);
199 }
200
201 /*
202 * Emit code to switch memory context.
203 */
204 static inline LLVMValueRef
l_mcxt_switch(LLVMModuleRef mod,LLVMBuilderRef b,LLVMValueRef nc)205 l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
206 {
207 const char *cmc = "CurrentMemoryContext";
208 LLVMValueRef cur;
209 LLVMValueRef ret;
210
211 if (!(cur = LLVMGetNamedGlobal(mod, cmc)))
212 cur = LLVMAddGlobal(mod, l_ptr(StructMemoryContextData), cmc);
213 ret = LLVMBuildLoad(b, cur, cmc);
214 LLVMBuildStore(b, nc, cur);
215
216 return ret;
217 }
218
219 /*
220 * Return pointer to the argno'th argument nullness.
221 */
222 static inline LLVMValueRef
l_funcnullp(LLVMBuilderRef b,LLVMValueRef v_fcinfo,size_t argno)223 l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
224 {
225 LLVMValueRef v_args;
226 LLVMValueRef v_argn;
227
228 v_args = LLVMBuildStructGEP(b,
229 v_fcinfo,
230 FIELDNO_FUNCTIONCALLINFODATA_ARGS,
231 "");
232 v_argn = LLVMBuildStructGEP(b, v_args, argno, "");
233
234 return LLVMBuildStructGEP(b, v_argn, FIELDNO_NULLABLE_DATUM_ISNULL, "");
235 }
236
237 /*
238 * Return pointer to the argno'th argument datum.
239 */
240 static inline LLVMValueRef
l_funcvaluep(LLVMBuilderRef b,LLVMValueRef v_fcinfo,size_t argno)241 l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
242 {
243 LLVMValueRef v_args;
244 LLVMValueRef v_argn;
245
246 v_args = LLVMBuildStructGEP(b,
247 v_fcinfo,
248 FIELDNO_FUNCTIONCALLINFODATA_ARGS,
249 "");
250 v_argn = LLVMBuildStructGEP(b, v_args, argno, "");
251
252 return LLVMBuildStructGEP(b, v_argn, FIELDNO_NULLABLE_DATUM_DATUM, "");
253 }
254
255 /*
256 * Return argno'th argument nullness.
257 */
258 static inline LLVMValueRef
l_funcnull(LLVMBuilderRef b,LLVMValueRef v_fcinfo,size_t argno)259 l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
260 {
261 return LLVMBuildLoad(b, l_funcnullp(b, v_fcinfo, argno), "");
262 }
263
264 /*
265 * Return argno'th argument datum.
266 */
267 static inline LLVMValueRef
l_funcvalue(LLVMBuilderRef b,LLVMValueRef v_fcinfo,size_t argno)268 l_funcvalue(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
269 {
270 return LLVMBuildLoad(b, l_funcvaluep(b, v_fcinfo, argno), "");
271 }
272
273 #endif /* USE_LLVM */
274 #endif
275