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
37 /*
38 * Return a scalar LLVMTypeRef corresponding to the given lp_type.
39 */
40 LLVMTypeRef
lp_build_elem_type(const struct gallivm_state * gallivm,struct lp_type type)41 lp_build_elem_type(const struct gallivm_state *gallivm, struct lp_type type)
42 {
43 if (type.floating) {
44 switch (type.width) {
45 case 16:
46 return lp_has_fp16()
47 ? LLVMHalfTypeInContext(gallivm->context)
48 : LLVMInt16TypeInContext(gallivm->context);
49 case 32:
50 return LLVMFloatTypeInContext(gallivm->context);
51 case 64:
52 return LLVMDoubleTypeInContext(gallivm->context);
53 default:
54 assert(0);
55 return LLVMFloatTypeInContext(gallivm->context);
56 }
57 }
58 else {
59 return LLVMIntTypeInContext(gallivm->context, type.width);
60 }
61 }
62
63
64 /*
65 * Return a vector LLVMTypeRef corresponding to the given lp_type.
66 */
67 LLVMTypeRef
lp_build_vec_type(const struct gallivm_state * gallivm,struct lp_type type)68 lp_build_vec_type(const struct gallivm_state *gallivm, struct lp_type type)
69 {
70 LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type);
71 if (type.length == 1)
72 return elem_type;
73 else
74 return LLVMVectorType(elem_type, type.length);
75 }
76
77
78 /**
79 * This function is a mirror of lp_build_elem_type() above.
80 *
81 * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the
82 * type and check for identity.
83 */
84 boolean
lp_check_elem_type(struct lp_type type,LLVMTypeRef elem_type)85 lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type)
86 {
87 assert(elem_type);
88 if (!elem_type)
89 return FALSE;
90
91 const LLVMTypeKind elem_kind = LLVMGetTypeKind(elem_type);
92
93 if (type.floating) {
94 switch (type.width) {
95 case 16:
96 if (elem_kind != (lp_has_fp16()
97 ? LLVMHalfTypeKind : LLVMIntegerTypeKind)) {
98 debug_printf("%s:%d: type is not 16 bits\n", __FILE__, __LINE__);
99 return FALSE;
100 }
101 break;
102 case 32:
103 if (elem_kind != LLVMFloatTypeKind) {
104 debug_printf("%s:%d: type is not float\n", __FILE__, __LINE__);
105 return FALSE;
106 }
107 break;
108 case 64:
109 if (elem_kind != LLVMDoubleTypeKind) {
110 debug_printf("%s:%d: type is not double\n", __FILE__, __LINE__);
111 return FALSE;
112 }
113 break;
114 default:
115 assert(0);
116 return FALSE;
117 }
118 }
119 else {
120 if (elem_kind != LLVMIntegerTypeKind) {
121 debug_printf("%s:%d: element is not integer\n", __FILE__, __LINE__);
122 return FALSE;
123 }
124
125 if (LLVMGetIntTypeWidth(elem_type) != type.width) {
126 debug_printf("%s:%d: type width mismatch %d != %d\n",
127 __FILE__, __LINE__,
128 LLVMGetIntTypeWidth(elem_type), type.width);
129 return FALSE;
130 }
131 }
132
133 return TRUE;
134 }
135
136
137 boolean
lp_check_vec_type(struct lp_type type,LLVMTypeRef vec_type)138 lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type)
139 {
140 assert(vec_type);
141 if (!vec_type)
142 return FALSE;
143
144 if (type.length == 1)
145 return lp_check_elem_type(type, vec_type);
146
147 if (LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind) {
148 printf("%s:%d: kind is not vector\n", __FILE__, __LINE__);
149 return FALSE;
150 }
151
152 if (LLVMGetVectorSize(vec_type) != type.length) {
153 printf("%s:%d: vector size mismatch %d != expected %d\n", __FILE__, __LINE__,
154 LLVMGetVectorSize(vec_type), type.length);
155 return FALSE;
156 }
157
158 LLVMTypeRef elem_type = LLVMGetElementType(vec_type);
159
160 return lp_check_elem_type(type, elem_type);
161 }
162
163
164 boolean
lp_check_value(struct lp_type type,LLVMValueRef val)165 lp_check_value(struct lp_type type, LLVMValueRef val)
166 {
167 assert(val);
168 if (!val)
169 return FALSE;
170
171 LLVMTypeRef vec_type = LLVMTypeOf(val);
172
173 return lp_check_vec_type(type, vec_type);
174 }
175
176
177 LLVMTypeRef
lp_build_int_elem_type(const struct gallivm_state * gallivm,struct lp_type type)178 lp_build_int_elem_type(const struct gallivm_state *gallivm,
179 struct lp_type type)
180 {
181 return LLVMIntTypeInContext(gallivm->context, type.width);
182 }
183
184
185 LLVMTypeRef
lp_build_int_vec_type(const struct gallivm_state * gallivm,struct lp_type type)186 lp_build_int_vec_type(const struct gallivm_state *gallivm,
187 struct lp_type type)
188 {
189 LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type);
190 if (type.length == 1)
191 return elem_type;
192 else
193 return LLVMVectorType(elem_type, type.length);
194 }
195
196
197 /**
198 * Create element of vector type
199 */
200 struct lp_type
lp_elem_type(struct lp_type type)201 lp_elem_type(struct lp_type type)
202 {
203 struct lp_type res_type;
204
205 assert(type.length > 1);
206 res_type = type;
207 res_type.length = 1;
208
209 return res_type;
210 }
211
212
213 /**
214 * Create unsigned integer type variation of given type.
215 */
216 struct lp_type
lp_uint_type(struct lp_type type)217 lp_uint_type(struct lp_type type)
218 {
219 struct lp_type res_type;
220
221 assert(type.length <= LP_MAX_VECTOR_LENGTH);
222 memset(&res_type, 0, sizeof res_type);
223 res_type.width = type.width;
224 res_type.length = type.length;
225
226 return res_type;
227 }
228
229
230 /**
231 * Create signed integer type variation of given type.
232 */
233 struct lp_type
lp_int_type(struct lp_type type)234 lp_int_type(struct lp_type type)
235 {
236 struct lp_type res_type;
237
238 assert(type.length <= LP_MAX_VECTOR_LENGTH);
239 memset(&res_type, 0, sizeof res_type);
240 res_type.width = type.width;
241 res_type.length = type.length;
242 res_type.sign = 1;
243
244 return res_type;
245 }
246
247
248 /**
249 * Return the type with twice the bit width (hence half the number of elements).
250 */
251 struct lp_type
lp_wider_type(struct lp_type type)252 lp_wider_type(struct lp_type type)
253 {
254 struct lp_type res_type;
255
256 memcpy(&res_type, &type, sizeof res_type);
257 res_type.width *= 2;
258 res_type.length /= 2;
259
260 assert(res_type.length);
261
262 return res_type;
263 }
264
265
266 /**
267 * Return the size of the LLVMType in bits.
268 * XXX this function doesn't necessarily handle all LLVM types.
269 */
270 unsigned
lp_sizeof_llvm_type(LLVMTypeRef t)271 lp_sizeof_llvm_type(LLVMTypeRef t)
272 {
273 LLVMTypeKind k = LLVMGetTypeKind(t);
274
275 switch (k) {
276 case LLVMIntegerTypeKind:
277 return LLVMGetIntTypeWidth(t);
278 case LLVMFloatTypeKind:
279 return 8 * sizeof(float);
280 case LLVMDoubleTypeKind:
281 return 8 * sizeof(double);
282 case LLVMHalfTypeKind:
283 return 8 * sizeof(uint16_t);
284 case LLVMVectorTypeKind:
285 {
286 LLVMTypeRef elem = LLVMGetElementType(t);
287 unsigned len = LLVMGetVectorSize(t);
288 return len * lp_sizeof_llvm_type(elem);
289 }
290 break;
291 case LLVMArrayTypeKind:
292 {
293 LLVMTypeRef elem = LLVMGetElementType(t);
294 unsigned len = LLVMGetArrayLength(t);
295 return len * lp_sizeof_llvm_type(elem);
296 }
297 break;
298 default:
299 assert(0 && "Unexpected type in lp_get_llvm_type_size()");
300 return 0;
301 }
302 }
303
304
305 /**
306 * Return string name for a LLVMTypeKind. Useful for debugging.
307 */
308 const char *
lp_typekind_name(LLVMTypeKind t)309 lp_typekind_name(LLVMTypeKind t)
310 {
311 switch (t) {
312 case LLVMVoidTypeKind:
313 return "LLVMVoidTypeKind";
314 case LLVMFloatTypeKind:
315 return "LLVMFloatTypeKind";
316 case LLVMHalfTypeKind:
317 return "LLVMHalfTypeKind";
318 case LLVMDoubleTypeKind:
319 return "LLVMDoubleTypeKind";
320 case LLVMX86_FP80TypeKind:
321 return "LLVMX86_FP80TypeKind";
322 case LLVMFP128TypeKind:
323 return "LLVMFP128TypeKind";
324 case LLVMPPC_FP128TypeKind:
325 return "LLVMPPC_FP128TypeKind";
326 case LLVMLabelTypeKind:
327 return "LLVMLabelTypeKind";
328 case LLVMIntegerTypeKind:
329 return "LLVMIntegerTypeKind";
330 case LLVMFunctionTypeKind:
331 return "LLVMFunctionTypeKind";
332 case LLVMStructTypeKind:
333 return "LLVMStructTypeKind";
334 case LLVMArrayTypeKind:
335 return "LLVMArrayTypeKind";
336 case LLVMPointerTypeKind:
337 return "LLVMPointerTypeKind";
338 case LLVMVectorTypeKind:
339 return "LLVMVectorTypeKind";
340 case LLVMMetadataTypeKind:
341 return "LLVMMetadataTypeKind";
342 default:
343 return "unknown LLVMTypeKind";
344 }
345 }
346
347
348 /**
349 * Print an LLVMTypeRef. Like LLVMDumpValue(). For debugging.
350 */
351 void
lp_dump_llvmtype(LLVMTypeRef t)352 lp_dump_llvmtype(LLVMTypeRef t)
353 {
354 LLVMTypeKind k = LLVMGetTypeKind(t);
355
356 if (k == LLVMVectorTypeKind) {
357 LLVMTypeRef te = LLVMGetElementType(t);
358 LLVMTypeKind ke = LLVMGetTypeKind(te);
359 unsigned len = LLVMGetVectorSize(t);
360 if (ke == LLVMIntegerTypeKind) {
361 unsigned b = LLVMGetIntTypeWidth(te);
362 debug_printf("Vector [%u] of %u-bit Integer\n", len, b);
363 }
364 else {
365 debug_printf("Vector [%u] of %s\n", len, lp_typekind_name(ke));
366 }
367 }
368 else if (k == LLVMArrayTypeKind) {
369 LLVMTypeRef te = LLVMGetElementType(t);
370 LLVMTypeKind ke = LLVMGetTypeKind(te);
371 unsigned len = LLVMGetArrayLength(t);
372 debug_printf("Array [%u] of %s\n", len, lp_typekind_name(ke));
373 }
374 else if (k == LLVMIntegerTypeKind) {
375 unsigned b = LLVMGetIntTypeWidth(t);
376 debug_printf("%u-bit Integer\n", b);
377 }
378 else if (k == LLVMPointerTypeKind) {
379 LLVMTypeRef te = LLVMGetElementType(t);
380 debug_printf("Pointer to ");
381 lp_dump_llvmtype(te);
382 }
383 else {
384 debug_printf("%s\n", lp_typekind_name(k));
385 }
386 }
387
388
389 void
lp_build_context_init(struct lp_build_context * bld,struct gallivm_state * gallivm,struct lp_type type)390 lp_build_context_init(struct lp_build_context *bld,
391 struct gallivm_state *gallivm,
392 struct lp_type type)
393 {
394 bld->gallivm = gallivm;
395 bld->type = type;
396
397 bld->int_elem_type = lp_build_int_elem_type(gallivm, type);
398 if (type.floating)
399 bld->elem_type = lp_build_elem_type(gallivm, type);
400 else
401 bld->elem_type = bld->int_elem_type;
402
403 if (type.length == 1) {
404 bld->int_vec_type = bld->int_elem_type;
405 bld->vec_type = bld->elem_type;
406 }
407 else {
408 bld->int_vec_type = LLVMVectorType(bld->int_elem_type, type.length);
409 bld->vec_type = LLVMVectorType(bld->elem_type, type.length);
410 }
411
412 bld->undef = LLVMGetUndef(bld->vec_type);
413 bld->zero = LLVMConstNull(bld->vec_type);
414 bld->one = lp_build_one(gallivm, type);
415 }
416
417
418 /**
419 * Count the number of instructions in a function.
420 */
421 static unsigned
lp_build_count_instructions(LLVMValueRef function)422 lp_build_count_instructions(LLVMValueRef function)
423 {
424 unsigned num_instrs = 0;
425 LLVMBasicBlockRef block;
426
427 block = LLVMGetFirstBasicBlock(function);
428 while (block) {
429 LLVMValueRef instr;
430 instr = LLVMGetFirstInstruction(block);
431 while (instr) {
432 ++num_instrs;
433
434 instr = LLVMGetNextInstruction(instr);
435 }
436 block = LLVMGetNextBasicBlock(block);
437 }
438
439 return num_instrs;
440 }
441
442
443 /**
444 * Count the number of instructions in a module.
445 */
446 unsigned
lp_build_count_ir_module(LLVMModuleRef module)447 lp_build_count_ir_module(LLVMModuleRef module)
448 {
449 LLVMValueRef func;
450 unsigned num_instrs = 0;
451
452 func = LLVMGetFirstFunction(module);
453 while (func) {
454 num_instrs += lp_build_count_instructions(func);
455 func = LLVMGetNextFunction(func);
456 }
457 return num_instrs;
458 }
459