1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 #include "util/u_debug.h"
30
31 #include "lp_bld_type.h"
32 #include "lp_bld_const.h"
33 #include "lp_bld_init.h"
34 #include "lp_bld_limits.h"
35
36 LLVMTypeRef
lp_build_elem_type(struct gallivm_state * gallivm,struct lp_type type)37 lp_build_elem_type(struct gallivm_state *gallivm, struct lp_type type)
38 {
39 if (type.floating) {
40 switch(type.width) {
41 case 16:
42 return lp_has_fp16() ? LLVMHalfTypeInContext(gallivm->context) : LLVMInt16TypeInContext(gallivm->context);
43 break;
44 case 32:
45 return LLVMFloatTypeInContext(gallivm->context);
46 break;
47 case 64:
48 return LLVMDoubleTypeInContext(gallivm->context);
49 break;
50 default:
51 assert(0);
52 return LLVMFloatTypeInContext(gallivm->context);
53 }
54 }
55 else {
56 return LLVMIntTypeInContext(gallivm->context, type.width);
57 }
58 }
59
60
61 LLVMTypeRef
lp_build_vec_type(struct gallivm_state * gallivm,struct lp_type type)62 lp_build_vec_type(struct gallivm_state *gallivm,struct lp_type type)
63 {
64 LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type);
65 if (type.length == 1)
66 return elem_type;
67 else
68 return LLVMVectorType(elem_type, type.length);
69 }
70
71
72 /**
73 * This function is a mirror of lp_build_elem_type() above.
74 *
75 * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the
76 * type and check for identity.
77 */
78 boolean
lp_check_elem_type(struct lp_type type,LLVMTypeRef elem_type)79 lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type)
80 {
81 LLVMTypeKind elem_kind;
82
83 assert(elem_type);
84 if(!elem_type)
85 return FALSE;
86
87 elem_kind = LLVMGetTypeKind(elem_type);
88
89 if (type.floating) {
90 switch(type.width) {
91 case 16:
92 if(elem_kind != (lp_has_fp16() ? LLVMHalfTypeKind : LLVMIntegerTypeKind))
93 return FALSE;
94 break;
95 case 32:
96 if(elem_kind != LLVMFloatTypeKind)
97 return FALSE;
98 break;
99 case 64:
100 if(elem_kind != LLVMDoubleTypeKind)
101 return FALSE;
102 break;
103 default:
104 assert(0);
105 return FALSE;
106 }
107 }
108 else {
109 if(elem_kind != LLVMIntegerTypeKind)
110 return FALSE;
111
112 if(LLVMGetIntTypeWidth(elem_type) != type.width)
113 return FALSE;
114 }
115
116 return TRUE;
117 }
118
119
120 boolean
lp_check_vec_type(struct lp_type type,LLVMTypeRef vec_type)121 lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type)
122 {
123 LLVMTypeRef elem_type;
124
125 assert(vec_type);
126 if(!vec_type)
127 return FALSE;
128
129 if (type.length == 1)
130 return lp_check_elem_type(type, vec_type);
131
132 if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind)
133 return FALSE;
134
135 if(LLVMGetVectorSize(vec_type) != type.length)
136 return FALSE;
137
138 elem_type = LLVMGetElementType(vec_type);
139
140 return lp_check_elem_type(type, elem_type);
141 }
142
143
144 boolean
lp_check_value(struct lp_type type,LLVMValueRef val)145 lp_check_value(struct lp_type type, LLVMValueRef val)
146 {
147 LLVMTypeRef vec_type;
148
149 assert(val);
150 if(!val)
151 return FALSE;
152
153 vec_type = LLVMTypeOf(val);
154
155 return lp_check_vec_type(type, vec_type);
156 }
157
158
159 LLVMTypeRef
lp_build_int_elem_type(struct gallivm_state * gallivm,struct lp_type type)160 lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type)
161 {
162 return LLVMIntTypeInContext(gallivm->context, type.width);
163 }
164
165
166 LLVMTypeRef
lp_build_int_vec_type(struct gallivm_state * gallivm,struct lp_type type)167 lp_build_int_vec_type(struct gallivm_state *gallivm, struct lp_type type)
168 {
169 LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type);
170 if (type.length == 1)
171 return elem_type;
172 else
173 return LLVMVectorType(elem_type, type.length);
174 }
175
176
177 /**
178 * Create element of vector type
179 */
180 struct lp_type
lp_elem_type(struct lp_type type)181 lp_elem_type(struct lp_type type)
182 {
183 struct lp_type res_type;
184
185 assert(type.length > 1);
186 res_type = type;
187 res_type.length = 1;
188
189 return res_type;
190 }
191
192
193 /**
194 * Create unsigned integer type variation of given type.
195 */
196 struct lp_type
lp_uint_type(struct lp_type type)197 lp_uint_type(struct lp_type type)
198 {
199 struct lp_type res_type;
200
201 assert(type.length <= LP_MAX_VECTOR_LENGTH);
202 memset(&res_type, 0, sizeof res_type);
203 res_type.width = type.width;
204 res_type.length = type.length;
205
206 return res_type;
207 }
208
209
210 /**
211 * Create signed integer type variation of given type.
212 */
213 struct lp_type
lp_int_type(struct lp_type type)214 lp_int_type(struct lp_type type)
215 {
216 struct lp_type res_type;
217
218 assert(type.length <= LP_MAX_VECTOR_LENGTH);
219 memset(&res_type, 0, sizeof res_type);
220 res_type.width = type.width;
221 res_type.length = type.length;
222 res_type.sign = 1;
223
224 return res_type;
225 }
226
227
228 /**
229 * Return the type with twice the bit width (hence half the number of elements).
230 */
231 struct lp_type
lp_wider_type(struct lp_type type)232 lp_wider_type(struct lp_type type)
233 {
234 struct lp_type res_type;
235
236 memcpy(&res_type, &type, sizeof res_type);
237 res_type.width *= 2;
238 res_type.length /= 2;
239
240 assert(res_type.length);
241
242 return res_type;
243 }
244
245
246 /**
247 * Return the size of the LLVMType in bits.
248 * XXX this function doesn't necessarily handle all LLVM types.
249 */
250 unsigned
lp_sizeof_llvm_type(LLVMTypeRef t)251 lp_sizeof_llvm_type(LLVMTypeRef t)
252 {
253 LLVMTypeKind k = LLVMGetTypeKind(t);
254
255 switch (k) {
256 case LLVMIntegerTypeKind:
257 return LLVMGetIntTypeWidth(t);
258 case LLVMFloatTypeKind:
259 return 8 * sizeof(float);
260 case LLVMDoubleTypeKind:
261 return 8 * sizeof(double);
262 case LLVMHalfTypeKind:
263 return 8 * sizeof(uint16_t);
264 case LLVMVectorTypeKind:
265 {
266 LLVMTypeRef elem = LLVMGetElementType(t);
267 unsigned len = LLVMGetVectorSize(t);
268 return len * lp_sizeof_llvm_type(elem);
269 }
270 break;
271 case LLVMArrayTypeKind:
272 {
273 LLVMTypeRef elem = LLVMGetElementType(t);
274 unsigned len = LLVMGetArrayLength(t);
275 return len * lp_sizeof_llvm_type(elem);
276 }
277 break;
278 default:
279 assert(0 && "Unexpected type in lp_get_llvm_type_size()");
280 return 0;
281 }
282 }
283
284
285 /**
286 * Return string name for a LLVMTypeKind. Useful for debugging.
287 */
288 const char *
lp_typekind_name(LLVMTypeKind t)289 lp_typekind_name(LLVMTypeKind t)
290 {
291 switch (t) {
292 case LLVMVoidTypeKind:
293 return "LLVMVoidTypeKind";
294 case LLVMFloatTypeKind:
295 return "LLVMFloatTypeKind";
296 case LLVMHalfTypeKind:
297 return "LLVMHalfTypeKind";
298 case LLVMDoubleTypeKind:
299 return "LLVMDoubleTypeKind";
300 case LLVMX86_FP80TypeKind:
301 return "LLVMX86_FP80TypeKind";
302 case LLVMFP128TypeKind:
303 return "LLVMFP128TypeKind";
304 case LLVMPPC_FP128TypeKind:
305 return "LLVMPPC_FP128TypeKind";
306 case LLVMLabelTypeKind:
307 return "LLVMLabelTypeKind";
308 case LLVMIntegerTypeKind:
309 return "LLVMIntegerTypeKind";
310 case LLVMFunctionTypeKind:
311 return "LLVMFunctionTypeKind";
312 case LLVMStructTypeKind:
313 return "LLVMStructTypeKind";
314 case LLVMArrayTypeKind:
315 return "LLVMArrayTypeKind";
316 case LLVMPointerTypeKind:
317 return "LLVMPointerTypeKind";
318 case LLVMVectorTypeKind:
319 return "LLVMVectorTypeKind";
320 case LLVMMetadataTypeKind:
321 return "LLVMMetadataTypeKind";
322 default:
323 return "unknown LLVMTypeKind";
324 }
325 }
326
327
328 /**
329 * Print an LLVMTypeRef. Like LLVMDumpValue(). For debugging.
330 */
331 void
lp_dump_llvmtype(LLVMTypeRef t)332 lp_dump_llvmtype(LLVMTypeRef t)
333 {
334 LLVMTypeKind k = LLVMGetTypeKind(t);
335
336 if (k == LLVMVectorTypeKind) {
337 LLVMTypeRef te = LLVMGetElementType(t);
338 LLVMTypeKind ke = LLVMGetTypeKind(te);
339 unsigned len = LLVMGetVectorSize(t);
340 if (ke == LLVMIntegerTypeKind) {
341 unsigned b = LLVMGetIntTypeWidth(te);
342 debug_printf("Vector [%u] of %u-bit Integer\n", len, b);
343 }
344 else {
345 debug_printf("Vector [%u] of %s\n", len, lp_typekind_name(ke));
346 }
347 }
348 else if (k == LLVMArrayTypeKind) {
349 LLVMTypeRef te = LLVMGetElementType(t);
350 LLVMTypeKind ke = LLVMGetTypeKind(te);
351 unsigned len = LLVMGetArrayLength(t);
352 debug_printf("Array [%u] of %s\n", len, lp_typekind_name(ke));
353 }
354 else if (k == LLVMIntegerTypeKind) {
355 unsigned b = LLVMGetIntTypeWidth(t);
356 debug_printf("%u-bit Integer\n", b);
357 }
358 else if (k == LLVMPointerTypeKind) {
359 LLVMTypeRef te = LLVMGetElementType(t);
360 debug_printf("Pointer to ");
361 lp_dump_llvmtype(te);
362 }
363 else {
364 debug_printf("%s\n", lp_typekind_name(k));
365 }
366 }
367
368
369 void
lp_build_context_init(struct lp_build_context * bld,struct gallivm_state * gallivm,struct lp_type type)370 lp_build_context_init(struct lp_build_context *bld,
371 struct gallivm_state *gallivm,
372 struct lp_type type)
373 {
374 bld->gallivm = gallivm;
375 bld->type = type;
376
377 bld->int_elem_type = lp_build_int_elem_type(gallivm, type);
378 if (type.floating)
379 bld->elem_type = lp_build_elem_type(gallivm, type);
380 else
381 bld->elem_type = bld->int_elem_type;
382
383 if (type.length == 1) {
384 bld->int_vec_type = bld->int_elem_type;
385 bld->vec_type = bld->elem_type;
386 }
387 else {
388 bld->int_vec_type = LLVMVectorType(bld->int_elem_type, type.length);
389 bld->vec_type = LLVMVectorType(bld->elem_type, type.length);
390 }
391
392 bld->undef = LLVMGetUndef(bld->vec_type);
393 bld->zero = LLVMConstNull(bld->vec_type);
394 bld->one = lp_build_one(gallivm, type);
395 }
396
397
398 /**
399 * Count the number of instructions in a function.
400 */
401 static unsigned
lp_build_count_instructions(LLVMValueRef function)402 lp_build_count_instructions(LLVMValueRef function)
403 {
404 unsigned num_instrs = 0;
405 LLVMBasicBlockRef block;
406
407 block = LLVMGetFirstBasicBlock(function);
408 while (block) {
409 LLVMValueRef instr;
410 instr = LLVMGetFirstInstruction(block);
411 while (instr) {
412 ++num_instrs;
413
414 instr = LLVMGetNextInstruction(instr);
415 }
416 block = LLVMGetNextBasicBlock(block);
417 }
418
419 return num_instrs;
420 }
421
422
423 /**
424 * Count the number of instructions in a module.
425 */
426 unsigned
lp_build_count_ir_module(LLVMModuleRef module)427 lp_build_count_ir_module(LLVMModuleRef module)
428 {
429 LLVMValueRef func;
430 unsigned num_instrs = 0;
431
432 func = LLVMGetFirstFunction(module);
433 while (func) {
434 num_instrs += lp_build_count_instructions(func);
435 func = LLVMGetNextFunction(func);
436 }
437 return num_instrs;
438 }
439