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 */
49extern 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 */
78struct 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 */
135struct 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
168static INLINE unsigned
169lp_type_width(struct lp_type type)
170{
171   return type.width * type.length;
172}
173
174
175/** Create scalar float type */
176static INLINE struct lp_type
177lp_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 */
192static INLINE struct lp_type
193lp_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 */
208static INLINE struct lp_type
209lp_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 */
223static INLINE struct lp_type
224lp_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 */
238static INLINE struct lp_type
239lp_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 */
252static INLINE struct lp_type
253lp_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
265static INLINE struct lp_type
266lp_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
279static INLINE struct lp_type
280lp_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
294static INLINE struct lp_type
295lp_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
308LLVMTypeRef
309lp_build_elem_type(struct gallivm_state *gallivm, struct lp_type type);
310
311
312LLVMTypeRef
313lp_build_vec_type(struct gallivm_state *gallivm, struct lp_type type);
314
315
316boolean
317lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type);
318
319
320boolean
321lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type);
322
323
324boolean
325lp_check_value(struct lp_type type, LLVMValueRef val);
326
327
328LLVMTypeRef
329lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type);
330
331
332LLVMTypeRef
333lp_build_int_vec_type(struct gallivm_state *gallivm, struct lp_type type);
334
335
336static INLINE struct lp_type
337lp_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
352static INLINE struct lp_type
353lp_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
368static INLINE struct lp_type
369lp_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
384struct lp_type
385lp_elem_type(struct lp_type type);
386
387
388struct lp_type
389lp_uint_type(struct lp_type type);
390
391
392struct lp_type
393lp_int_type(struct lp_type type);
394
395
396struct lp_type
397lp_wider_type(struct lp_type type);
398
399
400unsigned
401lp_sizeof_llvm_type(LLVMTypeRef t);
402
403
404const char *
405lp_typekind_name(LLVMTypeKind t);
406
407
408void
409lp_dump_llvmtype(LLVMTypeRef t);
410
411
412void
413lp_build_context_init(struct lp_build_context *bld,
414                      struct gallivm_state *gallivm,
415                      struct lp_type type);
416
417
418unsigned
419lp_build_count_instructions(LLVMValueRef function);
420
421
422#endif /* !LP_BLD_TYPE_H */
423