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 * @file
30 * Convenient representation of SIMD types.
31 *
32 * @author Jose Fonseca <jfonseca@vmware.com>
33 */
34
35
36 #ifndef LP_BLD_TYPE_H
37 #define LP_BLD_TYPE_H
38
39
40 #include "util/format/u_format.h"
41 #include "util/compiler.h"
42 #include "gallivm/lp_bld.h"
43
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47
48 /**
49 * Native SIMD architecture width available at runtime.
50 *
51 * Using this width should give the best performance,
52 * and it determines the necessary alignment of vector variables.
53 */
54 extern unsigned lp_native_vector_width;
55
56 /**
57 * Maximum supported vector width (not necessarily supported at run-time).
58 *
59 * Should only be used when lp_native_vector_width isn't available,
60 * i.e. sizing/alignment of non-malloced variables.
61 */
62 #define LP_MAX_VECTOR_WIDTH 512
63
64 /**
65 * Minimum vector alignment for static variable alignment
66 *
67 * It should always be a constant equal to LP_MAX_VECTOR_WIDTH/8. An
68 * expression is non-portable.
69 */
70 #define LP_MIN_VECTOR_ALIGN 64
71
72 /**
73 * Several functions can only cope with vectors of length up to this value.
74 * You may need to increase that value if you want to represent bigger vectors.
75 */
76 #define LP_MAX_VECTOR_LENGTH (LP_MAX_VECTOR_WIDTH/8)
77
78 /**
79 * The LLVM type system can't conveniently express all the things we care about
80 * on the types used for intermediate computations, such as signed vs unsigned,
81 * normalized values, or fixed point.
82 */
83 struct lp_type {
84 /**
85 * Floating-point. Cannot be used with fixed. Integer numbers are
86 * represented by this zero.
87 */
88 unsigned floating:1;
89
90 /**
91 * Fixed-point. Cannot be used with floating. Integer numbers are
92 * represented by this zero.
93 */
94 unsigned fixed:1;
95
96 /**
97 * Whether it can represent negative values or not.
98 *
99 * If this is not set for floating point, it means that all values are
100 * assumed to be positive.
101 */
102 unsigned sign:1;
103
104 /**
105 * Whether values are normalized to fit [0, 1] interval, or [-1, 1]
106 * interval for signed types.
107 *
108 * For integer types it means the representable integer range should be
109 * interpreted as the interval above.
110 *
111 * For floating and fixed point formats it means the values should be
112 * clamped to the interval above.
113 */
114 unsigned norm:1;
115
116 /** Arithmetic operations that use this type can not flust -0 to 0. */
117 unsigned signed_zero_preserve:1;
118
119 /** Arithmetic operations that use this type can not flust nan to 0. */
120 unsigned nan_preserve:1;
121
122 /**
123 * Element width.
124 *
125 * For fixed point values, the fixed point is assumed to be at half the
126 * width.
127 */
128 unsigned width:14;
129
130 /**
131 * Vector length. If length==1, this is a scalar (float/int) type.
132 *
133 * width*length should be a power of two greater or equal to eight.
134 *
135 * @sa LP_MAX_VECTOR_LENGTH
136 */
137 unsigned length:14;
138 };
139
140
141 /**
142 * We need most of the information here in order to correctly and efficiently
143 * translate an arithmetic operation into LLVM IR. Putting it here avoids the
144 * trouble of passing it as parameters.
145 */
146 struct lp_build_context
147 {
148 struct gallivm_state *gallivm;
149
150 /**
151 * This not only describes the input/output LLVM types, but also whether
152 * to normalize/clamp the results.
153 */
154 struct lp_type type;
155
156 /** Same as lp_build_elem_type(type) */
157 LLVMTypeRef elem_type;
158
159 /** Same as lp_build_vec_type(type) */
160 LLVMTypeRef vec_type;
161
162 /** Same as lp_build_int_elem_type(type) */
163 LLVMTypeRef int_elem_type;
164
165 /** Same as lp_build_int_vec_type(type) */
166 LLVMTypeRef int_vec_type;
167
168 /** Same as lp_build_undef(type) */
169 LLVMValueRef undef;
170
171 /** Same as lp_build_zero(type) */
172 LLVMValueRef zero;
173
174 /** Same as lp_build_one(type) */
175 LLVMValueRef one;
176 };
177
178
179 /**
180 * Converts a format description into an lp_type.
181 *
182 * Only works with "array formats".
183 *
184 * e.g. With PIPE_FORMAT_R32G32B32A32_FLOAT returns an lp_type with float[4]
185 */
186 static inline void
lp_type_from_format_desc(struct lp_type * type,const struct util_format_description * format_desc)187 lp_type_from_format_desc(struct lp_type* type, const struct util_format_description *format_desc)
188 {
189 assert(format_desc->is_array);
190 assert(!format_desc->is_mixed);
191
192 memset(type, 0, sizeof(struct lp_type));
193 type->floating = format_desc->channel[0].type == UTIL_FORMAT_TYPE_FLOAT;
194 type->fixed = format_desc->channel[0].type == UTIL_FORMAT_TYPE_FIXED;
195 type->sign = format_desc->channel[0].type != UTIL_FORMAT_TYPE_UNSIGNED;
196 type->norm = format_desc->channel[0].normalized;
197 type->width = format_desc->channel[0].size;
198 type->length = format_desc->nr_channels;
199 }
200
201
202 static inline void
lp_type_from_format(struct lp_type * type,enum pipe_format format)203 lp_type_from_format(struct lp_type* type, enum pipe_format format)
204 {
205 lp_type_from_format_desc(type, util_format_description(format));
206 }
207
208
209 static inline unsigned
lp_type_width(struct lp_type type)210 lp_type_width(struct lp_type type)
211 {
212 return type.width * type.length;
213 }
214
215
216 /** Create scalar float type */
217 static inline struct lp_type
lp_type_float(unsigned width)218 lp_type_float(unsigned width)
219 {
220 struct lp_type res_type;
221
222 memset(&res_type, 0, sizeof res_type);
223 res_type.floating = true;
224 res_type.sign = true;
225 res_type.width = width;
226 res_type.length = 1;
227
228 return res_type;
229 }
230
231
232 /** Create vector of float type */
233 static inline struct lp_type
lp_type_float_vec(unsigned width,unsigned total_width)234 lp_type_float_vec(unsigned width, unsigned total_width)
235 {
236 struct lp_type res_type;
237
238 memset(&res_type, 0, sizeof res_type);
239 res_type.floating = true;
240 res_type.sign = true;
241 res_type.width = width;
242 res_type.length = total_width / width;
243
244 return res_type;
245 }
246
247
248 /** Create scalar int type */
249 static inline struct lp_type
lp_type_int(unsigned width)250 lp_type_int(unsigned width)
251 {
252 struct lp_type res_type;
253
254 memset(&res_type, 0, sizeof res_type);
255 res_type.sign = true;
256 res_type.width = width;
257 res_type.length = 1;
258
259 return res_type;
260 }
261
262
263 /** Create vector int type */
264 static inline struct lp_type
lp_type_int_vec(unsigned width,unsigned total_width)265 lp_type_int_vec(unsigned width, unsigned total_width)
266 {
267 struct lp_type res_type;
268
269 memset(&res_type, 0, sizeof res_type);
270 res_type.sign = true;
271 res_type.width = width;
272 res_type.length = total_width / width;
273
274 return res_type;
275 }
276
277
278 /** Create scalar uint type */
279 static inline struct lp_type
lp_type_uint(unsigned width)280 lp_type_uint(unsigned width)
281 {
282 struct lp_type res_type;
283
284 memset(&res_type, 0, sizeof res_type);
285 res_type.width = width;
286 res_type.length = 1;
287
288 return res_type;
289 }
290
291
292 /** Create vector uint type */
293 static inline struct lp_type
lp_type_uint_vec(unsigned width,unsigned total_width)294 lp_type_uint_vec(unsigned width, unsigned total_width)
295 {
296 struct lp_type res_type;
297
298 memset(&res_type, 0, sizeof res_type);
299 res_type.width = width;
300 res_type.length = total_width / width;
301
302 return res_type;
303 }
304
305
306 static inline struct lp_type
lp_type_unorm(unsigned width,unsigned total_width)307 lp_type_unorm(unsigned width, unsigned total_width)
308 {
309 struct lp_type res_type;
310
311 memset(&res_type, 0, sizeof res_type);
312 res_type.norm = true;
313 res_type.width = width;
314 res_type.length = total_width / width;
315
316 return res_type;
317 }
318
319
320 static inline struct lp_type
lp_type_fixed(unsigned width,unsigned total_width)321 lp_type_fixed(unsigned width, unsigned total_width)
322 {
323 struct lp_type res_type;
324
325 memset(&res_type, 0, sizeof res_type);
326 res_type.sign = true;
327 res_type.fixed = true;
328 res_type.width = width;
329 res_type.length = total_width / width;
330
331 return res_type;
332 }
333
334
335 static inline struct lp_type
lp_type_ufixed(unsigned width,unsigned total_width)336 lp_type_ufixed(unsigned width, unsigned total_width)
337 {
338 struct lp_type res_type;
339
340 memset(&res_type, 0, sizeof res_type);
341 res_type.fixed = true;
342 res_type.width = width;
343 res_type.length = total_width / width;
344
345 return res_type;
346 }
347
348
349 LLVMTypeRef
350 lp_build_elem_type(const struct gallivm_state *gallivm, struct lp_type type);
351
352
353 LLVMTypeRef
354 lp_build_vec_type(const struct gallivm_state *gallivm, struct lp_type type);
355
356
357 bool
358 lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type);
359
360
361 bool
362 lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type);
363
364
365 bool
366 lp_check_value(struct lp_type type, LLVMValueRef val);
367
368
369 LLVMTypeRef
370 lp_build_int_elem_type(const struct gallivm_state *gallivm,
371 struct lp_type type);
372
373
374 LLVMTypeRef
375 lp_build_int_vec_type(const struct gallivm_state *gallivm,
376 struct lp_type type);
377
378
379 static inline struct lp_type
lp_float32_vec4_type(void)380 lp_float32_vec4_type(void)
381 {
382 struct lp_type type;
383
384 memset(&type, 0, sizeof(type));
385 type.floating = true;
386 type.sign = true;
387 type.norm = false;
388 type.width = 32;
389 type.length = 4;
390
391 return type;
392 }
393
394
395 static inline struct lp_type
lp_int32_vec4_type(void)396 lp_int32_vec4_type(void)
397 {
398 struct lp_type type;
399
400 memset(&type, 0, sizeof(type));
401 type.floating = false;
402 type.sign = true;
403 type.norm = false;
404 type.width = 32;
405 type.length = 4;
406
407 return type;
408 }
409
410
411 static inline struct lp_type
lp_unorm8_vec4_type(void)412 lp_unorm8_vec4_type(void)
413 {
414 struct lp_type type;
415
416 memset(&type, 0, sizeof(type));
417 type.floating = false;
418 type.sign = false;
419 type.norm = true;
420 type.width = 8;
421 type.length = 4;
422
423 return type;
424 }
425
426
427 struct lp_type
428 lp_elem_type(struct lp_type type);
429
430
431 struct lp_type
432 lp_uint_type(struct lp_type type);
433
434
435 struct lp_type
436 lp_int_type(struct lp_type type);
437
438
439 struct lp_type
440 lp_wider_type(struct lp_type type);
441
442
443 unsigned
444 lp_sizeof_llvm_type(LLVMTypeRef t);
445
446
447 const char *
448 lp_typekind_name(LLVMTypeKind t);
449
450
451 void
452 lp_dump_llvmtype(LLVMTypeRef t);
453
454
455 void
456 lp_build_context_init(struct lp_build_context *bld,
457 struct gallivm_state *gallivm,
458 struct lp_type type);
459
460
461 unsigned
462 lp_build_count_ir_module(LLVMModuleRef module);
463
464 #ifdef __cplusplus
465 }
466 #endif
467
468 #endif /* !LP_BLD_TYPE_H */
469