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