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 * Shared testing code.
32 *
33 * @author Jose Fonseca <jfonseca@vmware.com>
34 */
35
36
37#include "util/u_math.h"
38
39#include "gallivm/lp_bld_const.h"
40#include "gallivm/lp_bld_init.h"
41#include "gallivm/lp_bld_debug.h"
42#include "lp_test.h"
43
44
45void
46dump_type(FILE *fp,
47          struct lp_type type)
48{
49   fprintf(fp, "%s%s%u%sx%u",
50           type.sign ? (type.floating || type.fixed ? "" : "s") : "u",
51           type.floating ? "f" : (type.fixed ? "h" : "i"),
52           type.width,
53           type.norm ? "n" : "",
54           type.length);
55}
56
57
58double
59read_elem(struct lp_type type, const void *src, unsigned index)
60{
61   double scale = lp_const_scale(type);
62   double value;
63   assert(index < type.length);
64   if (type.floating) {
65      switch(type.width) {
66      case 32:
67         value = *((const float *)src + index);
68         break;
69      case 64:
70         value =  *((const double *)src + index);
71         break;
72      default:
73         assert(0);
74         return 0.0;
75      }
76   }
77   else {
78      if(type.sign) {
79         switch(type.width) {
80         case 8:
81            value = *((const int8_t *)src + index);
82            break;
83         case 16:
84            value = *((const int16_t *)src + index);
85            break;
86         case 32:
87            value = *((const int32_t *)src + index);
88            break;
89         case 64:
90            value = *((const int64_t *)src + index);
91            break;
92         default:
93            assert(0);
94            return 0.0;
95         }
96      }
97      else {
98         switch(type.width) {
99         case 8:
100            value = *((const uint8_t *)src + index);
101            break;
102         case 16:
103            value = *((const uint16_t *)src + index);
104            break;
105         case 32:
106            value = *((const uint32_t *)src + index);
107            break;
108         case 64:
109            value = *((const uint64_t *)src + index);
110            break;
111         default:
112            assert(0);
113            return 0.0;
114         }
115      }
116   }
117   return value/scale;
118}
119
120
121void
122write_elem(struct lp_type type, void *dst, unsigned index, double value)
123{
124   assert(index < type.length);
125   if(!type.sign && value < 0.0)
126      value = 0.0;
127   if(type.norm && value < -1.0)
128      value = -1.0;
129   if(type.norm && value > 1.0)
130      value = 1.0;
131   if (type.floating) {
132      switch(type.width) {
133      case 32:
134         *((float *)dst + index) = (float)(value);
135         break;
136      case 64:
137          *((double *)dst + index) = value;
138         break;
139      default:
140         assert(0);
141      }
142   }
143   else {
144      double scale = lp_const_scale(type);
145      value = round(value*scale);
146      if(type.sign) {
147         long long lvalue = (long long)value;
148         lvalue = MIN2(lvalue, ((long long)1 << (type.width - 1)) - 1);
149         lvalue = MAX2(lvalue, -((long long)1 << (type.width - 1)));
150         switch(type.width) {
151         case 8:
152            *((int8_t *)dst + index) = (int8_t)lvalue;
153            break;
154         case 16:
155            *((int16_t *)dst + index) = (int16_t)lvalue;
156            break;
157         case 32:
158            *((int32_t *)dst + index) = (int32_t)lvalue;
159            break;
160         case 64:
161            *((int64_t *)dst + index) = (int64_t)lvalue;
162            break;
163         default:
164            assert(0);
165         }
166      }
167      else {
168         unsigned long long lvalue = (long long)value;
169         lvalue = MIN2(lvalue, ((unsigned long long)1 << type.width) - 1);
170         switch(type.width) {
171         case 8:
172            *((uint8_t *)dst + index) = (uint8_t)lvalue;
173            break;
174         case 16:
175            *((uint16_t *)dst + index) = (uint16_t)lvalue;
176            break;
177         case 32:
178            *((uint32_t *)dst + index) = (uint32_t)lvalue;
179            break;
180         case 64:
181            *((uint64_t *)dst + index) = (uint64_t)lvalue;
182            break;
183         default:
184            assert(0);
185         }
186      }
187   }
188}
189
190
191void
192random_elem(struct lp_type type, void *dst, unsigned index)
193{
194   double value;
195   assert(index < type.length);
196   value = (double)rand()/(double)RAND_MAX;
197   if(!type.norm) {
198      if (type.floating) {
199         value *= 2.0;
200      }
201      else {
202         unsigned long long mask;
203         if (type.fixed)
204            mask = ((unsigned long long)1 << (type.width / 2)) - 1;
205         else if (type.sign)
206            mask = ((unsigned long long)1 << (type.width - 1)) - 1;
207         else
208            mask = ((unsigned long long)1 << type.width) - 1;
209         value += (double)(mask & rand());
210         if (!type.fixed && !type.sign && type.width == 32) {
211            /*
212             * rand only returns half the possible range
213             * XXX 64bit values...
214             */
215            if(rand() & 1)
216               value += (double)0x80000000;
217         }
218      }
219   }
220   if(type.sign)
221      if(rand() & 1)
222         value = -value;
223   write_elem(type, dst, index, value);
224}
225
226
227void
228read_vec(struct lp_type type, const void *src, double *dst)
229{
230   unsigned i;
231   for (i = 0; i < type.length; ++i)
232      dst[i] = read_elem(type, src, i);
233}
234
235
236void
237write_vec(struct lp_type type, void *dst, const double *src)
238{
239   unsigned i;
240   for (i = 0; i < type.length; ++i)
241      write_elem(type, dst, i, src[i]);
242}
243
244
245float
246random_float(void)
247{
248    return (float)((double)rand()/(double)RAND_MAX);
249}
250
251
252void
253random_vec(struct lp_type type, void *dst)
254{
255   unsigned i;
256   for (i = 0; i < type.length; ++i)
257      random_elem(type, dst, i);
258}
259
260
261boolean
262compare_vec_with_eps(struct lp_type type, const void *res, const void *ref, double eps)
263{
264   unsigned i;
265   eps *= type.floating ? 8.0 : 2.0;
266   for (i = 0; i < type.length; ++i) {
267      double res_elem = read_elem(type, res, i);
268      double ref_elem = read_elem(type, ref, i);
269      double delta = res_elem - ref_elem;
270      if (ref_elem < -1.0 || ref_elem > 1.0) {
271	 delta /= ref_elem;
272      }
273      delta = fabs(delta);
274      if (delta >= eps) {
275         return FALSE;
276      }
277   }
278
279   return TRUE;
280}
281
282
283boolean
284compare_vec(struct lp_type type, const void *res, const void *ref)
285{
286   double eps = lp_const_eps(type);
287   return compare_vec_with_eps(type, res, ref, eps);
288}
289
290
291void
292dump_vec(FILE *fp, struct lp_type type, const void *src)
293{
294   unsigned i;
295   for (i = 0; i < type.length; ++i) {
296      if(i)
297         fprintf(fp, " ");
298      if (type.floating) {
299         double value;
300         switch(type.width) {
301         case 32:
302            value = *((const float *)src + i);
303            break;
304         case 64:
305            value = *((const double *)src + i);
306            break;
307         default:
308            assert(0);
309            value = 0.0;
310         }
311         fprintf(fp, "%f", value);
312      }
313      else {
314         if(type.sign && !type.norm) {
315            long long value;
316            const char *format;
317            switch(type.width) {
318            case 8:
319               value = *((const int8_t *)src + i);
320               format = "%3lli";
321               break;
322            case 16:
323               value = *((const int16_t *)src + i);
324               format = "%5lli";
325               break;
326            case 32:
327               value = *((const int32_t *)src + i);
328               format = "%10lli";
329               break;
330            case 64:
331               value = *((const int64_t *)src + i);
332               format = "%20lli";
333               break;
334            default:
335               assert(0);
336               value = 0.0;
337               format = "?";
338            }
339            fprintf(fp, format, value);
340         }
341         else {
342            unsigned long long value;
343            const char *format;
344            switch(type.width) {
345            case 8:
346               value = *((const uint8_t *)src + i);
347               format = type.norm ? "%2x" : "%4llu";
348               break;
349            case 16:
350               value = *((const uint16_t *)src + i);
351               format = type.norm ? "%4x" : "%6llx";
352               break;
353            case 32:
354               value = *((const uint32_t *)src + i);
355               format = type.norm ? "%8x" : "%11llx";
356               break;
357            case 64:
358               value = *((const uint64_t *)src + i);
359               format = type.norm ? "%16x" : "%21llx";
360               break;
361            default:
362               assert(0);
363               value = 0.0;
364               format = "?";
365            }
366            fprintf(fp, format, value);
367         }
368      }
369   }
370}
371
372
373int main(int argc, char **argv)
374{
375   unsigned verbose = 0;
376   FILE *fp = NULL;
377   unsigned long n = 1000;
378   unsigned i;
379   boolean success;
380   boolean single = FALSE;
381   unsigned fpstate;
382
383   fpstate = util_fpstate_get();
384   util_fpstate_set_denorms_to_zero(fpstate);
385
386   if (!lp_build_init())
387      return 1;
388
389   for(i = 1; i < argc; ++i) {
390      if(strcmp(argv[i], "-v") == 0)
391         ++verbose;
392      else if(strcmp(argv[i], "-s") == 0)
393         single = TRUE;
394      else if(strcmp(argv[i], "-o") == 0)
395         fp = fopen(argv[++i], "wt");
396      else
397         n = atoi(argv[i]);
398   }
399
400#ifdef DEBUG
401   if (verbose >= 2) {
402      gallivm_debug |= GALLIVM_DEBUG_IR;
403      gallivm_debug |= GALLIVM_DEBUG_ASM;
404   }
405#endif
406
407   if (fp) {
408      /* Warm up the caches */
409      test_some(0, NULL, 100);
410
411      write_tsv_header(fp);
412   }
413
414   if (single)
415      success = test_single(verbose, fp);
416   else if (n)
417      success = test_some(verbose, fp, n);
418   else
419      success = test_all(verbose, fp);
420
421   if (fp)
422      fclose(fp);
423
424   LLVMShutdown();
425
426   return success ? 0 : 1;
427}
428