1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2009 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci/** 30bf215546Sopenharmony_ci * @file 31bf215546Sopenharmony_ci * Helpers for emiting intrinsic calls. 32bf215546Sopenharmony_ci * 33bf215546Sopenharmony_ci * LLVM vanilla IR doesn't represent all basic arithmetic operations we care 34bf215546Sopenharmony_ci * about, and it is often necessary to resort target-specific intrinsics for 35bf215546Sopenharmony_ci * performance, convenience. 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * Ideally we would like to stay away from target specific intrinsics and 38bf215546Sopenharmony_ci * move all the instruction selection logic into upstream LLVM where it belongs. 39bf215546Sopenharmony_ci * 40bf215546Sopenharmony_ci * These functions are also used for calling C functions provided by us from 41bf215546Sopenharmony_ci * generated LLVM code. 42bf215546Sopenharmony_ci * 43bf215546Sopenharmony_ci * @author Jose Fonseca <jfonseca@vmware.com> 44bf215546Sopenharmony_ci */ 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci#include <llvm/Config/llvm-config.h> 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci#include "util/u_debug.h" 49bf215546Sopenharmony_ci#include "util/u_string.h" 50bf215546Sopenharmony_ci#include "util/bitscan.h" 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci#include "lp_bld_const.h" 53bf215546Sopenharmony_ci#include "lp_bld_intr.h" 54bf215546Sopenharmony_ci#include "lp_bld_type.h" 55bf215546Sopenharmony_ci#include "lp_bld_pack.h" 56bf215546Sopenharmony_ci#include "lp_bld_debug.h" 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_civoid 60bf215546Sopenharmony_cilp_format_intrinsic(char *name, 61bf215546Sopenharmony_ci size_t size, 62bf215546Sopenharmony_ci const char *name_root, 63bf215546Sopenharmony_ci LLVMTypeRef type) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci unsigned length = 0; 66bf215546Sopenharmony_ci unsigned width; 67bf215546Sopenharmony_ci char c; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci LLVMTypeKind kind = LLVMGetTypeKind(type); 70bf215546Sopenharmony_ci if (kind == LLVMVectorTypeKind) { 71bf215546Sopenharmony_ci length = LLVMGetVectorSize(type); 72bf215546Sopenharmony_ci type = LLVMGetElementType(type); 73bf215546Sopenharmony_ci kind = LLVMGetTypeKind(type); 74bf215546Sopenharmony_ci } 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci switch (kind) { 77bf215546Sopenharmony_ci case LLVMIntegerTypeKind: 78bf215546Sopenharmony_ci c = 'i'; 79bf215546Sopenharmony_ci width = LLVMGetIntTypeWidth(type); 80bf215546Sopenharmony_ci break; 81bf215546Sopenharmony_ci case LLVMFloatTypeKind: 82bf215546Sopenharmony_ci c = 'f'; 83bf215546Sopenharmony_ci width = 32; 84bf215546Sopenharmony_ci break; 85bf215546Sopenharmony_ci case LLVMDoubleTypeKind: 86bf215546Sopenharmony_ci c = 'f'; 87bf215546Sopenharmony_ci width = 64; 88bf215546Sopenharmony_ci break; 89bf215546Sopenharmony_ci case LLVMHalfTypeKind: 90bf215546Sopenharmony_ci c = 'f'; 91bf215546Sopenharmony_ci width = 16; 92bf215546Sopenharmony_ci break; 93bf215546Sopenharmony_ci default: 94bf215546Sopenharmony_ci unreachable("unexpected LLVMTypeKind"); 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci if (length) { 98bf215546Sopenharmony_ci snprintf(name, size, "%s.v%u%c%u", name_root, length, c, width); 99bf215546Sopenharmony_ci } else { 100bf215546Sopenharmony_ci snprintf(name, size, "%s.%c%u", name_root, c, width); 101bf215546Sopenharmony_ci } 102bf215546Sopenharmony_ci} 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ciLLVMValueRef 106bf215546Sopenharmony_cilp_declare_intrinsic_with_type(LLVMModuleRef module, 107bf215546Sopenharmony_ci const char *name, 108bf215546Sopenharmony_ci LLVMTypeRef function_type) 109bf215546Sopenharmony_ci{ 110bf215546Sopenharmony_ci assert(!LLVMGetNamedFunction(module, name)); 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci LLVMValueRef function = LLVMAddFunction(module, name, function_type); 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci LLVMSetFunctionCallConv(function, LLVMCCallConv); 115bf215546Sopenharmony_ci LLVMSetLinkage(function, LLVMExternalLinkage); 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci assert(LLVMIsDeclaration(function)); 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci return function; 120bf215546Sopenharmony_ci} 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ciLLVMValueRef 124bf215546Sopenharmony_cilp_declare_intrinsic(LLVMModuleRef module, 125bf215546Sopenharmony_ci const char *name, 126bf215546Sopenharmony_ci LLVMTypeRef ret_type, 127bf215546Sopenharmony_ci LLVMTypeRef *arg_types, 128bf215546Sopenharmony_ci unsigned num_args) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci LLVMTypeRef function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0); 131bf215546Sopenharmony_ci return lp_declare_intrinsic_with_type(module, name, function_type); 132bf215546Sopenharmony_ci} 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR < 4 136bf215546Sopenharmony_cistatic LLVMAttribute lp_attr_to_llvm_attr(enum lp_func_attr attr) 137bf215546Sopenharmony_ci{ 138bf215546Sopenharmony_ci switch (attr) { 139bf215546Sopenharmony_ci case LP_FUNC_ATTR_ALWAYSINLINE: return LLVMAlwaysInlineAttribute; 140bf215546Sopenharmony_ci case LP_FUNC_ATTR_INREG: return LLVMInRegAttribute; 141bf215546Sopenharmony_ci case LP_FUNC_ATTR_NOALIAS: return LLVMNoAliasAttribute; 142bf215546Sopenharmony_ci case LP_FUNC_ATTR_NOUNWIND: return LLVMNoUnwindAttribute; 143bf215546Sopenharmony_ci case LP_FUNC_ATTR_READNONE: return LLVMReadNoneAttribute; 144bf215546Sopenharmony_ci case LP_FUNC_ATTR_READONLY: return LLVMReadOnlyAttribute; 145bf215546Sopenharmony_ci default: 146bf215546Sopenharmony_ci _debug_printf("Unhandled function attribute: %x\n", attr); 147bf215546Sopenharmony_ci return 0; 148bf215546Sopenharmony_ci } 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci#else 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_cistatic const char *attr_to_str(enum lp_func_attr attr) 154bf215546Sopenharmony_ci{ 155bf215546Sopenharmony_ci switch (attr) { 156bf215546Sopenharmony_ci case LP_FUNC_ATTR_ALWAYSINLINE: return "alwaysinline"; 157bf215546Sopenharmony_ci case LP_FUNC_ATTR_INREG: return "inreg"; 158bf215546Sopenharmony_ci case LP_FUNC_ATTR_NOALIAS: return "noalias"; 159bf215546Sopenharmony_ci case LP_FUNC_ATTR_NOUNWIND: return "nounwind"; 160bf215546Sopenharmony_ci case LP_FUNC_ATTR_READNONE: return "readnone"; 161bf215546Sopenharmony_ci case LP_FUNC_ATTR_READONLY: return "readonly"; 162bf215546Sopenharmony_ci case LP_FUNC_ATTR_WRITEONLY: return "writeonly"; 163bf215546Sopenharmony_ci case LP_FUNC_ATTR_INACCESSIBLE_MEM_ONLY: return "inaccessiblememonly"; 164bf215546Sopenharmony_ci case LP_FUNC_ATTR_CONVERGENT: return "convergent"; 165bf215546Sopenharmony_ci case LP_FUNC_ATTR_PRESPLITCORO: return "presplitcoroutine"; 166bf215546Sopenharmony_ci default: 167bf215546Sopenharmony_ci _debug_printf("Unhandled function attribute: %x\n", attr); 168bf215546Sopenharmony_ci return 0; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci} 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci#endif 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_civoid 175bf215546Sopenharmony_cilp_add_function_attr(LLVMValueRef function_or_call, 176bf215546Sopenharmony_ci int attr_idx, enum lp_func_attr attr) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR < 4 180bf215546Sopenharmony_ci LLVMAttribute llvm_attr = lp_attr_to_llvm_attr(attr); 181bf215546Sopenharmony_ci if (LLVMIsAFunction(function_or_call)) { 182bf215546Sopenharmony_ci if (attr_idx == -1) { 183bf215546Sopenharmony_ci LLVMAddFunctionAttr(function_or_call, llvm_attr); 184bf215546Sopenharmony_ci } else { 185bf215546Sopenharmony_ci LLVMAddAttribute(LLVMGetParam(function_or_call, attr_idx - 1), llvm_attr); 186bf215546Sopenharmony_ci } 187bf215546Sopenharmony_ci } else { 188bf215546Sopenharmony_ci LLVMAddInstrAttribute(function_or_call, attr_idx, llvm_attr); 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci#else 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci LLVMModuleRef module; 193bf215546Sopenharmony_ci if (LLVMIsAFunction(function_or_call)) { 194bf215546Sopenharmony_ci module = LLVMGetGlobalParent(function_or_call); 195bf215546Sopenharmony_ci } else { 196bf215546Sopenharmony_ci LLVMBasicBlockRef bb = LLVMGetInstructionParent(function_or_call); 197bf215546Sopenharmony_ci LLVMValueRef function = LLVMGetBasicBlockParent(bb); 198bf215546Sopenharmony_ci module = LLVMGetGlobalParent(function); 199bf215546Sopenharmony_ci } 200bf215546Sopenharmony_ci LLVMContextRef ctx = LLVMGetModuleContext(module); 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci const char *attr_name = attr_to_str(attr); 203bf215546Sopenharmony_ci unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, 204bf215546Sopenharmony_ci strlen(attr_name)); 205bf215546Sopenharmony_ci LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(ctx, kind_id, 0); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci if (LLVMIsAFunction(function_or_call)) 208bf215546Sopenharmony_ci LLVMAddAttributeAtIndex(function_or_call, attr_idx, llvm_attr); 209bf215546Sopenharmony_ci else 210bf215546Sopenharmony_ci LLVMAddCallSiteAttribute(function_or_call, attr_idx, llvm_attr); 211bf215546Sopenharmony_ci#endif 212bf215546Sopenharmony_ci} 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_cistatic void 215bf215546Sopenharmony_cilp_add_func_attributes(LLVMValueRef function, unsigned attrib_mask) 216bf215546Sopenharmony_ci{ 217bf215546Sopenharmony_ci /* NoUnwind indicates that the intrinsic never raises a C++ exception. 218bf215546Sopenharmony_ci * Set it for all intrinsics. 219bf215546Sopenharmony_ci */ 220bf215546Sopenharmony_ci attrib_mask |= LP_FUNC_ATTR_NOUNWIND; 221bf215546Sopenharmony_ci attrib_mask &= ~LP_FUNC_ATTR_LEGACY; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci while (attrib_mask) { 224bf215546Sopenharmony_ci enum lp_func_attr attr = 1u << u_bit_scan(&attrib_mask); 225bf215546Sopenharmony_ci lp_add_function_attr(function, -1, attr); 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci} 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ciLLVMValueRef 230bf215546Sopenharmony_cilp_build_intrinsic(LLVMBuilderRef builder, 231bf215546Sopenharmony_ci const char *name, 232bf215546Sopenharmony_ci LLVMTypeRef ret_type, 233bf215546Sopenharmony_ci LLVMValueRef *args, 234bf215546Sopenharmony_ci unsigned num_args, 235bf215546Sopenharmony_ci unsigned attr_mask) 236bf215546Sopenharmony_ci{ 237bf215546Sopenharmony_ci LLVMModuleRef module = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder))); 238bf215546Sopenharmony_ci LLVMValueRef function, call; 239bf215546Sopenharmony_ci bool set_callsite_attrs = LLVM_VERSION_MAJOR >= 4 && 240bf215546Sopenharmony_ci !(attr_mask & LP_FUNC_ATTR_LEGACY); 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci LLVMTypeRef arg_types[LP_MAX_FUNC_ARGS]; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci assert(num_args <= LP_MAX_FUNC_ARGS); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci for(unsigned i = 0; i < num_args; ++i) { 247bf215546Sopenharmony_ci assert(args[i]); 248bf215546Sopenharmony_ci arg_types[i] = LLVMTypeOf(args[i]); 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci LLVMTypeRef function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0); 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci function = LLVMGetNamedFunction(module, name); 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci if(!function) { 256bf215546Sopenharmony_ci function = lp_declare_intrinsic_with_type(module, name, function_type); 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci /* 259bf215546Sopenharmony_ci * If llvm removes an intrinsic we use, we'll hit this abort (rather 260bf215546Sopenharmony_ci * than a call to address zero in the jited code). 261bf215546Sopenharmony_ci */ 262bf215546Sopenharmony_ci if (LLVMGetIntrinsicID(function) == 0) { 263bf215546Sopenharmony_ci _debug_printf("llvm (version " MESA_LLVM_VERSION_STRING 264bf215546Sopenharmony_ci ") found no intrinsic for %s, going to crash...\n", 265bf215546Sopenharmony_ci name); 266bf215546Sopenharmony_ci abort(); 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci if (!set_callsite_attrs) 270bf215546Sopenharmony_ci lp_add_func_attributes(function, attr_mask); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (gallivm_debug & GALLIVM_DEBUG_IR) { 273bf215546Sopenharmony_ci lp_debug_dump_value(function); 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci call = LLVMBuildCall2(builder, function_type, function, args, num_args, ""); 278bf215546Sopenharmony_ci if (set_callsite_attrs) 279bf215546Sopenharmony_ci lp_add_func_attributes(call, attr_mask); 280bf215546Sopenharmony_ci return call; 281bf215546Sopenharmony_ci} 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ciLLVMValueRef 285bf215546Sopenharmony_cilp_build_intrinsic_unary(LLVMBuilderRef builder, 286bf215546Sopenharmony_ci const char *name, 287bf215546Sopenharmony_ci LLVMTypeRef ret_type, 288bf215546Sopenharmony_ci LLVMValueRef a) 289bf215546Sopenharmony_ci{ 290bf215546Sopenharmony_ci return lp_build_intrinsic(builder, name, ret_type, &a, 1, 0); 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ciLLVMValueRef 295bf215546Sopenharmony_cilp_build_intrinsic_binary(LLVMBuilderRef builder, 296bf215546Sopenharmony_ci const char *name, 297bf215546Sopenharmony_ci LLVMTypeRef ret_type, 298bf215546Sopenharmony_ci LLVMValueRef a, 299bf215546Sopenharmony_ci LLVMValueRef b) 300bf215546Sopenharmony_ci{ 301bf215546Sopenharmony_ci LLVMValueRef args[2]; 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci args[0] = a; 304bf215546Sopenharmony_ci args[1] = b; 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci return lp_build_intrinsic(builder, name, ret_type, args, 2, 0); 307bf215546Sopenharmony_ci} 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci/** 311bf215546Sopenharmony_ci * Call intrinsic with arguments adapted to intrinsic vector length. 312bf215546Sopenharmony_ci * 313bf215546Sopenharmony_ci * Split vectors which are too large for the hw, or expand them if they 314bf215546Sopenharmony_ci * are too small, so a caller calling a function which might use intrinsics 315bf215546Sopenharmony_ci * doesn't need to do splitting/expansion on its own. 316bf215546Sopenharmony_ci * This only supports intrinsics where src and dst types match. 317bf215546Sopenharmony_ci */ 318bf215546Sopenharmony_ciLLVMValueRef 319bf215546Sopenharmony_cilp_build_intrinsic_binary_anylength(struct gallivm_state *gallivm, 320bf215546Sopenharmony_ci const char *name, 321bf215546Sopenharmony_ci struct lp_type src_type, 322bf215546Sopenharmony_ci unsigned intr_size, 323bf215546Sopenharmony_ci LLVMValueRef a, 324bf215546Sopenharmony_ci LLVMValueRef b) 325bf215546Sopenharmony_ci{ 326bf215546Sopenharmony_ci unsigned i; 327bf215546Sopenharmony_ci struct lp_type intrin_type = src_type; 328bf215546Sopenharmony_ci LLVMBuilderRef builder = gallivm->builder; 329bf215546Sopenharmony_ci LLVMValueRef i32undef = LLVMGetUndef(LLVMInt32TypeInContext(gallivm->context)); 330bf215546Sopenharmony_ci LLVMValueRef anative, bnative; 331bf215546Sopenharmony_ci unsigned intrin_length = intr_size / src_type.width; 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci intrin_type.length = intrin_length; 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci if (intrin_length > src_type.length) { 336bf215546Sopenharmony_ci LLVMValueRef elems[LP_MAX_VECTOR_LENGTH]; 337bf215546Sopenharmony_ci LLVMValueRef constvec, tmp; 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci for (i = 0; i < src_type.length; i++) { 340bf215546Sopenharmony_ci elems[i] = lp_build_const_int32(gallivm, i); 341bf215546Sopenharmony_ci } 342bf215546Sopenharmony_ci for (; i < intrin_length; i++) { 343bf215546Sopenharmony_ci elems[i] = i32undef; 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci if (src_type.length == 1) { 346bf215546Sopenharmony_ci LLVMTypeRef elem_type = lp_build_elem_type(gallivm, intrin_type); 347bf215546Sopenharmony_ci a = LLVMBuildBitCast(builder, a, LLVMVectorType(elem_type, 1), ""); 348bf215546Sopenharmony_ci b = LLVMBuildBitCast(builder, b, LLVMVectorType(elem_type, 1), ""); 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci constvec = LLVMConstVector(elems, intrin_length); 351bf215546Sopenharmony_ci anative = LLVMBuildShuffleVector(builder, a, a, constvec, ""); 352bf215546Sopenharmony_ci bnative = LLVMBuildShuffleVector(builder, b, b, constvec, ""); 353bf215546Sopenharmony_ci tmp = lp_build_intrinsic_binary(builder, name, 354bf215546Sopenharmony_ci lp_build_vec_type(gallivm, intrin_type), 355bf215546Sopenharmony_ci anative, bnative); 356bf215546Sopenharmony_ci if (src_type.length > 1) { 357bf215546Sopenharmony_ci constvec = LLVMConstVector(elems, src_type.length); 358bf215546Sopenharmony_ci return LLVMBuildShuffleVector(builder, tmp, tmp, constvec, ""); 359bf215546Sopenharmony_ci } 360bf215546Sopenharmony_ci else { 361bf215546Sopenharmony_ci return LLVMBuildExtractElement(builder, tmp, elems[0], ""); 362bf215546Sopenharmony_ci } 363bf215546Sopenharmony_ci } 364bf215546Sopenharmony_ci else if (intrin_length < src_type.length) { 365bf215546Sopenharmony_ci unsigned num_vec = src_type.length / intrin_length; 366bf215546Sopenharmony_ci LLVMValueRef tmp[LP_MAX_VECTOR_LENGTH]; 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci /* don't support arbitrary size here as this is so yuck */ 369bf215546Sopenharmony_ci if (src_type.length % intrin_length) { 370bf215546Sopenharmony_ci /* FIXME: This is something which should be supported 371bf215546Sopenharmony_ci * but there doesn't seem to be any need for it currently 372bf215546Sopenharmony_ci * so crash and burn. 373bf215546Sopenharmony_ci */ 374bf215546Sopenharmony_ci debug_printf("%s: should handle arbitrary vector size\n", 375bf215546Sopenharmony_ci __FUNCTION__); 376bf215546Sopenharmony_ci assert(0); 377bf215546Sopenharmony_ci return NULL; 378bf215546Sopenharmony_ci } 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci for (i = 0; i < num_vec; i++) { 381bf215546Sopenharmony_ci anative = lp_build_extract_range(gallivm, a, i*intrin_length, 382bf215546Sopenharmony_ci intrin_length); 383bf215546Sopenharmony_ci bnative = lp_build_extract_range(gallivm, b, i*intrin_length, 384bf215546Sopenharmony_ci intrin_length); 385bf215546Sopenharmony_ci tmp[i] = lp_build_intrinsic_binary(builder, name, 386bf215546Sopenharmony_ci lp_build_vec_type(gallivm, intrin_type), 387bf215546Sopenharmony_ci anative, bnative); 388bf215546Sopenharmony_ci } 389bf215546Sopenharmony_ci return lp_build_concat(gallivm, tmp, intrin_type, num_vec); 390bf215546Sopenharmony_ci } 391bf215546Sopenharmony_ci else { 392bf215546Sopenharmony_ci return lp_build_intrinsic_binary(builder, name, 393bf215546Sopenharmony_ci lp_build_vec_type(gallivm, src_type), 394bf215546Sopenharmony_ci a, b); 395bf215546Sopenharmony_ci } 396bf215546Sopenharmony_ci} 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ciLLVMValueRef 400bf215546Sopenharmony_cilp_build_intrinsic_map(struct gallivm_state *gallivm, 401bf215546Sopenharmony_ci const char *name, 402bf215546Sopenharmony_ci LLVMTypeRef ret_type, 403bf215546Sopenharmony_ci LLVMValueRef *args, 404bf215546Sopenharmony_ci unsigned num_args) 405bf215546Sopenharmony_ci{ 406bf215546Sopenharmony_ci LLVMBuilderRef builder = gallivm->builder; 407bf215546Sopenharmony_ci LLVMTypeRef ret_elem_type = LLVMGetElementType(ret_type); 408bf215546Sopenharmony_ci unsigned n = LLVMGetVectorSize(ret_type); 409bf215546Sopenharmony_ci unsigned i, j; 410bf215546Sopenharmony_ci LLVMValueRef res; 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci assert(num_args <= LP_MAX_FUNC_ARGS); 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci res = LLVMGetUndef(ret_type); 415bf215546Sopenharmony_ci for(i = 0; i < n; ++i) { 416bf215546Sopenharmony_ci LLVMValueRef index = lp_build_const_int32(gallivm, i); 417bf215546Sopenharmony_ci LLVMValueRef arg_elems[LP_MAX_FUNC_ARGS]; 418bf215546Sopenharmony_ci LLVMValueRef res_elem; 419bf215546Sopenharmony_ci for(j = 0; j < num_args; ++j) 420bf215546Sopenharmony_ci arg_elems[j] = LLVMBuildExtractElement(builder, args[j], index, ""); 421bf215546Sopenharmony_ci res_elem = lp_build_intrinsic(builder, name, ret_elem_type, arg_elems, num_args, 0); 422bf215546Sopenharmony_ci res = LLVMBuildInsertElement(builder, res, res_elem, index, ""); 423bf215546Sopenharmony_ci } 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci return res; 426bf215546Sopenharmony_ci} 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ciLLVMValueRef 430bf215546Sopenharmony_cilp_build_intrinsic_map_unary(struct gallivm_state *gallivm, 431bf215546Sopenharmony_ci const char *name, 432bf215546Sopenharmony_ci LLVMTypeRef ret_type, 433bf215546Sopenharmony_ci LLVMValueRef a) 434bf215546Sopenharmony_ci{ 435bf215546Sopenharmony_ci return lp_build_intrinsic_map(gallivm, name, ret_type, &a, 1); 436bf215546Sopenharmony_ci} 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ciLLVMValueRef 440bf215546Sopenharmony_cilp_build_intrinsic_map_binary(struct gallivm_state *gallivm, 441bf215546Sopenharmony_ci const char *name, 442bf215546Sopenharmony_ci LLVMTypeRef ret_type, 443bf215546Sopenharmony_ci LLVMValueRef a, 444bf215546Sopenharmony_ci LLVMValueRef b) 445bf215546Sopenharmony_ci{ 446bf215546Sopenharmony_ci LLVMValueRef args[2]; 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci args[0] = a; 449bf215546Sopenharmony_ci args[1] = b; 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci return lp_build_intrinsic_map(gallivm, name, ret_type, args, 2); 452bf215546Sopenharmony_ci} 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci 455