Home | History | Annotate | Download | only in gallivm
      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