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 */ 42LLVMValueRef 43lp_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 */ 73LLVMValueRef 74lp_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 */ 115LLVMValueRef 116lp_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 151LLVMValueRef 152lp_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