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