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 #include "util/u_debug.h"
     30 
     31 #include "lp_bld_type.h"
     32 #include "lp_bld_const.h"
     33 #include "lp_bld_init.h"
     34 
     35 
     36 LLVMTypeRef
     37 lp_build_elem_type(struct gallivm_state *gallivm, struct lp_type type)
     38 {
     39    if (type.floating) {
     40       switch(type.width) {
     41       case 16:
     42          return LLVMIntTypeInContext(gallivm->context, 16);
     43          break;
     44       case 32:
     45          return LLVMFloatTypeInContext(gallivm->context);
     46          break;
     47       case 64:
     48          return LLVMDoubleTypeInContext(gallivm->context);
     49          break;
     50       default:
     51          assert(0);
     52          return LLVMFloatTypeInContext(gallivm->context);
     53       }
     54    }
     55    else {
     56       return LLVMIntTypeInContext(gallivm->context, type.width);
     57    }
     58 }
     59 
     60 
     61 LLVMTypeRef
     62 lp_build_vec_type(struct gallivm_state *gallivm,struct lp_type type)
     63 {
     64    LLVMTypeRef elem_type = lp_build_elem_type(gallivm, type);
     65    if (type.length == 1)
     66       return elem_type;
     67    else
     68       return LLVMVectorType(elem_type, type.length);
     69 }
     70 
     71 
     72 /**
     73  * This function is a mirror of lp_build_elem_type() above.
     74  *
     75  * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the
     76  * type and check for identity.
     77  */
     78 boolean
     79 lp_check_elem_type(struct lp_type type, LLVMTypeRef elem_type)
     80 {
     81    LLVMTypeKind elem_kind;
     82 
     83    assert(elem_type);
     84    if(!elem_type)
     85       return FALSE;
     86 
     87    elem_kind = LLVMGetTypeKind(elem_type);
     88 
     89    if (type.floating) {
     90       switch(type.width) {
     91       case 16:
     92          if(elem_kind != LLVMIntegerTypeKind)
     93             return FALSE;
     94          break;
     95       case 32:
     96          if(elem_kind != LLVMFloatTypeKind)
     97             return FALSE;
     98          break;
     99       case 64:
    100          if(elem_kind != LLVMDoubleTypeKind)
    101             return FALSE;
    102          break;
    103       default:
    104          assert(0);
    105          return FALSE;
    106       }
    107    }
    108    else {
    109       if(elem_kind != LLVMIntegerTypeKind)
    110          return FALSE;
    111 
    112       if(LLVMGetIntTypeWidth(elem_type) != type.width)
    113          return FALSE;
    114    }
    115 
    116    return TRUE;
    117 }
    118 
    119 
    120 boolean
    121 lp_check_vec_type(struct lp_type type, LLVMTypeRef vec_type)
    122 {
    123    LLVMTypeRef elem_type;
    124 
    125    assert(vec_type);
    126    if(!vec_type)
    127       return FALSE;
    128 
    129    if (type.length == 1)
    130       return lp_check_elem_type(type, vec_type);
    131 
    132    if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind)
    133       return FALSE;
    134 
    135    if(LLVMGetVectorSize(vec_type) != type.length)
    136       return FALSE;
    137 
    138    elem_type = LLVMGetElementType(vec_type);
    139 
    140    return lp_check_elem_type(type, elem_type);
    141 }
    142 
    143 
    144 boolean
    145 lp_check_value(struct lp_type type, LLVMValueRef val)
    146 {
    147    LLVMTypeRef vec_type;
    148 
    149    assert(val);
    150    if(!val)
    151       return FALSE;
    152 
    153    vec_type = LLVMTypeOf(val);
    154 
    155    return lp_check_vec_type(type, vec_type);
    156 }
    157 
    158 
    159 LLVMTypeRef
    160 lp_build_int_elem_type(struct gallivm_state *gallivm, struct lp_type type)
    161 {
    162    return LLVMIntTypeInContext(gallivm->context, type.width);
    163 }
    164 
    165 
    166 LLVMTypeRef
    167 lp_build_int_vec_type(struct gallivm_state *gallivm, struct lp_type type)
    168 {
    169    LLVMTypeRef elem_type = lp_build_int_elem_type(gallivm, type);
    170    if (type.length == 1)
    171       return elem_type;
    172    else
    173       return LLVMVectorType(elem_type, type.length);
    174 }
    175 
    176 
    177 /**
    178  * Create element of vector type
    179  */
    180 struct lp_type
    181 lp_elem_type(struct lp_type type)
    182 {
    183    struct lp_type res_type;
    184 
    185    assert(type.length > 1);
    186    res_type = type;
    187    res_type.length = 1;
    188 
    189    return res_type;
    190 }
    191 
    192 
    193 /**
    194  * Create unsigned integer type variation of given type.
    195  */
    196 struct lp_type
    197 lp_uint_type(struct lp_type type)
    198 {
    199    struct lp_type res_type;
    200 
    201    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    202    memset(&res_type, 0, sizeof res_type);
    203    res_type.width = type.width;
    204    res_type.length = type.length;
    205 
    206    return res_type;
    207 }
    208 
    209 
    210 /**
    211  * Create signed integer type variation of given type.
    212  */
    213 struct lp_type
    214 lp_int_type(struct lp_type type)
    215 {
    216    struct lp_type res_type;
    217 
    218    assert(type.length <= LP_MAX_VECTOR_LENGTH);
    219    memset(&res_type, 0, sizeof res_type);
    220    res_type.width = type.width;
    221    res_type.length = type.length;
    222    res_type.sign = 1;
    223 
    224    return res_type;
    225 }
    226 
    227 
    228 /**
    229  * Return the type with twice the bit width (hence half the number of elements).
    230  */
    231 struct lp_type
    232 lp_wider_type(struct lp_type type)
    233 {
    234    struct lp_type res_type;
    235 
    236    memcpy(&res_type, &type, sizeof res_type);
    237    res_type.width *= 2;
    238    res_type.length /= 2;
    239 
    240    assert(res_type.length);
    241 
    242    return res_type;
    243 }
    244 
    245 
    246 /**
    247  * Return the size of the LLVMType in bits.
    248  * XXX this function doesn't necessarily handle all LLVM types.
    249  */
    250 unsigned
    251 lp_sizeof_llvm_type(LLVMTypeRef t)
    252 {
    253    LLVMTypeKind k = LLVMGetTypeKind(t);
    254 
    255    switch (k) {
    256    case LLVMIntegerTypeKind:
    257       return LLVMGetIntTypeWidth(t);
    258    case LLVMFloatTypeKind:
    259       return 8 * sizeof(float);
    260    case LLVMDoubleTypeKind:
    261       return 8 * sizeof(double);
    262    case LLVMVectorTypeKind:
    263       {
    264          LLVMTypeRef elem = LLVMGetElementType(t);
    265          unsigned len = LLVMGetVectorSize(t);
    266          return len * lp_sizeof_llvm_type(elem);
    267       }
    268       break;
    269    case LLVMArrayTypeKind:
    270       {
    271          LLVMTypeRef elem = LLVMGetElementType(t);
    272          unsigned len = LLVMGetArrayLength(t);
    273          return len * lp_sizeof_llvm_type(elem);
    274       }
    275       break;
    276    default:
    277       assert(0 && "Unexpected type in lp_get_llvm_type_size()");
    278       return 0;
    279    }
    280 }
    281 
    282 
    283 /**
    284  * Return string name for a LLVMTypeKind.  Useful for debugging.
    285  */
    286 const char *
    287 lp_typekind_name(LLVMTypeKind t)
    288 {
    289    switch (t) {
    290    case LLVMVoidTypeKind:
    291       return "LLVMVoidTypeKind";
    292    case LLVMFloatTypeKind:
    293       return "LLVMFloatTypeKind";
    294    case LLVMDoubleTypeKind:
    295       return "LLVMDoubleTypeKind";
    296    case LLVMX86_FP80TypeKind:
    297       return "LLVMX86_FP80TypeKind";
    298    case LLVMFP128TypeKind:
    299       return "LLVMFP128TypeKind";
    300    case LLVMPPC_FP128TypeKind:
    301       return "LLVMPPC_FP128TypeKind";
    302    case LLVMLabelTypeKind:
    303       return "LLVMLabelTypeKind";
    304    case LLVMIntegerTypeKind:
    305       return "LLVMIntegerTypeKind";
    306    case LLVMFunctionTypeKind:
    307       return "LLVMFunctionTypeKind";
    308    case LLVMStructTypeKind:
    309       return "LLVMStructTypeKind";
    310    case LLVMArrayTypeKind:
    311       return "LLVMArrayTypeKind";
    312    case LLVMPointerTypeKind:
    313       return "LLVMPointerTypeKind";
    314 #if HAVE_LLVM < 0x0300
    315    case LLVMOpaqueTypeKind:
    316       return "LLVMOpaqueTypeKind";
    317 #endif
    318    case LLVMVectorTypeKind:
    319       return "LLVMVectorTypeKind";
    320    case LLVMMetadataTypeKind:
    321       return "LLVMMetadataTypeKind";
    322 #if HAVE_LLVM == 0x0207
    323    case LLVMUnionTypeKind:
    324       return "LLVMUnionTypeKind";
    325 #endif
    326    default:
    327       return "unknown LLVMTypeKind";
    328    }
    329 }
    330 
    331 
    332 /**
    333  * Print an LLVMTypeRef.  Like LLVMDumpValue().  For debugging.
    334  */
    335 void
    336 lp_dump_llvmtype(LLVMTypeRef t)
    337 {
    338    LLVMTypeKind k = LLVMGetTypeKind(t);
    339 
    340    if (k == LLVMVectorTypeKind) {
    341       LLVMTypeRef te = LLVMGetElementType(t);
    342       LLVMTypeKind ke = LLVMGetTypeKind(te);
    343       unsigned len = LLVMGetVectorSize(t);
    344       if (ke == LLVMIntegerTypeKind) {
    345          unsigned b = LLVMGetIntTypeWidth(te);
    346          debug_printf("Vector [%u] of %u-bit Integer\n", len, b);
    347       }
    348       else {
    349          debug_printf("Vector [%u] of %s\n", len, lp_typekind_name(ke));
    350       }
    351    }
    352    else if (k == LLVMArrayTypeKind) {
    353       LLVMTypeRef te = LLVMGetElementType(t);
    354       LLVMTypeKind ke = LLVMGetTypeKind(te);
    355       unsigned len = LLVMGetArrayLength(t);
    356       debug_printf("Array [%u] of %s\n", len, lp_typekind_name(ke));
    357    }
    358    else if (k == LLVMIntegerTypeKind) {
    359       unsigned b = LLVMGetIntTypeWidth(t);
    360       debug_printf("%u-bit Integer\n", b);
    361    }
    362    else if (k == LLVMPointerTypeKind) {
    363       LLVMTypeRef te = LLVMGetElementType(t);
    364       debug_printf("Pointer to ");
    365       lp_dump_llvmtype(te);
    366    }
    367    else {
    368       debug_printf("%s\n", lp_typekind_name(k));
    369    }
    370 }
    371 
    372 
    373 void
    374 lp_build_context_init(struct lp_build_context *bld,
    375                       struct gallivm_state *gallivm,
    376                       struct lp_type type)
    377 {
    378    bld->gallivm = gallivm;
    379    bld->type = type;
    380 
    381    bld->int_elem_type = lp_build_int_elem_type(gallivm, type);
    382    if (type.floating)
    383       bld->elem_type = lp_build_elem_type(gallivm, type);
    384    else
    385       bld->elem_type = bld->int_elem_type;
    386 
    387    if (type.length == 1) {
    388       bld->int_vec_type = bld->int_elem_type;
    389       bld->vec_type = bld->elem_type;
    390    }
    391    else {
    392       bld->int_vec_type = LLVMVectorType(bld->int_elem_type, type.length);
    393       bld->vec_type = LLVMVectorType(bld->elem_type, type.length);
    394    }
    395 
    396    bld->undef = LLVMGetUndef(bld->vec_type);
    397    bld->zero = LLVMConstNull(bld->vec_type);
    398    bld->one = lp_build_one(gallivm, type);
    399 }
    400 
    401 
    402 /**
    403  * Count the number of instructions in a function.
    404  */
    405 unsigned
    406 lp_build_count_instructions(LLVMValueRef function)
    407 {
    408    unsigned num_instrs = 0;
    409    LLVMBasicBlockRef block;
    410 
    411    block = LLVMGetFirstBasicBlock(function);
    412    while (block) {
    413       LLVMValueRef instr;
    414       instr = LLVMGetFirstInstruction(block);
    415       while (instr) {
    416          ++num_instrs;
    417 
    418          instr = LLVMGetNextInstruction(instr);
    419       }
    420       block = LLVMGetNextBasicBlock(block);
    421    }
    422 
    423    return num_instrs;
    424 }
    425