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