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