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