• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  /**
30   * @file
31   * Helper functions for constant building.
32   *
33   * @author Jose Fonseca <jfonseca@vmware.com>
34   */
35  
36  #include <float.h>
37  
38  #include "util/u_debug.h"
39  #include "util/u_math.h"
40  #include "util/u_half.h"
41  
42  #include "lp_bld_type.h"
43  #include "lp_bld_const.h"
44  #include "lp_bld_init.h"
45  
46  
47  unsigned
lp_mantissa(struct lp_type type)48  lp_mantissa(struct lp_type type)
49  {
50     assert(type.floating);
51  
52     if(type.floating) {
53        switch(type.width) {
54        case 16:
55           return 10;
56        case 32:
57           return 23;
58        case 64:
59           return 52;
60        default:
61           assert(0);
62           return 0;
63        }
64     }
65     else {
66        if(type.sign)
67           return type.width - 1;
68        else
69           return type.width;
70     }
71  }
72  
73  
74  /**
75   * Shift of the unity.
76   *
77   * Same as lp_const_scale(), but in terms of shifts.
78   */
79  unsigned
lp_const_shift(struct lp_type type)80  lp_const_shift(struct lp_type type)
81  {
82     if(type.floating)
83        return 0;
84     else if(type.fixed)
85        return type.width/2;
86     else if(type.norm)
87        return type.sign ? type.width - 1 : type.width;
88     else
89        return 0;
90  }
91  
92  
93  unsigned
lp_const_offset(struct lp_type type)94  lp_const_offset(struct lp_type type)
95  {
96     if(type.floating || type.fixed)
97        return 0;
98     else if(type.norm)
99        return 1;
100     else
101        return 0;
102  }
103  
104  
105  /**
106   * Scaling factor between the LLVM native value and its interpretation.
107   *
108   * This is 1.0 for all floating types and unnormalized integers, and something
109   * else for the fixed points types and normalized integers.
110   */
111  double
lp_const_scale(struct lp_type type)112  lp_const_scale(struct lp_type type)
113  {
114     unsigned long long llscale;
115     double dscale;
116  
117     llscale = (unsigned long long)1 << lp_const_shift(type);
118     llscale -= lp_const_offset(type);
119     dscale = (double)llscale;
120     assert((unsigned long long)dscale == llscale);
121  
122     return dscale;
123  }
124  
125  
126  /**
127   * Minimum value representable by the type.
128   */
129  double
lp_const_min(struct lp_type type)130  lp_const_min(struct lp_type type)
131  {
132     unsigned bits;
133  
134     if(!type.sign)
135        return 0.0;
136  
137     if(type.norm)
138        return -1.0;
139  
140     if (type.floating) {
141        switch(type.width) {
142        case 16:
143           return -65504;
144        case 32:
145           return -FLT_MAX;
146        case 64:
147           return -DBL_MAX;
148        default:
149           assert(0);
150           return 0.0;
151        }
152     }
153  
154     if(type.fixed)
155        /* FIXME: consider the fractional bits? */
156        bits = type.width / 2 - 1;
157     else
158        bits = type.width - 1;
159  
160     return (double)-((long long)1 << bits);
161  }
162  
163  
164  /**
165   * Maximum value representable by the type.
166   */
167  double
lp_const_max(struct lp_type type)168  lp_const_max(struct lp_type type)
169  {
170     unsigned bits;
171  
172     if(type.norm)
173        return 1.0;
174  
175     if (type.floating) {
176        switch(type.width) {
177        case 16:
178           return 65504;
179        case 32:
180           return FLT_MAX;
181        case 64:
182           return DBL_MAX;
183        default:
184           assert(0);
185           return 0.0;
186        }
187     }
188  
189     if(type.fixed)
190        bits = type.width / 2;
191     else
192        bits = type.width;
193  
194     if(type.sign)
195        bits -= 1;
196  
197     return (double)(((unsigned long long)1 << bits) - 1);
198  }
199  
200  
201  double
lp_const_eps(struct lp_type type)202  lp_const_eps(struct lp_type type)
203  {
204     if (type.floating) {
205        switch(type.width) {
206        case 16:
207           return 2E-10;
208        case 32:
209           return FLT_EPSILON;
210        case 64:
211           return DBL_EPSILON;
212        default:
213           assert(0);
214           return 0.0;
215        }
216     }
217     else {
218        double scale = lp_const_scale(type);
219        return 1.0/scale;
220     }
221  }
222  
223  
224  LLVMValueRef
lp_build_undef(struct gallivm_state * gallivm,struct lp_type type)225  lp_build_undef(struct gallivm_state *gallivm, struct lp_type type)
226  {
227     LLVMTypeRef vec_type = lp_build_vec_type(gallivm, type);
228     return LLVMGetUndef(vec_type);
229  }
230  
231  
232  LLVMValueRef
lp_build_zero(struct gallivm_state * gallivm,struct lp_type type)233  lp_build_zero(struct gallivm_state *gallivm, struct lp_type type)
234  {
235     if (type.length == 1) {
236        if (type.floating)
237           return lp_build_const_float(gallivm, 0.0);
238        else
239           return LLVMConstInt(LLVMIntTypeInContext(gallivm->context, type.width), 0, 0);
240     }
241     else {
242        LLVMTypeRef vec_type = lp_build_vec_type(gallivm, type);
243        return LLVMConstNull(vec_type);
244     }
245  }
246  
247  
248  LLVMValueRef
lp_build_one(struct gallivm_state * gallivm,struct lp_type type)249  lp_build_one(struct gallivm_state *gallivm, struct lp_type type)
250  {
251     LLVMTypeRef elem_type;
252     LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
253     unsigned i;
254  
255     assert(type.length <= LP_MAX_VECTOR_LENGTH);
256  
257     elem_type = lp_build_elem_type(gallivm, type);
258  
259     if(type.floating && type.width == 16)
260        elems[0] = LLVMConstInt(elem_type, util_float_to_half(1.0f), 0);
261     else if(type.floating)
262        elems[0] = LLVMConstReal(elem_type, 1.0);
263     else if(type.fixed)
264        elems[0] = LLVMConstInt(elem_type, 1LL << (type.width/2), 0);
265     else if(!type.norm)
266        elems[0] = LLVMConstInt(elem_type, 1, 0);
267     else if(type.sign)
268        elems[0] = LLVMConstInt(elem_type, (1LL << (type.width - 1)) - 1, 0);
269     else {
270        /* special case' -- 1.0 for normalized types is more easily attained if
271         * we start with a vector consisting of all bits set */
272        LLVMTypeRef vec_type = LLVMVectorType(elem_type, type.length);
273        LLVMValueRef vec = LLVMConstAllOnes(vec_type);
274  
275  #if 0
276        if(type.sign)
277           /* TODO: Unfortunately this caused "Tried to create a shift operation
278            * on a non-integer type!" */
279           vec = LLVMConstLShr(vec, lp_build_const_int_vec(type, 1));
280  #endif
281  
282        return vec;
283     }
284  
285     for(i = 1; i < type.length; ++i)
286        elems[i] = elems[0];
287  
288     if (type.length == 1)
289        return elems[0];
290     else
291        return LLVMConstVector(elems, type.length);
292  }
293  
294  
295  /**
296   * Build constant-valued element from a scalar value.
297   */
298  LLVMValueRef
lp_build_const_elem(struct gallivm_state * gallivm,struct lp_type type,double val)299  lp_build_const_elem(struct gallivm_state *gallivm,
300                      struct lp_type type,
301                      double val)
302  {
303     LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type);
304     LLVMValueRef elem;
305  
306     if(type.floating && type.width == 16) {
307        elem = LLVMConstInt(elem_type, util_float_to_half((float)val), 0);
308     } else if(type.floating) {
309        elem = LLVMConstReal(elem_type, val);
310     }
311     else {
312        double dscale = lp_const_scale(type);
313  
314        elem = LLVMConstInt(elem_type, round(val*dscale), 0);
315     }
316  
317     return elem;
318  }
319  
320  
321  /**
322   * Build constant-valued vector from a scalar value.
323   */
324  LLVMValueRef
lp_build_const_vec(struct gallivm_state * gallivm,struct lp_type type,double val)325  lp_build_const_vec(struct gallivm_state *gallivm, struct lp_type type,
326                     double val)
327  {
328     if (type.length == 1) {
329        return lp_build_const_elem(gallivm, type, val);
330     } else {
331        LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
332        unsigned i;
333        elems[0] = lp_build_const_elem(gallivm, type, val);
334        for(i = 1; i < type.length; ++i)
335           elems[i] = elems[0];
336        return LLVMConstVector(elems, type.length);
337     }
338  }
339  
340  
341  LLVMValueRef
lp_build_const_int_vec(struct gallivm_state * gallivm,struct lp_type type,long long val)342  lp_build_const_int_vec(struct gallivm_state *gallivm, struct lp_type type,
343                         long long val)
344  {
345     LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type);
346     LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
347     unsigned i;
348  
349     assert(type.length <= LP_MAX_VECTOR_LENGTH);
350  
351     for(i = 0; i < type.length; ++i)
352        elems[i] = LLVMConstInt(elem_type, val, type.sign ? 1 : 0);
353  
354     if (type.length == 1)
355        return elems[0];
356  
357     return LLVMConstVector(elems, type.length);
358  }
359  
360  
361  LLVMValueRef
lp_build_const_aos(struct gallivm_state * gallivm,struct lp_type type,double r,double g,double b,double a,const unsigned char * swizzle)362  lp_build_const_aos(struct gallivm_state *gallivm,
363                     struct lp_type type,
364                     double r, double g, double b, double a,
365                     const unsigned char *swizzle)
366  {
367     const unsigned char default_swizzle[4] = {0, 1, 2, 3};
368     LLVMTypeRef elem_type;
369     LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
370     unsigned i;
371  
372     assert(type.length % 4 == 0);
373     assert(type.length <= LP_MAX_VECTOR_LENGTH);
374  
375     elem_type = lp_build_elem_type(gallivm, type);
376  
377     if(swizzle == NULL)
378        swizzle = default_swizzle;
379  
380     elems[swizzle[0]] = lp_build_const_elem(gallivm, type, r);
381     elems[swizzle[1]] = lp_build_const_elem(gallivm, type, g);
382     elems[swizzle[2]] = lp_build_const_elem(gallivm, type, b);
383     elems[swizzle[3]] = lp_build_const_elem(gallivm, type, a);
384  
385     for(i = 4; i < type.length; ++i)
386        elems[i] = elems[i % 4];
387  
388     return LLVMConstVector(elems, type.length);
389  }
390  
391  
392  /**
393   * @param mask TGSI_WRITEMASK_xxx
394   */
395  LLVMValueRef
lp_build_const_mask_aos(struct gallivm_state * gallivm,struct lp_type type,unsigned mask)396  lp_build_const_mask_aos(struct gallivm_state *gallivm,
397                          struct lp_type type,
398                          unsigned mask)
399  {
400     LLVMTypeRef elem_type = LLVMIntTypeInContext(gallivm->context, type.width);
401     LLVMValueRef masks[LP_MAX_VECTOR_LENGTH];
402     unsigned i, j;
403  
404     assert(type.length <= LP_MAX_VECTOR_LENGTH);
405  
406     for (j = 0; j < type.length; j += 4) {
407        for( i = 0; i < 4; ++i) {
408           masks[j + i] = LLVMConstInt(elem_type,
409                                       mask & (1 << i) ? ~0ULL : 0,
410                                       1);
411        }
412     }
413  
414     return LLVMConstVector(masks, type.length);
415  }
416  
417  
418  /**
419   * Performs lp_build_const_mask_aos, but first swizzles the mask
420   */
421  LLVMValueRef
lp_build_const_mask_aos_swizzled(struct gallivm_state * gallivm,struct lp_type type,unsigned mask,const unsigned char * swizzle)422  lp_build_const_mask_aos_swizzled(struct gallivm_state *gallivm,
423                          struct lp_type type,
424                          unsigned mask,
425                          const unsigned char *swizzle)
426  {
427     mask =
428             ((mask & (1 << swizzle[0])) >> swizzle[0])
429          | (((mask & (1 << swizzle[1])) >> swizzle[1]) << 1)
430          | (((mask & (1 << swizzle[2])) >> swizzle[2]) << 2)
431          | (((mask & (1 << swizzle[3])) >> swizzle[3]) << 3);
432  
433     return lp_build_const_mask_aos(gallivm, type, mask);
434  }
435  
436  
437  /**
438   * Build a zero-terminated constant string.
439   */
440  LLVMValueRef
lp_build_const_string(struct gallivm_state * gallivm,const char * str)441  lp_build_const_string(struct gallivm_state *gallivm,
442                        const char *str)
443  {
444     unsigned len = strlen(str) + 1;
445     LLVMTypeRef i8 = LLVMInt8TypeInContext(gallivm->context);
446     LLVMValueRef string = LLVMAddGlobal(gallivm->module, LLVMArrayType(i8, len), "");
447     LLVMSetGlobalConstant(string, TRUE);
448     LLVMSetLinkage(string, LLVMInternalLinkage);
449     LLVMSetInitializer(string, LLVMConstStringInContext(gallivm->context, str, len, TRUE));
450     string = LLVMConstBitCast(string, LLVMPointerType(i8, 0));
451     return string;
452  }
453  
454  
455  /**
456   * Build a callable function pointer.
457   *
458   * We use function pointer constants instead of LLVMAddGlobalMapping()
459   * to work around a bug in LLVM 2.6, and for efficiency/simplicity.
460   */
461  LLVMValueRef
lp_build_const_func_pointer(struct gallivm_state * gallivm,const void * ptr,LLVMTypeRef ret_type,LLVMTypeRef * arg_types,unsigned num_args,const char * name)462  lp_build_const_func_pointer(struct gallivm_state *gallivm,
463                              const void *ptr,
464                              LLVMTypeRef ret_type,
465                              LLVMTypeRef *arg_types,
466                              unsigned num_args,
467                              const char *name)
468  {
469     LLVMTypeRef function_type;
470     LLVMValueRef function;
471  
472     function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0);
473  
474     function = lp_build_const_int_pointer(gallivm, ptr);
475  
476     function = LLVMBuildBitCast(gallivm->builder, function,
477                                 LLVMPointerType(function_type, 0),
478                                 name);
479  
480     return function;
481  }
482