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