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