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 = lp_build_vec_type(gallivm, type);
    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, (long long) 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    LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    369    unsigned i;
    370 
    371    assert(type.length % 4 == 0);
    372    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    373 
    374    lp_build_elem_type(gallivm, type);
    375 
    376    if (!swizzle)
    377       swizzle = default_swizzle;
    378 
    379    elems[swizzle[0]] = lp_build_const_elem(gallivm, type, r);
    380    elems[swizzle[1]] = lp_build_const_elem(gallivm, type, g);
    381    elems[swizzle[2]] = lp_build_const_elem(gallivm, type, b);
    382    elems[swizzle[3]] = lp_build_const_elem(gallivm, type, a);
    383 
    384    for(i = 4; i < type.length; ++i)
    385       elems[i] = elems[i % 4];
    386 
    387    return LLVMConstVector(elems, type.length);
    388 }
    389 
    390 
    391 /**
    392  * @param mask TGSI_WRITEMASK_xxx
    393  */
    394 LLVMValueRef
    395 lp_build_const_mask_aos(struct gallivm_state *gallivm,
    396                         struct lp_type type,
    397                         unsigned mask,
    398                         unsigned channels)
    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 += channels) {
    407       for( i = 0; i < channels; ++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                                  unsigned channels,
    426                                  const unsigned char *swizzle)
    427 {
    428    unsigned i, mask_swizzled;
    429    mask_swizzled = 0;
    430 
    431    for (i = 0; i < channels; ++i) {
    432       if (swizzle[i] < 4) {
    433          mask_swizzled |= ((mask & (1 << swizzle[i])) >> swizzle[i]) << i;
    434       }
    435    }
    436 
    437    return lp_build_const_mask_aos(gallivm, type, mask_swizzled, channels);
    438 }
    439 
    440 
    441 /**
    442  * Build a zero-terminated constant string.
    443  */
    444 LLVMValueRef
    445 lp_build_const_string(struct gallivm_state *gallivm,
    446                       const char *str)
    447 {
    448    unsigned len = strlen(str) + 1;
    449    LLVMTypeRef i8 = LLVMInt8TypeInContext(gallivm->context);
    450    LLVMValueRef string = LLVMAddGlobal(gallivm->module, LLVMArrayType(i8, len), "");
    451    LLVMSetGlobalConstant(string, TRUE);
    452    LLVMSetLinkage(string, LLVMInternalLinkage);
    453    LLVMSetInitializer(string, LLVMConstStringInContext(gallivm->context, str, len, TRUE));
    454    string = LLVMConstBitCast(string, LLVMPointerType(i8, 0));
    455    return string;
    456 }
    457 
    458 
    459 /**
    460  * Build a callable function pointer.
    461  *
    462  * We use function pointer constants instead of LLVMAddGlobalMapping()
    463  * to work around a bug in LLVM 2.6, and for efficiency/simplicity.
    464  */
    465 LLVMValueRef
    466 lp_build_const_func_pointer(struct gallivm_state *gallivm,
    467                             const void *ptr,
    468                             LLVMTypeRef ret_type,
    469                             LLVMTypeRef *arg_types,
    470                             unsigned num_args,
    471                             const char *name)
    472 {
    473    LLVMTypeRef function_type;
    474    LLVMValueRef function;
    475 
    476    function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0);
    477 
    478    function = lp_build_const_int_pointer(gallivm, ptr);
    479 
    480    function = LLVMBuildBitCast(gallivm->builder, function,
    481                                LLVMPointerType(function_type, 0),
    482                                name);
    483 
    484    return function;
    485 }
    486