gallivm: Allow target specific intrinsics in lp_declare_intrinsic()
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_intr.c
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 /**
30 * @file
31 * Helpers for emiting intrinsic calls.
32 *
33 * LLVM vanilla IR doesn't represent all basic arithmetic operations we care
34 * about, and it is often necessary to resort target-specific intrinsics for
35 * performance, convenience.
36 *
37 * Ideally we would like to stay away from target specific intrinsics and
38 * move all the instruction selection logic into upstream LLVM where it belongs.
39 *
40 * These functions are also used for calling C functions provided by us from
41 * generated LLVM code.
42 *
43 * @author Jose Fonseca <jfonseca@vmware.com>
44 */
45
46
47 #include "util/u_debug.h"
48
49 #include "lp_bld_const.h"
50 #include "lp_bld_intr.h"
51
52
53 LLVMValueRef
54 lp_declare_intrinsic(LLVMModuleRef module,
55 const char *name,
56 LLVMTypeRef ret_type,
57 LLVMTypeRef *arg_types,
58 unsigned num_args)
59 {
60 LLVMTypeRef function_type;
61 LLVMValueRef function;
62
63 assert(!LLVMGetNamedFunction(module, name));
64
65 function_type = LLVMFunctionType(ret_type, arg_types, num_args, 0);
66 function = LLVMAddFunction(module, name, function_type);
67
68 LLVMSetFunctionCallConv(function, LLVMCCallConv);
69 LLVMSetLinkage(function, LLVMExternalLinkage);
70
71 assert(LLVMIsDeclaration(function));
72
73 return function;
74 }
75
76
77 LLVMValueRef
78 lp_build_intrinsic(LLVMBuilderRef builder,
79 const char *name,
80 LLVMTypeRef ret_type,
81 LLVMValueRef *args,
82 unsigned num_args)
83 {
84 LLVMModuleRef module = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)));
85 LLVMValueRef function;
86
87 function = LLVMGetNamedFunction(module, name);
88 if(!function) {
89 LLVMTypeRef arg_types[LP_MAX_FUNC_ARGS];
90 unsigned i;
91
92 assert(num_args <= LP_MAX_FUNC_ARGS);
93
94 for(i = 0; i < num_args; ++i) {
95 assert(args[i]);
96 arg_types[i] = LLVMTypeOf(args[i]);
97 }
98
99 function = lp_declare_intrinsic(module, name, ret_type, arg_types, num_args);
100 }
101
102 return LLVMBuildCall(builder, function, args, num_args, "");
103 }
104
105
106 LLVMValueRef
107 lp_build_intrinsic_unary(LLVMBuilderRef builder,
108 const char *name,
109 LLVMTypeRef ret_type,
110 LLVMValueRef a)
111 {
112 return lp_build_intrinsic(builder, name, ret_type, &a, 1);
113 }
114
115
116 LLVMValueRef
117 lp_build_intrinsic_binary(LLVMBuilderRef builder,
118 const char *name,
119 LLVMTypeRef ret_type,
120 LLVMValueRef a,
121 LLVMValueRef b)
122 {
123 LLVMValueRef args[2];
124
125 args[0] = a;
126 args[1] = b;
127
128 return lp_build_intrinsic(builder, name, ret_type, args, 2);
129 }
130
131
132 LLVMValueRef
133 lp_build_intrinsic_map(struct gallivm_state *gallivm,
134 const char *name,
135 LLVMTypeRef ret_type,
136 LLVMValueRef *args,
137 unsigned num_args)
138 {
139 LLVMBuilderRef builder = gallivm->builder;
140 LLVMTypeRef ret_elem_type = LLVMGetElementType(ret_type);
141 unsigned n = LLVMGetVectorSize(ret_type);
142 unsigned i, j;
143 LLVMValueRef res;
144
145 assert(num_args <= LP_MAX_FUNC_ARGS);
146
147 res = LLVMGetUndef(ret_type);
148 for(i = 0; i < n; ++i) {
149 LLVMValueRef index = lp_build_const_int32(gallivm, i);
150 LLVMValueRef arg_elems[LP_MAX_FUNC_ARGS];
151 LLVMValueRef res_elem;
152 for(j = 0; j < num_args; ++j)
153 arg_elems[j] = LLVMBuildExtractElement(builder, args[j], index, "");
154 res_elem = lp_build_intrinsic(builder, name, ret_elem_type, arg_elems, num_args);
155 res = LLVMBuildInsertElement(builder, res, res_elem, index, "");
156 }
157
158 return res;
159 }
160
161
162 LLVMValueRef
163 lp_build_intrinsic_map_unary(struct gallivm_state *gallivm,
164 const char *name,
165 LLVMTypeRef ret_type,
166 LLVMValueRef a)
167 {
168 return lp_build_intrinsic_map(gallivm, name, ret_type, &a, 1);
169 }
170
171
172 LLVMValueRef
173 lp_build_intrinsic_map_binary(struct gallivm_state *gallivm,
174 const char *name,
175 LLVMTypeRef ret_type,
176 LLVMValueRef a,
177 LLVMValueRef b)
178 {
179 LLVMValueRef args[2];
180
181 args[0] = a;
182 args[1] = b;
183
184 return lp_build_intrinsic_map(gallivm, name, ret_type, args, 2);
185 }
186
187