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 */
27static inline LLVMValueRef
28l_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 */
38static inline LLVMTypeRef
39l_ptr(LLVMTypeRef t)
40{
41 return LLVMPointerType(t, 0);
42}
43
44/*
45 * Emit constant integer.
46 */
47static inline LLVMValueRef
48l_int8_const(int8 i)
49{
50 return LLVMConstInt(LLVMInt8Type(), i, false);
51}
52
53/*
54 * Emit constant integer.
55 */
56static inline LLVMValueRef
57l_int16_const(int16 i)
58{
59 return LLVMConstInt(LLVMInt16Type(), i, false);
60}
61
62/*
63 * Emit constant integer.
64 */
65static inline LLVMValueRef
66l_int32_const(int32 i)
67{
68 return LLVMConstInt(LLVMInt32Type(), i, false);
69}
70
71/*
72 * Emit constant integer.
73 */
74static inline LLVMValueRef
75l_int64_const(int64 i)
76{
77 return LLVMConstInt(LLVMInt64Type(), i, false);
78}
79
80/*
81 * Emit constant integer.
82 */
83static inline LLVMValueRef
84l_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 */
92static inline LLVMValueRef
93l_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 */
101static inline LLVMValueRef
102l_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 */
110static inline LLVMValueRef
111l_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 */
121static inline LLVMValueRef
122l_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 */
130static 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 */
136static inline LLVMBasicBlockRef
137l_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 */
150static 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 */
156static inline LLVMBasicBlockRef
157l_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 */
172static inline void
173l_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 */
189static inline void
190l_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 */
205static inline LLVMValueRef
206l_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 */
223static inline LLVMValueRef
224l_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 */
241static inline LLVMValueRef
242l_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 */
259static inline LLVMValueRef
260l_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 */
268static inline LLVMValueRef
269l_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