1 | /* |
2 | * llvmjit_emit.h |
3 | * Helpers to make emitting LLVM IR a it 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 |
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(int8 i) |
49 | { |
50 | return LLVMConstInt(LLVMInt8Type(), i, false); |
51 | } |
52 | |
53 | /* |
54 | * Emit constant integer. |
55 | */ |
56 | static inline LLVMValueRef |
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 |
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 |
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 |
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 | /* |
108 | * Load a pointer member idx from a struct. |
109 | */ |
110 | static inline LLVMValueRef |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 | |