llvmpipe: Use lp_build_ifloor_fract for exp2 calculation.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_test_arit.c
1 /**************************************************************************
2 *
3 * Copyright 2011 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 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "util/u_pointer.h"
34 #include "util/u_memory.h"
35 #include "util/u_math.h"
36
37 #include "gallivm/lp_bld.h"
38 #include "gallivm/lp_bld_init.h"
39 #include "gallivm/lp_bld_arit.h"
40
41 #include "lp_test.h"
42
43
44 void
45 write_tsv_header(FILE *fp)
46 {
47 fprintf(fp,
48 "result\t"
49 "format\n");
50
51 fflush(fp);
52 }
53
54
55 typedef float (*unary_func_t)(float);
56
57
58 /**
59 * Describe a test case of one unary function.
60 */
61 struct unary_test_t
62 {
63 /*
64 * Test name -- name of the mathematical function under test.
65 */
66
67 const char *name;
68
69 LLVMValueRef
70 (*builder)(struct lp_build_context *bld, LLVMValueRef a);
71
72 /*
73 * Reference (pure-C) function.
74 */
75 float
76 (*ref)(float a);
77
78 /*
79 * Test values.
80 */
81 const float *values;
82 unsigned num_values;
83 };
84
85
86 const float exp2_values[] = {
87 -60,
88 -4,
89 -2,
90 -1,
91 -1e-007,
92 0,
93 1e-007,
94 0.01,
95 0.1,
96 0.9,
97 0.99,
98 1,
99 2,
100 4,
101 60
102 };
103
104
105 const float log2_values[] = {
106 #if 0
107 /*
108 * Smallest denormalized number; meant just for experimentation, but not
109 * validation.
110 */
111 1.4012984643248171e-45,
112 #endif
113 1e-007,
114 0.1,
115 0.5,
116 0.99,
117 1,
118 1.01,
119 1.1,
120 1.9,
121 1.99,
122 2,
123 4,
124 100000,
125 1e+018
126 };
127
128
129 static float rsqrtf(float x)
130 {
131 return 1.0/sqrt(x);
132 }
133
134
135 const float rsqrt_values[] = {
136 -1, -1e-007,
137 1e-007, 1,
138 -4, -1,
139 1, 4,
140 -1e+035, -100000,
141 100000, 1e+035,
142 };
143
144
145 const float sincos_values[] = {
146 -5*M_PI/4,
147 -4*M_PI/4,
148 -4*M_PI/4,
149 -3*M_PI/4,
150 -2*M_PI/4,
151 -1*M_PI/4,
152 1*M_PI/4,
153 2*M_PI/4,
154 3*M_PI/4,
155 4*M_PI/4,
156 5*M_PI/4,
157 };
158
159
160 /*
161 * Unary test cases.
162 */
163
164 static const struct unary_test_t unary_tests[] = {
165 {"exp2", &lp_build_exp2, &exp2f, exp2_values, Elements(exp2_values)},
166 {"log2", &lp_build_log2, &log2f, log2_values, Elements(log2_values)},
167 {"exp", &lp_build_exp, &expf, exp2_values, Elements(exp2_values)},
168 {"log", &lp_build_log, &logf, log2_values, Elements(log2_values)},
169 {"rsqrt", &lp_build_rsqrt, &rsqrtf, rsqrt_values, Elements(rsqrt_values)},
170 {"sin", &lp_build_sin, &sinf, sincos_values, Elements(sincos_values)},
171 {"cos", &lp_build_cos, &cosf, sincos_values, Elements(sincos_values)},
172 };
173
174
175 /*
176 * Build LLVM function that exercises the unary operator builder.
177 */
178 static LLVMValueRef
179 build_unary_test_func(struct gallivm_state *gallivm,
180 LLVMModuleRef module,
181 LLVMContextRef context,
182 const struct unary_test_t *test)
183 {
184 LLVMTypeRef i32t = LLVMInt32TypeInContext(context);
185 LLVMTypeRef f32t = LLVMFloatTypeInContext(context);
186 LLVMTypeRef v4f32t = LLVMVectorType(f32t, 4);
187 LLVMTypeRef args[1] = { f32t };
188 LLVMValueRef func = LLVMAddFunction(module, test->name, LLVMFunctionType(f32t, args, Elements(args), 0));
189 LLVMValueRef arg1 = LLVMGetParam(func, 0);
190 LLVMBuilderRef builder = gallivm->builder;
191 LLVMBasicBlockRef block = LLVMAppendBasicBlockInContext(context, func, "entry");
192 LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0);
193 LLVMValueRef ret;
194
195 struct lp_build_context bld;
196
197 lp_build_context_init(&bld, gallivm, lp_float32_vec4_type());
198
199 LLVMSetFunctionCallConv(func, LLVMCCallConv);
200
201 LLVMPositionBuilderAtEnd(builder, block);
202
203 /* scalar to vector */
204 arg1 = LLVMBuildInsertElement(builder, LLVMGetUndef(v4f32t), arg1, index0, "");
205
206 ret = test->builder(&bld, arg1);
207
208 /* vector to scalar */
209 ret = LLVMBuildExtractElement(builder, ret, index0, "");
210
211 LLVMBuildRet(builder, ret);
212 return func;
213 }
214
215
216 /*
217 * Test one LLVM unary arithmetic builder function.
218 */
219 static boolean
220 test_unary(struct gallivm_state *gallivm, unsigned verbose, FILE *fp, const struct unary_test_t *test)
221 {
222 LLVMModuleRef module = gallivm->module;
223 LLVMValueRef test_func;
224 LLVMExecutionEngineRef engine = gallivm->engine;
225 LLVMContextRef context = gallivm->context;
226 char *error = NULL;
227 unary_func_t test_func_jit;
228 boolean success = TRUE;
229 int i;
230
231 test_func = build_unary_test_func(gallivm, module, context, test);
232
233 if (LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) {
234 printf("LLVMVerifyModule: %s\n", error);
235 LLVMDumpModule(module);
236 abort();
237 }
238 LLVMDisposeMessage(error);
239
240 test_func_jit = (unary_func_t) pointer_to_func(LLVMGetPointerToGlobal(engine, test_func));
241
242 for (i = 0; i < test->num_values; ++i) {
243 float value = test->values[i];
244 float ref = test->ref(value);
245 float src = test_func_jit(value);
246
247 double error = fabs(src - ref);
248 double precision = error ? -log2(error/fabs(ref)) : FLT_MANT_DIG;
249
250 bool pass = precision >= 20.0;
251
252 if (isnan(ref)) {
253 continue;
254 }
255
256 if (!pass || verbose) {
257 printf("%s(%.9g): ref = %.9g, src = %.9g, precision = %f bits, %s\n",
258 test->name, value, ref, src, precision,
259 pass ? "PASS" : "FAIL");
260 }
261
262 if (!pass) {
263 success = FALSE;
264 }
265 }
266
267 LLVMFreeMachineCodeForFunction(engine, test_func);
268
269 return success;
270 }
271
272
273 boolean
274 test_all(struct gallivm_state *gallivm, unsigned verbose, FILE *fp)
275 {
276 boolean success = TRUE;
277 int i;
278
279 for (i = 0; i < Elements(unary_tests); ++i) {
280 if (!test_unary(gallivm, verbose, fp, &unary_tests[i])) {
281 success = FALSE;
282 }
283 }
284
285 return success;
286 }
287
288
289 boolean
290 test_some(struct gallivm_state *gallivm, unsigned verbose, FILE *fp,
291 unsigned long n)
292 {
293 /*
294 * Not randomly generated test cases, so test all.
295 */
296
297 return test_all(gallivm, verbose, fp);
298 }
299
300
301 boolean
302 test_single(struct gallivm_state *gallivm, unsigned verbose, FILE *fp)
303 {
304 return TRUE;
305 }