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