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 (at) vmware.com> 33 */ 34 35 36 #ifndef LP_BLD_TYPE_H 37 #define LP_BLD_TYPE_H 38 39 40 #include "util/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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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