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 
46 void
dump_type(FILE * fp,struct lp_type type)47 dump_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 
59 double
read_elem(struct lp_type type,const void * src,unsigned index)60 read_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 
122 void
write_elem(struct lp_type type,void * dst,unsigned index,double value)123 write_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 
191 void
random_elem(struct lp_type type,void * dst,unsigned index)192 random_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 
219 void
read_vec(struct lp_type type,const void * src,double * dst)220 read_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 
228 void
write_vec(struct lp_type type,void * dst,const double * src)229 write_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 
237 float
random_float(void)238 random_float(void)
239 {
240     return (float)((double)rand()/(double)RAND_MAX);
241 }
242 
243 
244 void
random_vec(struct lp_type type,void * dst)245 random_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 
253 boolean
compare_vec_with_eps(struct lp_type type,const void * res,const void * ref,double eps)254 compare_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 
275 boolean
compare_vec(struct lp_type type,const void * res,const void * ref)276 compare_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 
283 void
dump_vec(FILE * fp,struct lp_type type,const void * src)284 dump_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 
main(int argc,char ** argv)365 int 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