Home | History | Annotate | Download | only in gallivm
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * The above copyright notice and this permission notice (including the
     23  * next paragraph) shall be included in all copies or substantial portions
     24  * of the Software.
     25  *
     26  **************************************************************************/
     27 
     28 
     29 #include "util/u_debug.h"
     30 #include "lp_bld_debug.h"
     31 #include "lp_bld_const.h"
     32 #include "lp_bld_format.h"
     33 #include "lp_bld_gather.h"
     34 #include "lp_bld_init.h"
     35 
     36 
     37 /**
     38  * Get the pointer to one element from scatter positions in memory.
     39  *
     40  * @sa lp_build_gather()
     41  */
     42 LLVMValueRef
     43 lp_build_gather_elem_ptr(struct gallivm_state *gallivm,
     44                          unsigned length,
     45                          LLVMValueRef base_ptr,
     46                          LLVMValueRef offsets,
     47                          unsigned i)
     48 {
     49    LLVMValueRef offset;
     50    LLVMValueRef ptr;
     51 
     52    assert(LLVMTypeOf(base_ptr) == LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0));
     53 
     54    if (length == 1) {
     55       assert(i == 0);
     56       offset = offsets;
     57    } else {
     58       LLVMValueRef index = lp_build_const_int32(gallivm, i);
     59       offset = LLVMBuildExtractElement(gallivm->builder, offsets, index, "");
     60    }
     61 
     62    ptr = LLVMBuildGEP(gallivm->builder, base_ptr, &offset, 1, "");
     63 
     64    return ptr;
     65 }
     66 
     67 
     68 /**
     69  * Gather one element from scatter positions in memory.
     70  *
     71  * @sa lp_build_gather()
     72  */
     73 LLVMValueRef
     74 lp_build_gather_elem(struct gallivm_state *gallivm,
     75                      unsigned length,
     76                      unsigned src_width,
     77                      unsigned dst_width,
     78                      LLVMValueRef base_ptr,
     79                      LLVMValueRef offsets,
     80                      unsigned i)
     81 {
     82    LLVMTypeRef src_type = LLVMIntTypeInContext(gallivm->context, src_width);
     83    LLVMTypeRef src_ptr_type = LLVMPointerType(src_type, 0);
     84    LLVMTypeRef dst_elem_type = LLVMIntTypeInContext(gallivm->context, dst_width);
     85    LLVMValueRef ptr;
     86    LLVMValueRef res;
     87 
     88    assert(LLVMTypeOf(base_ptr) == LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0));
     89 
     90    ptr = lp_build_gather_elem_ptr(gallivm, length, base_ptr, offsets, i);
     91    ptr = LLVMBuildBitCast(gallivm->builder, ptr, src_ptr_type, "");
     92    res = LLVMBuildLoad(gallivm->builder, ptr, "");
     93 
     94    assert(src_width <= dst_width);
     95    if (src_width > dst_width)
     96       res = LLVMBuildTrunc(gallivm->builder, res, dst_elem_type, "");
     97    if (src_width < dst_width)
     98       res = LLVMBuildZExt(gallivm->builder, res, dst_elem_type, "");
     99 
    100    return res;
    101 }
    102 
    103 
    104 /**
    105  * Gather elements from scatter positions in memory into a single vector.
    106  * Use for fetching texels from a texture.
    107  * For SSE, typical values are length=4, src_width=32, dst_width=32.
    108  *
    109  * @param length length of the offsets
    110  * @param src_width src element width in bits
    111  * @param dst_width result element width in bits (src will be expanded to fit)
    112  * @param base_ptr base pointer, should be a i8 pointer type.
    113  * @param offsets vector with offsets
    114  */
    115 LLVMValueRef
    116 lp_build_gather(struct gallivm_state *gallivm,
    117                 unsigned length,
    118                 unsigned src_width,
    119                 unsigned dst_width,
    120                 LLVMValueRef base_ptr,
    121                 LLVMValueRef offsets)
    122 {
    123    LLVMValueRef res;
    124 
    125    if (length == 1) {
    126       /* Scalar */
    127       return lp_build_gather_elem(gallivm, length,
    128                                   src_width, dst_width,
    129                                   base_ptr, offsets, 0);
    130    } else {
    131       /* Vector */
    132 
    133       LLVMTypeRef dst_elem_type = LLVMIntTypeInContext(gallivm->context, dst_width);
    134       LLVMTypeRef dst_vec_type = LLVMVectorType(dst_elem_type, length);
    135       unsigned i;
    136 
    137       res = LLVMGetUndef(dst_vec_type);
    138       for (i = 0; i < length; ++i) {
    139          LLVMValueRef index = lp_build_const_int32(gallivm, i);
    140          LLVMValueRef elem;
    141          elem = lp_build_gather_elem(gallivm, length,
    142                                      src_width, dst_width,
    143                                      base_ptr, offsets, i);
    144          res = LLVMBuildInsertElement(gallivm->builder, res, elem, index, "");
    145       }
    146    }
    147 
    148    return res;
    149 }
    150 
    151 LLVMValueRef
    152 lp_build_gather_values(struct gallivm_state * gallivm,
    153                        LLVMValueRef * values,
    154                        unsigned value_count)
    155 {
    156    LLVMTypeRef vec_type = LLVMVectorType(LLVMTypeOf(values[0]), value_count);
    157    LLVMBuilderRef builder = gallivm->builder;
    158    LLVMValueRef vec = LLVMGetUndef(vec_type);
    159    unsigned i;
    160 
    161    for (i = 0; i < value_count; i++) {
    162       LLVMValueRef index = lp_build_const_int32(gallivm, i);
    163       vec = LLVMBuildInsertElement(builder, vec, values[i], index, "");
    164    }
    165    return vec;
    166 }
    167