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
36LLVMTypeRef
37lp_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 LLVMIntTypeInContext(gallivm->context, 16);
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
61LLVMTypeRef
62lp_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 */
78boolean
79lp_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 != 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
120boolean
121lp_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
144boolean
145lp_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
159LLVMTypeRef
160lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type)
161{
162   return LLVMIntTypeInContext(gallivm->context, type.width);
163}
164
165
166LLVMTypeRef
167lp_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 */
180struct lp_type
181lp_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 */
196struct lp_type
197lp_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 */
213struct lp_type
214lp_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 */
231struct lp_type
232lp_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 */
250unsigned
251lp_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 LLVMVectorTypeKind:
263      {
264         LLVMTypeRef elem = LLVMGetElementType(t);
265         unsigned len = LLVMGetVectorSize(t);
266         return len * lp_sizeof_llvm_type(elem);
267      }
268      break;
269   case LLVMArrayTypeKind:
270      {
271         LLVMTypeRef elem = LLVMGetElementType(t);
272         unsigned len = LLVMGetArrayLength(t);
273         return len * lp_sizeof_llvm_type(elem);
274      }
275      break;
276   default:
277      assert(0 && "Unexpected type in lp_get_llvm_type_size()");
278      return 0;
279   }
280}
281
282
283/**
284 * Return string name for a LLVMTypeKind.  Useful for debugging.
285 */
286const char *
287lp_typekind_name(LLVMTypeKind t)
288{
289   switch (t) {
290   case LLVMVoidTypeKind:
291      return "LLVMVoidTypeKind";
292   case LLVMFloatTypeKind:
293      return "LLVMFloatTypeKind";
294   case LLVMDoubleTypeKind:
295      return "LLVMDoubleTypeKind";
296   case LLVMX86_FP80TypeKind:
297      return "LLVMX86_FP80TypeKind";
298   case LLVMFP128TypeKind:
299      return "LLVMFP128TypeKind";
300   case LLVMPPC_FP128TypeKind:
301      return "LLVMPPC_FP128TypeKind";
302   case LLVMLabelTypeKind:
303      return "LLVMLabelTypeKind";
304   case LLVMIntegerTypeKind:
305      return "LLVMIntegerTypeKind";
306   case LLVMFunctionTypeKind:
307      return "LLVMFunctionTypeKind";
308   case LLVMStructTypeKind:
309      return "LLVMStructTypeKind";
310   case LLVMArrayTypeKind:
311      return "LLVMArrayTypeKind";
312   case LLVMPointerTypeKind:
313      return "LLVMPointerTypeKind";
314#if HAVE_LLVM < 0x0300
315   case LLVMOpaqueTypeKind:
316      return "LLVMOpaqueTypeKind";
317#endif
318   case LLVMVectorTypeKind:
319      return "LLVMVectorTypeKind";
320   case LLVMMetadataTypeKind:
321      return "LLVMMetadataTypeKind";
322#if HAVE_LLVM == 0x0207
323   case LLVMUnionTypeKind:
324      return "LLVMUnionTypeKind";
325#endif
326   default:
327      return "unknown LLVMTypeKind";
328   }
329}
330
331
332/**
333 * Print an LLVMTypeRef.  Like LLVMDumpValue().  For debugging.
334 */
335void
336lp_dump_llvmtype(LLVMTypeRef t)
337{
338   LLVMTypeKind k = LLVMGetTypeKind(t);
339
340   if (k == LLVMVectorTypeKind) {
341      LLVMTypeRef te = LLVMGetElementType(t);
342      LLVMTypeKind ke = LLVMGetTypeKind(te);
343      unsigned len = LLVMGetVectorSize(t);
344      if (ke == LLVMIntegerTypeKind) {
345         unsigned b = LLVMGetIntTypeWidth(te);
346         debug_printf("Vector [%u] of %u-bit Integer\n", len, b);
347      }
348      else {
349         debug_printf("Vector [%u] of %s\n", len, lp_typekind_name(ke));
350      }
351   }
352   else if (k == LLVMArrayTypeKind) {
353      LLVMTypeRef te = LLVMGetElementType(t);
354      LLVMTypeKind ke = LLVMGetTypeKind(te);
355      unsigned len = LLVMGetArrayLength(t);
356      debug_printf("Array [%u] of %s\n", len, lp_typekind_name(ke));
357   }
358   else if (k == LLVMIntegerTypeKind) {
359      unsigned b = LLVMGetIntTypeWidth(t);
360      debug_printf("%u-bit Integer\n", b);
361   }
362   else if (k == LLVMPointerTypeKind) {
363      LLVMTypeRef te = LLVMGetElementType(t);
364      debug_printf("Pointer to ");
365      lp_dump_llvmtype(te);
366   }
367   else {
368      debug_printf("%s\n", lp_typekind_name(k));
369   }
370}
371
372
373void
374lp_build_context_init(struct lp_build_context *bld,
375                      struct gallivm_state *gallivm,
376                      struct lp_type type)
377{
378   bld->gallivm = gallivm;
379   bld->type = type;
380
381   bld->int_elem_type = lp_build_int_elem_type(gallivm, type);
382   if (type.floating)
383      bld->elem_type = lp_build_elem_type(gallivm, type);
384   else
385      bld->elem_type = bld->int_elem_type;
386
387   if (type.length == 1) {
388      bld->int_vec_type = bld->int_elem_type;
389      bld->vec_type = bld->elem_type;
390   }
391   else {
392      bld->int_vec_type = LLVMVectorType(bld->int_elem_type, type.length);
393      bld->vec_type = LLVMVectorType(bld->elem_type, type.length);
394   }
395
396   bld->undef = LLVMGetUndef(bld->vec_type);
397   bld->zero = LLVMConstNull(bld->vec_type);
398   bld->one = lp_build_one(gallivm, type);
399}
400
401
402/**
403 * Count the number of instructions in a function.
404 */
405unsigned
406lp_build_count_instructions(LLVMValueRef function)
407{
408   unsigned num_instrs = 0;
409   LLVMBasicBlockRef block;
410
411   block = LLVMGetFirstBasicBlock(function);
412   while (block) {
413      LLVMValueRef instr;
414      instr = LLVMGetFirstInstruction(block);
415      while (instr) {
416         ++num_instrs;
417
418         instr = LLVMGetNextInstruction(instr);
419      }
420      block = LLVMGetNextBasicBlock(block);
421   }
422
423   return num_instrs;
424}
425