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 /**
     30  * @file
     31  * Helper functions for constant building.
     32  *
     33  * @author Jose Fonseca <jfonseca (at) vmware.com>
     34  */
     35 
     36 #include <float.h>
     37 
     38 #include "util/u_debug.h"
     39 #include "util/u_math.h"
     40 #include "util/u_half.h"
     41 
     42 #include "lp_bld_type.h"
     43 #include "lp_bld_const.h"
     44 #include "lp_bld_init.h"
     45 
     46 
     47 unsigned
     48 lp_mantissa(struct lp_type type)
     49 {
     50    assert(type.floating);
     51 
     52    if(type.floating) {
     53       switch(type.width) {
     54       case 16:
     55          return 10;
     56       case 32:
     57          return 23;
     58       case 64:
     59          return 52;
     60       default:
     61          assert(0);
     62          return 0;
     63       }
     64    }
     65    else {
     66       if(type.sign)
     67          return type.width - 1;
     68       else
     69          return type.width;
     70    }
     71 }
     72 
     73 
     74 /**
     75  * Shift of the unity.
     76  *
     77  * Same as lp_const_scale(), but in terms of shifts.
     78  */
     79 unsigned
     80 lp_const_shift(struct lp_type type)
     81 {
     82    if(type.floating)
     83       return 0;
     84    else if(type.fixed)
     85       return type.width/2;
     86    else if(type.norm)
     87       return type.sign ? type.width - 1 : type.width;
     88    else
     89       return 0;
     90 }
     91 
     92 
     93 unsigned
     94 lp_const_offset(struct lp_type type)
     95 {
     96    if(type.floating || type.fixed)
     97       return 0;
     98    else if(type.norm)
     99       return 1;
    100    else
    101       return 0;
    102 }
    103 
    104 
    105 /**
    106  * Scaling factor between the LLVM native value and its interpretation.
    107  *
    108  * This is 1.0 for all floating types and unnormalized integers, and something
    109  * else for the fixed points types and normalized integers.
    110  */
    111 double
    112 lp_const_scale(struct lp_type type)
    113 {
    114    unsigned long long llscale;
    115    double dscale;
    116 
    117    llscale = (unsigned long long)1 << lp_const_shift(type);
    118    llscale -= lp_const_offset(type);
    119    dscale = (double)llscale;
    120    assert((unsigned long long)dscale == llscale);
    121 
    122    return dscale;
    123 }
    124 
    125 
    126 /**
    127  * Minimum value representable by the type.
    128  */
    129 double
    130 lp_const_min(struct lp_type type)
    131 {
    132    unsigned bits;
    133 
    134    if(!type.sign)
    135       return 0.0;
    136 
    137    if(type.norm)
    138       return -1.0;
    139 
    140    if (type.floating) {
    141       switch(type.width) {
    142       case 16:
    143          return -65504;
    144       case 32:
    145          return -FLT_MAX;
    146       case 64:
    147          return -DBL_MAX;
    148       default:
    149          assert(0);
    150          return 0.0;
    151       }
    152    }
    153 
    154    if(type.fixed)
    155       /* FIXME: consider the fractional bits? */
    156       bits = type.width / 2 - 1;
    157    else
    158       bits = type.width - 1;
    159 
    160    return (double)-((long long)1 << bits);
    161 }
    162 
    163 
    164 /**
    165  * Maximum value representable by the type.
    166  */
    167 double
    168 lp_const_max(struct lp_type type)
    169 {
    170    unsigned bits;
    171 
    172    if(type.norm)
    173       return 1.0;
    174 
    175    if (type.floating) {
    176       switch(type.width) {
    177       case 16:
    178          return 65504;
    179       case 32:
    180          return FLT_MAX;
    181       case 64:
    182          return DBL_MAX;
    183       default:
    184          assert(0);
    185          return 0.0;
    186       }
    187    }
    188 
    189    if(type.fixed)
    190       bits = type.width / 2;
    191    else
    192       bits = type.width;
    193 
    194    if(type.sign)
    195       bits -= 1;
    196 
    197    return (double)(((unsigned long long)1 << bits) - 1);
    198 }
    199 
    200 
    201 double
    202 lp_const_eps(struct lp_type type)
    203 {
    204    if (type.floating) {
    205       switch(type.width) {
    206       case 16:
    207          return 2E-10;
    208       case 32:
    209          return FLT_EPSILON;
    210       case 64:
    211          return DBL_EPSILON;
    212       default:
    213          assert(0);
    214          return 0.0;
    215       }
    216    }
    217    else {
    218       double scale = lp_const_scale(type);
    219       return 1.0/scale;
    220    }
    221 }
    222 
    223 
    224 LLVMValueRef
    225 lp_build_undef(struct gallivm_state *gallivm, struct lp_type type)
    226 {
    227    LLVMTypeRef vec_type = lp_build_vec_type(gallivm, type);
    228    return LLVMGetUndef(vec_type);
    229 }
    230 
    231 
    232 LLVMValueRef
    233 lp_build_zero(struct gallivm_state *gallivm, struct lp_type type)
    234 {
    235    if (type.length == 1) {
    236       if (type.floating)
    237          return lp_build_const_float(gallivm, 0.0);
    238       else
    239          return LLVMConstInt(LLVMIntTypeInContext(gallivm->context, type.width), 0, 0);
    240    }
    241    else {
    242       LLVMTypeRef vec_type = lp_build_vec_type(gallivm, type);
    243       return LLVMConstNull(vec_type);
    244    }
    245 }
    246 
    247 
    248 LLVMValueRef
    249 lp_build_one(struct gallivm_state *gallivm, struct lp_type type)
    250 {
    251    LLVMTypeRef elem_type;
    252    LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    253    unsigned i;
    254 
    255    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    256 
    257    elem_type = lp_build_elem_type(gallivm, type);
    258 
    259    if(type.floating && type.width == 16)
    260       elems[0] = LLVMConstInt(elem_type, util_float_to_half(1.0f), 0);
    261    else if(type.floating)
    262       elems[0] = LLVMConstReal(elem_type, 1.0);
    263    else if(type.fixed)
    264       elems[0] = LLVMConstInt(elem_type, 1LL << (type.width/2), 0);
    265    else if(!type.norm)
    266       elems[0] = LLVMConstInt(elem_type, 1, 0);
    267    else if(type.sign)
    268       elems[0] = LLVMConstInt(elem_type, (1LL << (type.width - 1)) - 1, 0);
    269    else {
    270       /* special case' -- 1.0 for normalized types is more easily attained if
    271        * we start with a vector consisting of all bits set */
    272       LLVMTypeRef vec_type = LLVMVectorType(elem_type, type.length);
    273       LLVMValueRef vec = LLVMConstAllOnes(vec_type);
    274 
    275 #if 0
    276       if(type.sign)
    277          /* TODO: Unfortunately this caused "Tried to create a shift operation
    278           * on a non-integer type!" */
    279          vec = LLVMConstLShr(vec, lp_build_const_int_vec(type, 1));
    280 #endif
    281 
    282       return vec;
    283    }
    284 
    285    for(i = 1; i < type.length; ++i)
    286       elems[i] = elems[0];
    287 
    288    if (type.length == 1)
    289       return elems[0];
    290    else
    291       return LLVMConstVector(elems, type.length);
    292 }
    293 
    294 
    295 /**
    296  * Build constant-valued element from a scalar value.
    297  */
    298 LLVMValueRef
    299 lp_build_const_elem(struct gallivm_state *gallivm,
    300                     struct lp_type type,
    301                     double val)
    302 {
    303    LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type);
    304    LLVMValueRef elem;
    305 
    306    if(type.floating && type.width == 16) {
    307       elem = LLVMConstInt(elem_type, util_float_to_half((float)val), 0);
    308    } else if(type.floating) {
    309       elem = LLVMConstReal(elem_type, val);
    310    }
    311    else {
    312       double dscale = lp_const_scale(type);
    313 
    314       elem = LLVMConstInt(elem_type, round(val*dscale), 0);
    315    }
    316 
    317    return elem;
    318 }
    319 
    320 
    321 /**
    322  * Build constant-valued vector from a scalar value.
    323  */
    324 LLVMValueRef
    325 lp_build_const_vec(struct gallivm_state *gallivm, struct lp_type type,
    326                    double val)
    327 {
    328    if (type.length == 1) {
    329       return lp_build_const_elem(gallivm, type, val);
    330    } else {
    331       LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    332       unsigned i;
    333       elems[0] = lp_build_const_elem(gallivm, type, val);
    334       for(i = 1; i < type.length; ++i)
    335          elems[i] = elems[0];
    336       return LLVMConstVector(elems, type.length);
    337    }
    338 }
    339 
    340 
    341 LLVMValueRef
    342 lp_build_const_int_vec(struct gallivm_state *gallivm, struct lp_type type,
    343                        long long val)
    344 {
    345    LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type);
    346    LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    347    unsigned i;
    348 
    349    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    350 
    351    for(i = 0; i < type.length; ++i)
    352       elems[i] = LLVMConstInt(elem_type, val, type.sign ? 1 : 0);
    353 
    354    if (type.length == 1)
    355       return elems[0];
    356 
    357    return LLVMConstVector(elems, type.length);
    358 }
    359 
    360 
    361 LLVMValueRef
    362 lp_build_const_aos(struct gallivm_state *gallivm,
    363                    struct lp_type type,
    364                    double r, double g, double b, double a,
    365                    const unsigned char *swizzle)
    366 {
    367    const unsigned char default_swizzle[4] = {0, 1, 2, 3};
    368    LLVMTypeRef elem_type;
    369    LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    370    unsigned i;
    371 
    372    assert(type.length % 4 == 0);
    373    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    374 
    375    elem_type = lp_build_elem_type(gallivm, type);
    376 
    377    if(swizzle == NULL)
    378       swizzle = default_swizzle;
    379 
    380    elems[swizzle[0]] = lp_build_const_elem(gallivm, type, r);
    381    elems[swizzle[1]] = lp_build_const_elem(gallivm, type, g);
    382    elems[swizzle[2]] = lp_build_const_elem(gallivm, type, b);
    383    elems[swizzle[3]] = lp_build_const_elem(gallivm, type, a);
    384 
    385    for(i = 4; i < type.length; ++i)
    386       elems[i] = elems[i % 4];
    387 
    388    return LLVMConstVector(elems, type.length);
    389 }
    390 
    391 
    392 /**
    393  * @param mask TGSI_WRITEMASK_xxx
    394  */
    395 LLVMValueRef
    396 lp_build_const_mask_aos(struct gallivm_state *gallivm,
    397                         struct lp_type type,
    398                         unsigned mask)
    399 {
    400    LLVMTypeRef elem_type = LLVMIntTypeInContext(gallivm->context, type.width);
    401    LLVMValueRef masks[LP_MAX_VECTOR_LENGTH];
    402    unsigned i, j;
    403 
    404    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    405 
    406    for (j = 0; j < type.length; j += 4) {
    407       for( i = 0; i < 4; ++i) {
    408          masks[j + i] = LLVMConstInt(elem_type,
    409                                      mask & (1 << i) ? ~0ULL : 0,
    410                                      1);
    411       }
    412    }
    413 
    414    return LLVMConstVector(masks, type.length);
    415 }
    416 
    417 
    418 /**
    419  * Performs lp_build_const_mask_aos, but first swizzles the mask
    420  */
    421 LLVMValueRef
    422 lp_build_const_mask_aos_swizzled(struct gallivm_state *gallivm,
    423                         struct lp_type type,
    424                         unsigned mask,
    425                         const unsigned char *swizzle)
    426 {
    427    mask =
    428            ((mask & (1 << swizzle[0])) >> swizzle[0])
    429         | (((mask & (1 << swizzle[1])) >> swizzle[1]) << 1)
    430         | (((mask & (1 << swizzle[2])) >> swizzle[2]) << 2)
    431         | (((mask & (1 << swizzle[3])) >> swizzle[3]) << 3);
    432 
    433    return lp_build_const_mask_aos(gallivm, type, mask);
    434 }
    435 
    436 
    437 /**
    438  * Build a zero-terminated constant string.
    439  */
    440 LLVMValueRef
    441 lp_build_const_string(struct gallivm_state *gallivm,
    442                       const char *str)
    443 {
    444    unsigned len = strlen(str) + 1;
    445    LLVMTypeRef i8 = LLVMInt8TypeInContext(gallivm->context);
    446    LLVMValueRef string = LLVMAddGlobal(gallivm->module, LLVMArrayType(i8, len), "");
    447    LLVMSetGlobalConstant(string, TRUE);
    448    LLVMSetLinkage(string, LLVMInternalLinkage);
    449    LLVMSetInitializer(string, LLVMConstStringInContext(gallivm->context, str, len, TRUE));
    450    string = LLVMConstBitCast(string, LLVMPointerType(i8, 0));
    451    return string;
    452 }
    453 
    454 
    455 /**
    456  * Build a callable function pointer.
    457  *
    458  * We use function pointer constants instead of LLVMAddGlobalMapping()
    459  * to work around a bug in LLVM 2.6, and for efficiency/simplicity.
    460  */
    461 LLVMValueRef
    462 lp_build_const_func_pointer(struct gallivm_state *gallivm,
    463                             const void *ptr,
    464                             LLVMTypeRef ret_type,
    465                             LLVMTypeRef *arg_types,
    466                             unsigned num_args,
    467                             const char *name)
    468 {
    469    LLVMTypeRef function_type;
    470    LLVMValueRef function;
    471 
    472    function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0);
    473 
    474    function = lp_build_const_int_pointer(gallivm, ptr);
    475 
    476    function = LLVMBuildBitCast(gallivm->builder, function,
    477                                LLVMPointerType(function_type, 0),
    478                                name);
    479 
    480    return function;
    481 }
    482