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         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      }
211   }
212   if(!type.sign)
213      if(rand() & 1)
214         value = -value;
215   write_elem(type, dst, index, value);
216}
217
218
219void
220read_vec(struct lp_type type, const void *src, double *dst)
221{
222   unsigned i;
223   for (i = 0; i < type.length; ++i)
224      dst[i] = read_elem(type, src, i);
225}
226
227
228void
229write_vec(struct lp_type type, void *dst, const double *src)
230{
231   unsigned i;
232   for (i = 0; i < type.length; ++i)
233      write_elem(type, dst, i, src[i]);
234}
235
236
237float
238random_float(void)
239{
240    return (float)((double)rand()/(double)RAND_MAX);
241}
242
243
244void
245random_vec(struct lp_type type, void *dst)
246{
247   unsigned i;
248   for (i = 0; i < type.length; ++i)
249      random_elem(type, dst, i);
250}
251
252
253boolean
254compare_vec_with_eps(struct lp_type type, const void *res, const void *ref, double eps)
255{
256   unsigned i;
257   eps *= type.floating ? 8.0 : 2.0;
258   for (i = 0; i < type.length; ++i) {
259      double res_elem = read_elem(type, res, i);
260      double ref_elem = read_elem(type, ref, i);
261      double delta = res_elem - ref_elem;
262      if (ref_elem < -1.0 || ref_elem > 1.0) {
263	 delta /= ref_elem;
264      }
265      delta = fabs(delta);
266      if (delta >= eps) {
267         return FALSE;
268      }
269   }
270
271   return TRUE;
272}
273
274
275boolean
276compare_vec(struct lp_type type, const void *res, const void *ref)
277{
278   double eps = lp_const_eps(type);
279   return compare_vec_with_eps(type, res, ref, eps);
280}
281
282
283void
284dump_vec(FILE *fp, struct lp_type type, const void *src)
285{
286   unsigned i;
287   for (i = 0; i < type.length; ++i) {
288      if(i)
289         fprintf(fp, " ");
290      if (type.floating) {
291         double value;
292         switch(type.width) {
293         case 32:
294            value = *((const float *)src + i);
295            break;
296         case 64:
297            value = *((const double *)src + i);
298            break;
299         default:
300            assert(0);
301            value = 0.0;
302         }
303         fprintf(fp, "%f", value);
304      }
305      else {
306         if(type.sign && !type.norm) {
307            long long value;
308            const char *format;
309            switch(type.width) {
310            case 8:
311               value = *((const int8_t *)src + i);
312               format = "%3lli";
313               break;
314            case 16:
315               value = *((const int16_t *)src + i);
316               format = "%5lli";
317               break;
318            case 32:
319               value = *((const int32_t *)src + i);
320               format = "%10lli";
321               break;
322            case 64:
323               value = *((const int64_t *)src + i);
324               format = "%20lli";
325               break;
326            default:
327               assert(0);
328               value = 0.0;
329               format = "?";
330            }
331            fprintf(fp, format, value);
332         }
333         else {
334            unsigned long long value;
335            const char *format;
336            switch(type.width) {
337            case 8:
338               value = *((const uint8_t *)src + i);
339               format = type.norm ? "%2x" : "%4llu";
340               break;
341            case 16:
342               value = *((const uint16_t *)src + i);
343               format = type.norm ? "%4x" : "%6llx";
344               break;
345            case 32:
346               value = *((const uint32_t *)src + i);
347               format = type.norm ? "%8x" : "%11llx";
348               break;
349            case 64:
350               value = *((const uint64_t *)src + i);
351               format = type.norm ? "%16x" : "%21llx";
352               break;
353            default:
354               assert(0);
355               value = 0.0;
356               format = "?";
357            }
358            fprintf(fp, format, value);
359         }
360      }
361   }
362}
363
364
365int main(int argc, char **argv)
366{
367   unsigned verbose = 0;
368   FILE *fp = NULL;
369   unsigned long n = 1000;
370   unsigned i;
371   boolean success;
372   boolean single = FALSE;
373
374   for(i = 1; i < argc; ++i) {
375      if(strcmp(argv[i], "-v") == 0)
376         ++verbose;
377      else if(strcmp(argv[i], "-s") == 0)
378         single = TRUE;
379      else if(strcmp(argv[i], "-o") == 0)
380         fp = fopen(argv[++i], "wt");
381      else
382         n = atoi(argv[i]);
383   }
384
385   lp_build_init();
386
387#ifdef DEBUG
388   if (verbose >= 2) {
389      gallivm_debug |= GALLIVM_DEBUG_IR;
390      gallivm_debug |= GALLIVM_DEBUG_ASM;
391   }
392#endif
393
394   util_cpu_detect();
395
396   if(fp) {
397      /* Warm up the caches */
398      test_some(0, NULL, 100);
399
400      write_tsv_header(fp);
401   }
402
403   if (single)
404      success = test_single(verbose, fp);
405   else if (n)
406      success = test_some(verbose, fp, n);
407   else
408      success = test_all(verbose, fp);
409
410   if(fp)
411      fclose(fp);
412
413   return success ? 0 : 1;
414}
415