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