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