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