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