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 "pipe/p_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 /**
117 * Element width.
118 *
119 * For fixed point values, the fixed point is assumed to be at half the
120 * width.
121 */
122 unsigned width:14;
123
124 /**
125 * Vector length. If length==1, this is a scalar (float/int) type.
126 *
127 * width*length should be a power of two greater or equal to eight.
128 *
129 * @sa LP_MAX_VECTOR_LENGTH
130 */
131 unsigned length:14;
132 };
133
134
135 /**
136 * We need most of the information here in order to correctly and efficiently
137 * translate an arithmetic operation into LLVM IR. Putting it here avoids the
138 * trouble of passing it as parameters.
139 */
140 struct lp_build_context
141 {
142 struct gallivm_state *gallivm;
143
144 /**
145 * This not only describes the input/output LLVM types, but also whether
146 * to normalize/clamp the results.
147 */
148 struct lp_type type;
149
150 /** Same as lp_build_elem_type(type) */
151 LLVMTypeRef elem_type;
152
153 /** Same as lp_build_vec_type(type) */
154 LLVMTypeRef vec_type;
155
156 /** Same as lp_build_int_elem_type(type) */
157 LLVMTypeRef int_elem_type;
158
159 /** Same as lp_build_int_vec_type(type) */
160 LLVMTypeRef int_vec_type;
161
162 /** Same as lp_build_undef(type) */
163 LLVMValueRef undef;
164
165 /** Same as lp_build_zero(type) */
166 LLVMValueRef zero;
167
168 /** Same as lp_build_one(type) */
169 LLVMValueRef one;
170 };
171
172
173 /**
174 * Converts a format description into an lp_type.
175 *
176 * Only works with "array formats".
177 *
178 * e.g. With PIPE_FORMAT_R32G32B32A32_FLOAT returns an lp_type with float[4]
179 */
180 static inline void
lp_type_from_format_desc(struct lp_type * type,const struct util_format_description * format_desc)181 lp_type_from_format_desc(struct lp_type* type, const struct util_format_description *format_desc)
182 {
183 assert(format_desc->is_array);
184 assert(!format_desc->is_mixed);
185
186 memset(type, 0, sizeof(struct lp_type));
187 type->floating = format_desc->channel[0].type == UTIL_FORMAT_TYPE_FLOAT;
188 type->fixed = format_desc->channel[0].type == UTIL_FORMAT_TYPE_FIXED;
189 type->sign = format_desc->channel[0].type != UTIL_FORMAT_TYPE_UNSIGNED;
190 type->norm = format_desc->channel[0].normalized;
191 type->width = format_desc->channel[0].size;
192 type->length = format_desc->nr_channels;
193 }
194
195
196 static inline void
lp_type_from_format(struct lp_type * type,enum pipe_format format)197 lp_type_from_format(struct lp_type* type, enum pipe_format format)
198 {
199 lp_type_from_format_desc(type, util_format_description(format));
200 }
201
202
203 static inline unsigned
lp_type_width(struct lp_type type)204 lp_type_width(struct lp_type type)
205 {
206 return type.width * type.length;
207 }
208
209
210 /** Create scalar float type */
211 static inline struct lp_type
lp_type_float(unsigned width)212 lp_type_float(unsigned width)
213 {
214 struct lp_type res_type;
215
216 memset(&res_type, 0, sizeof res_type);
217 res_type.floating = TRUE;
218 res_type.sign = TRUE;
219 res_type.width = width;
220 res_type.length = 1;
221
222 return res_type;
223 }
224
225
226 /** Create vector of float type */
227 static inline struct lp_type
lp_type_float_vec(unsigned width,unsigned total_width)228 lp_type_float_vec(unsigned width, unsigned total_width)
229 {
230 struct lp_type res_type;
231
232 memset(&res_type, 0, sizeof res_type);
233 res_type.floating = TRUE;
234 res_type.sign = TRUE;
235 res_type.width = width;
236 res_type.length = total_width / width;
237
238 return res_type;
239 }
240
241
242 /** Create scalar int type */
243 static inline struct lp_type
lp_type_int(unsigned width)244 lp_type_int(unsigned width)
245 {
246 struct lp_type res_type;
247
248 memset(&res_type, 0, sizeof res_type);
249 res_type.sign = TRUE;
250 res_type.width = width;
251 res_type.length = 1;
252
253 return res_type;
254 }
255
256
257 /** Create vector int type */
258 static inline struct lp_type
lp_type_int_vec(unsigned width,unsigned total_width)259 lp_type_int_vec(unsigned width, unsigned total_width)
260 {
261 struct lp_type res_type;
262
263 memset(&res_type, 0, sizeof res_type);
264 res_type.sign = TRUE;
265 res_type.width = width;
266 res_type.length = total_width / width;
267
268 return res_type;
269 }
270
271
272 /** Create scalar uint type */
273 static inline struct lp_type
lp_type_uint(unsigned width)274 lp_type_uint(unsigned width)
275 {
276 struct lp_type res_type;
277
278 memset(&res_type, 0, sizeof res_type);
279 res_type.width = width;
280 res_type.length = 1;
281
282 return res_type;
283 }
284
285
286 /** Create vector uint type */
287 static inline struct lp_type
lp_type_uint_vec(unsigned width,unsigned total_width)288 lp_type_uint_vec(unsigned width, unsigned total_width)
289 {
290 struct lp_type res_type;
291
292 memset(&res_type, 0, sizeof res_type);
293 res_type.width = width;
294 res_type.length = total_width / width;
295
296 return res_type;
297 }
298
299
300 static inline struct lp_type
lp_type_unorm(unsigned width,unsigned total_width)301 lp_type_unorm(unsigned width, unsigned total_width)
302 {
303 struct lp_type res_type;
304
305 memset(&res_type, 0, sizeof res_type);
306 res_type.norm = TRUE;
307 res_type.width = width;
308 res_type.length = total_width / width;
309
310 return res_type;
311 }
312
313
314 static inline struct lp_type
lp_type_fixed(unsigned width,unsigned total_width)315 lp_type_fixed(unsigned width, unsigned total_width)
316 {
317 struct lp_type res_type;
318
319 memset(&res_type, 0, sizeof res_type);
320 res_type.sign = TRUE;
321 res_type.fixed = TRUE;
322 res_type.width = width;
323 res_type.length = total_width / width;
324
325 return res_type;
326 }
327
328
329 static inline struct lp_type
lp_type_ufixed(unsigned width,unsigned total_width)330 lp_type_ufixed(unsigned width, unsigned total_width)
331 {
332 struct lp_type res_type;
333
334 memset(&res_type, 0, sizeof res_type);
335 res_type.fixed = TRUE;
336 res_type.width = width;
337 res_type.length = total_width / width;
338
339 return res_type;
340 }
341
342
343 LLVMTypeRef
344 lp_build_elem_type(struct gallivm_state *gallivm, struct lp_type type);
345
346
347 LLVMTypeRef
348 lp_build_vec_type(struct gallivm_state *gallivm, struct lp_type type);
349
350
351 boolean
352 lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type);
353
354
355 boolean
356 lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type);
357
358
359 boolean
360 lp_check_value(struct lp_type type, LLVMValueRef val);
361
362
363 LLVMTypeRef
364 lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type);
365
366
367 LLVMTypeRef
368 lp_build_int_vec_type(struct gallivm_state *gallivm, struct lp_type type);
369
370
371 static inline struct lp_type
lp_float32_vec4_type(void)372 lp_float32_vec4_type(void)
373 {
374 struct lp_type type;
375
376 memset(&type, 0, sizeof(type));
377 type.floating = TRUE;
378 type.sign = TRUE;
379 type.norm = FALSE;
380 type.width = 32;
381 type.length = 4;
382
383 return type;
384 }
385
386
387 static inline struct lp_type
lp_int32_vec4_type(void)388 lp_int32_vec4_type(void)
389 {
390 struct lp_type type;
391
392 memset(&type, 0, sizeof(type));
393 type.floating = FALSE;
394 type.sign = TRUE;
395 type.norm = FALSE;
396 type.width = 32;
397 type.length = 4;
398
399 return type;
400 }
401
402
403 static inline struct lp_type
lp_unorm8_vec4_type(void)404 lp_unorm8_vec4_type(void)
405 {
406 struct lp_type type;
407
408 memset(&type, 0, sizeof(type));
409 type.floating = FALSE;
410 type.sign = FALSE;
411 type.norm = TRUE;
412 type.width = 8;
413 type.length = 4;
414
415 return type;
416 }
417
418
419 struct lp_type
420 lp_elem_type(struct lp_type type);
421
422
423 struct lp_type
424 lp_uint_type(struct lp_type type);
425
426
427 struct lp_type
428 lp_int_type(struct lp_type type);
429
430
431 struct lp_type
432 lp_wider_type(struct lp_type type);
433
434
435 unsigned
436 lp_sizeof_llvm_type(LLVMTypeRef t);
437
438
439 const char *
440 lp_typekind_name(LLVMTypeKind t);
441
442
443 void
444 lp_dump_llvmtype(LLVMTypeRef t);
445
446
447 void
448 lp_build_context_init(struct lp_build_context *bld,
449 struct gallivm_state *gallivm,
450 struct lp_type type);
451
452
453 unsigned
454 lp_build_count_ir_module(LLVMModuleRef module);
455
456 #ifdef __cplusplus
457 }
458 #endif
459
460 #endif /* !LP_BLD_TYPE_H */
461