llvmpipe: Test only present functionality to allow regression testing.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_test_conv.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 * Unit tests for type conversion.
32 *
33 * @author Jose Fonseca <jfonseca@vmware.com>
34 */
35
36
37 #include "lp_bld_type.h"
38 #include "lp_bld_conv.h"
39 #include "lp_test.h"
40
41
42 typedef void (*conv_test_ptr_t)(const void *src, const void *dst);
43
44
45 void
46 write_tsv_header(FILE *fp)
47 {
48 fprintf(fp,
49 "result\t"
50 "cycles_per_channel\t"
51 "src_type\t"
52 "dst_type\n");
53
54 fflush(fp);
55 }
56
57
58 static void
59 write_tsv_row(FILE *fp,
60 union lp_type src_type,
61 union lp_type dst_type,
62 double cycles,
63 boolean success)
64 {
65 fprintf(fp, "%s\t", success ? "pass" : "fail");
66
67 fprintf(fp, "%.1f\t", cycles / MAX2(src_type.length, dst_type.length));
68
69 dump_type(fp, src_type);
70 fprintf(fp, "\t");
71
72 dump_type(fp, dst_type);
73 fprintf(fp, "\n");
74
75 fflush(fp);
76 }
77
78
79 static void
80 dump_conv_types(FILE *fp,
81 union lp_type src_type,
82 union lp_type dst_type)
83 {
84 fprintf(fp, "src_type=");
85 dump_type(fp, src_type);
86
87 fprintf(fp, " dst_type=");
88 dump_type(fp, dst_type);
89
90 fprintf(fp, " ...\n");
91 fflush(fp);
92 }
93
94
95 static LLVMValueRef
96 add_conv_test(LLVMModuleRef module,
97 union lp_type src_type, unsigned num_srcs,
98 union lp_type dst_type, unsigned num_dsts)
99 {
100 LLVMTypeRef args[2];
101 LLVMValueRef func;
102 LLVMValueRef src_ptr;
103 LLVMValueRef dst_ptr;
104 LLVMBasicBlockRef block;
105 LLVMBuilderRef builder;
106 LLVMValueRef src[LP_MAX_VECTOR_LENGTH];
107 LLVMValueRef dst[LP_MAX_VECTOR_LENGTH];
108 unsigned i;
109
110 args[0] = LLVMPointerType(lp_build_vec_type(src_type), 0);
111 args[1] = LLVMPointerType(lp_build_vec_type(dst_type), 0);
112
113 func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidType(), args, 2, 0));
114 LLVMSetFunctionCallConv(func, LLVMCCallConv);
115 src_ptr = LLVMGetParam(func, 0);
116 dst_ptr = LLVMGetParam(func, 1);
117
118 block = LLVMAppendBasicBlock(func, "entry");
119 builder = LLVMCreateBuilder();
120 LLVMPositionBuilderAtEnd(builder, block);
121
122 for(i = 0; i < num_srcs; ++i) {
123 LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
124 LLVMValueRef ptr = LLVMBuildGEP(builder, src_ptr, &index, 1, "");
125 src[i] = LLVMBuildLoad(builder, ptr, "");
126 }
127
128 lp_build_conv(builder, src_type, dst_type, src, num_srcs, dst, num_dsts);
129
130 for(i = 0; i < num_dsts; ++i) {
131 LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
132 LLVMValueRef ptr = LLVMBuildGEP(builder, dst_ptr, &index, 1, "");
133 LLVMBuildStore(builder, dst[i], ptr);
134 }
135
136 LLVMBuildRetVoid(builder);;
137
138 LLVMDisposeBuilder(builder);
139 return func;
140 }
141
142
143 static boolean
144 test_one(unsigned verbose,
145 FILE *fp,
146 union lp_type src_type,
147 union lp_type dst_type)
148 {
149 LLVMModuleRef module = NULL;
150 LLVMValueRef func = NULL;
151 LLVMExecutionEngineRef engine = NULL;
152 LLVMModuleProviderRef provider = NULL;
153 LLVMPassManagerRef pass = NULL;
154 char *error = NULL;
155 conv_test_ptr_t conv_test_ptr;
156 boolean success;
157 const unsigned n = 32;
158 int64_t cycles[n];
159 double cycles_avg = 0.0;
160 unsigned num_srcs;
161 unsigned num_dsts;
162 unsigned i, j;
163
164 if(verbose >= 1)
165 dump_conv_types(stdout, src_type, dst_type);
166
167 if(src_type.length > dst_type.length) {
168 num_srcs = 1;
169 num_dsts = src_type.length/dst_type.length;
170 }
171 else {
172 num_dsts = 1;
173 num_srcs = dst_type.length/src_type.length;
174 }
175
176 assert(src_type.width * src_type.length == dst_type.width * dst_type.length);
177
178 /* We must not loose or gain channels. Only precision */
179 assert(src_type.length * num_srcs == dst_type.length * num_dsts);
180
181 module = LLVMModuleCreateWithName("test");
182
183 func = add_conv_test(module, src_type, num_srcs, dst_type, num_dsts);
184
185 if(LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) {
186 LLVMDumpModule(module);
187 abort();
188 }
189 LLVMDisposeMessage(error);
190
191 provider = LLVMCreateModuleProviderForExistingModule(module);
192 if (LLVMCreateJITCompiler(&engine, provider, 1, &error)) {
193 if(verbose < 1)
194 dump_conv_types(stderr, src_type, dst_type);
195 fprintf(stderr, "%s\n", error);
196 LLVMDisposeMessage(error);
197 abort();
198 }
199
200 #if 0
201 pass = LLVMCreatePassManager();
202 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
203 /* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
204 * but there are more on SVN. */
205 LLVMAddConstantPropagationPass(pass);
206 LLVMAddInstructionCombiningPass(pass);
207 LLVMAddPromoteMemoryToRegisterPass(pass);
208 LLVMAddGVNPass(pass);
209 LLVMAddCFGSimplificationPass(pass);
210 LLVMRunPassManager(pass, module);
211 #else
212 (void)pass;
213 #endif
214
215 if(verbose >= 2)
216 LLVMDumpModule(module);
217
218 conv_test_ptr = (conv_test_ptr_t)LLVMGetPointerToGlobal(engine, func);
219
220 success = TRUE;
221 for(i = 0; i < n && success; ++i) {
222 unsigned src_stride = src_type.length*src_type.width/8;
223 unsigned dst_stride = dst_type.length*dst_type.width/8;
224 uint8_t src[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
225 uint8_t dst[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
226 double fref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
227 uint8_t ref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
228 int64_t start_counter = 0;
229 int64_t end_counter = 0;
230
231 for(j = 0; j < num_srcs; ++j) {
232 random_vec(src_type, src + j*src_stride);
233 read_vec(src_type, src + j*src_stride, fref + j*src_type.length);
234 }
235
236 for(j = 0; j < num_dsts; ++j) {
237 write_vec(dst_type, ref + j*dst_stride, fref + j*dst_type.length);
238 }
239
240 start_counter = rdtsc();
241 conv_test_ptr(src, dst);
242 end_counter = rdtsc();
243
244 cycles[i] = end_counter - start_counter;
245
246 for(j = 0; j < num_dsts; ++j) {
247 if(!compare_vec(dst_type, dst + j*dst_stride, ref + j*dst_stride))
248 success = FALSE;
249 }
250
251 if (!success) {
252 if(verbose < 1)
253 dump_conv_types(stderr, src_type, dst_type);
254 fprintf(stderr, "MISMATCH\n");
255
256 for(j = 0; j < num_srcs; ++j) {
257 fprintf(stderr, " Src%u: ", j);
258 dump_vec(stderr, src_type, src + j*src_stride);
259 fprintf(stderr, "\n");
260 }
261
262 #if 0
263 fprintf(stderr, " Ref: ", j);
264 for(j = 0; j < src_type.length*num_srcs; ++j)
265 fprintf(stderr, " %f", fref[j]);
266 fprintf(stderr, "\n");
267 #endif
268
269 for(j = 0; j < num_dsts; ++j) {
270 fprintf(stderr, " Dst%u: ", j);
271 dump_vec(stderr, dst_type, dst + j*dst_stride);
272 fprintf(stderr, "\n");
273
274 fprintf(stderr, " Ref%u: ", j);
275 dump_vec(stderr, dst_type, ref + j*dst_stride);
276 fprintf(stderr, "\n");
277 }
278 }
279 }
280
281 /*
282 * Unfortunately the output of cycle counter is not very reliable as it comes
283 * -- sometimes we get outliers (due IRQs perhaps?) which are
284 * better removed to avoid random or biased data.
285 */
286 {
287 double sum = 0.0, sum2 = 0.0;
288 double avg, std;
289 unsigned m;
290
291 for(i = 0; i < n; ++i) {
292 sum += cycles[i];
293 sum2 += cycles[i]*cycles[i];
294 }
295
296 avg = sum/n;
297 std = sqrtf((sum2 - n*avg*avg)/n);
298
299 m = 0;
300 sum = 0.0;
301 for(i = 0; i < n; ++i) {
302 if(fabs(cycles[i] - avg) <= 4.0*std) {
303 sum += cycles[i];
304 ++m;
305 }
306 }
307
308 cycles_avg = sum/m;
309
310 }
311
312 if(fp)
313 write_tsv_row(fp, src_type, dst_type, cycles_avg, success);
314
315 if (!success) {
316 static boolean firsttime = TRUE;
317 if(firsttime) {
318 if(verbose < 2)
319 LLVMDumpModule(module);
320 LLVMWriteBitcodeToFile(module, "conv.bc");
321 fprintf(stderr, "conv.bc written\n");
322 fprintf(stderr, "Invoke as \"llc -o - conv.bc\"\n");
323 firsttime = FALSE;
324 //abort();
325 }
326 }
327
328 LLVMFreeMachineCodeForFunction(engine, func);
329
330 LLVMDisposeExecutionEngine(engine);
331 if(pass)
332 LLVMDisposePassManager(pass);
333
334 return success;
335 }
336
337
338 const union lp_type conv_types[] = {
339 /* float, fixed, sign, norm, width, len */
340
341 {{ TRUE, FALSE, TRUE, TRUE, 32, 4 }},
342 {{ TRUE, FALSE, TRUE, FALSE, 32, 4 }},
343 {{ TRUE, FALSE, FALSE, TRUE, 32, 4 }},
344 {{ TRUE, FALSE, FALSE, FALSE, 32, 4 }},
345
346 #if 0
347 {{ FALSE, FALSE, TRUE, TRUE, 32, 4 }},
348 {{ FALSE, FALSE, TRUE, FALSE, 32, 4 }},
349 {{ FALSE, FALSE, FALSE, TRUE, 32, 4 }},
350 {{ FALSE, FALSE, FALSE, FALSE, 32, 4 }},
351
352 {{ FALSE, FALSE, TRUE, TRUE, 16, 8 }},
353 {{ FALSE, FALSE, TRUE, FALSE, 16, 8 }},
354 {{ FALSE, FALSE, FALSE, TRUE, 16, 8 }},
355 {{ FALSE, FALSE, FALSE, FALSE, 16, 8 }},
356
357 {{ FALSE, FALSE, TRUE, TRUE, 8, 16 }},
358 {{ FALSE, FALSE, TRUE, FALSE, 8, 16 }},
359 {{ FALSE, FALSE, FALSE, TRUE, 8, 16 }},
360 {{ FALSE, FALSE, FALSE, FALSE, 8, 16 }},
361 #else
362 {{ FALSE, FALSE, TRUE, FALSE, 32, 4 }},
363 {{ FALSE, FALSE, TRUE, FALSE, 16, 8 }},
364 {{ FALSE, FALSE, FALSE, FALSE, 8, 16 }},
365 {{ FALSE, FALSE, FALSE, TRUE, 8, 16 }},
366 #endif
367 };
368
369
370 const unsigned num_types = sizeof(conv_types)/sizeof(conv_types[0]);
371
372
373 boolean
374 test_all(unsigned verbose, FILE *fp)
375 {
376 const union lp_type *src_type;
377 const union lp_type *dst_type;
378 bool success = TRUE;
379
380 for(src_type = conv_types; src_type < &conv_types[num_types]; ++src_type) {
381 for(dst_type = conv_types; dst_type < &conv_types[num_types]; ++dst_type) {
382
383 if(src_type == dst_type)
384 continue;
385
386 if(src_type->norm != dst_type->norm)
387 continue;
388
389 if(!test_one(verbose, fp, *src_type, *dst_type))
390 success = FALSE;
391
392 }
393 }
394
395 return success;
396 }
397
398
399 boolean
400 test_some(unsigned verbose, FILE *fp, unsigned long n)
401 {
402 const union lp_type *src_type;
403 const union lp_type *dst_type;
404 unsigned long i;
405 bool success = TRUE;
406
407 for(i = 0; i < n; ++i) {
408 src_type = &conv_types[random() % num_types];
409
410 do {
411 dst_type = &conv_types[random() % num_types];
412 } while (src_type == dst_type || src_type->norm != dst_type->norm);
413
414 if(!test_one(verbose, fp, *src_type, *dst_type))
415 success = FALSE;
416 }
417
418 return success;
419 }