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 <[email protected]>
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 /* Returns an integer vector of [0, 1, 2, ...] */
353 LLVMValueRef
lp_build_const_channel_vec(struct gallivm_state * gallivm,struct lp_type type)354 lp_build_const_channel_vec(struct gallivm_state *gallivm, struct lp_type type)
355 {
356 LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type);
357 LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
358
359 assert(type.length <= LP_MAX_VECTOR_LENGTH);
360
361 for (unsigned i = 0; i < type.length; ++i)
362 elems[i] = LLVMConstInt(elem_type, i, 0);
363
364 if (type.length == 1)
365 return elems[0];
366
367 return LLVMConstVector(elems, type.length);
368 }
369
370
371 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)372 lp_build_const_aos(struct gallivm_state *gallivm,
373 struct lp_type type,
374 double r, double g, double b, double a,
375 const unsigned char *swizzle)
376 {
377 const unsigned char default_swizzle[4] = {0, 1, 2, 3};
378 LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
379
380 assert(type.length % 4 == 0);
381 assert(type.length <= LP_MAX_VECTOR_LENGTH);
382
383 lp_build_elem_type(gallivm, type);
384
385 if (!swizzle)
386 swizzle = default_swizzle;
387
388 elems[swizzle[0]] = lp_build_const_elem(gallivm, type, r);
389 elems[swizzle[1]] = lp_build_const_elem(gallivm, type, g);
390 elems[swizzle[2]] = lp_build_const_elem(gallivm, type, b);
391 elems[swizzle[3]] = lp_build_const_elem(gallivm, type, a);
392
393 for (unsigned i = 4; i < type.length; ++i)
394 elems[i] = elems[i % 4];
395
396 return LLVMConstVector(elems, type.length);
397 }
398
399
400 /**
401 * @param mask TGSI_WRITEMASK_xxx
402 */
403 LLVMValueRef
lp_build_const_mask_aos(struct gallivm_state * gallivm,struct lp_type type,unsigned mask,unsigned channels)404 lp_build_const_mask_aos(struct gallivm_state *gallivm,
405 struct lp_type type,
406 unsigned mask,
407 unsigned channels)
408 {
409 LLVMTypeRef elem_type = LLVMIntTypeInContext(gallivm->context, type.width);
410 LLVMValueRef masks[LP_MAX_VECTOR_LENGTH];
411
412 assert(type.length <= LP_MAX_VECTOR_LENGTH);
413
414 for (unsigned j = 0; j < type.length; j += channels) {
415 for (unsigned i = 0; i < channels; ++i) {
416 masks[j + i] = LLVMConstInt(elem_type,
417 mask & (1 << i) ? ~0ULL : 0,
418 1);
419 }
420 }
421
422 return LLVMConstVector(masks, type.length);
423 }
424
425
426 /**
427 * Performs lp_build_const_mask_aos, but first swizzles the mask
428 */
429 LLVMValueRef
lp_build_const_mask_aos_swizzled(struct gallivm_state * gallivm,struct lp_type type,unsigned mask,unsigned channels,const unsigned char * swizzle)430 lp_build_const_mask_aos_swizzled(struct gallivm_state *gallivm,
431 struct lp_type type,
432 unsigned mask,
433 unsigned channels,
434 const unsigned char *swizzle)
435 {
436 unsigned mask_swizzled = 0;
437
438 for (unsigned i = 0; i < channels; ++i) {
439 if (swizzle[i] < 4) {
440 mask_swizzled |= ((mask & (1 << swizzle[i])) >> swizzle[i]) << i;
441 }
442 }
443
444 return lp_build_const_mask_aos(gallivm, type, mask_swizzled, channels);
445 }
446
447
448 /**
449 * Build a zero-terminated constant string.
450 */
451 LLVMValueRef
lp_build_const_string(struct gallivm_state * gallivm,const char * str)452 lp_build_const_string(struct gallivm_state *gallivm,
453 const char *str)
454 {
455 unsigned len = strlen(str) + 1;
456 LLVMTypeRef i8 = LLVMInt8TypeInContext(gallivm->context);
457 LLVMValueRef string = LLVMAddGlobal(gallivm->module, LLVMArrayType(i8, len), "");
458 LLVMSetGlobalConstant(string, true);
459 LLVMSetLinkage(string, LLVMInternalLinkage);
460 LLVMSetInitializer(string, LLVMConstStringInContext(gallivm->context, str, len, true));
461 string = LLVMConstBitCast(string, LLVMPointerType(i8, 0));
462 return string;
463 }
464
465
466 LLVMValueRef
lp_build_const_func_pointer_from_type(struct gallivm_state * gallivm,const void * ptr,LLVMTypeRef function_type,const char * name)467 lp_build_const_func_pointer_from_type(struct gallivm_state *gallivm,
468 const void *ptr,
469 LLVMTypeRef function_type,
470 const char *name)
471 {
472 return LLVMBuildBitCast(gallivm->builder,
473 lp_build_const_int_pointer(gallivm, ptr),
474 LLVMPointerType(function_type, 0),
475 name);
476 }
477
478
479 /**
480 * Build a callable function pointer.
481 *
482 * We use function pointer constants instead of LLVMAddGlobalMapping()
483 * to work around a bug in LLVM 2.6, and for efficiency/simplicity.
484 */
485 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)486 lp_build_const_func_pointer(struct gallivm_state *gallivm,
487 const void *ptr,
488 LLVMTypeRef ret_type,
489 LLVMTypeRef *arg_types,
490 unsigned num_args,
491 const char *name)
492 {
493 LLVMTypeRef function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0);
494 return lp_build_const_func_pointer_from_type(gallivm, ptr, function_type, name);
495 }
496