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