1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //    http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "function_list.h"
18 #include "reference_math.h"
19 #include "test_functions.h"
20 
21 #define FTZ_ON 1
22 #define FTZ_OFF 0
23 #define EXACT 0.0f
24 #define RELAXED_ON 1
25 #define RELAXED_OFF 0
26 
27 #define STRINGIFY(_s) #_s
28 
29 // Only use ulps information in spir test
30 #ifdef FUNCTION_LIST_ULPS_ONLY
31 
32 #define ENTRY(_name, _ulp, _embedded_ulp, _rmode, _type)                       \
33     {                                                                          \
34         STRINGIFY(_name), STRINGIFY(_name), { NULL }, { NULL }, { NULL },      \
35             _ulp, _ulp, _embedded_ulp, INFINITY, INFINITY, _rmode,             \
36             RELAXED_OFF, _type                                                 \
37     }
38 #define ENTRY_EXT(_name, _ulp, _embedded_ulp, _relaxed_ulp, _rmode, _type,     \
39                   _relaxed_embedded_ulp)                                       \
40     {                                                                          \
41         STRINGIFY(_name), STRINGIFY(_name), { NULL }, { NULL }, { NULL },      \
42             _ulp, _ulp, _embedded_ulp, _relaxed_ulp, _relaxed_embedded_ulp,    \
43             _rmode, RELAXED_ON, _type                                          \
44     }
45 #define HALF_ENTRY(_name, _ulp, _embedded_ulp, _rmode, _type)                  \
46     {                                                                          \
47         "half_" STRINGIFY(_name), "half_" STRINGIFY(_name), { NULL },          \
48             { NULL }, { NULL }, _ulp, _ulp, _embedded_ulp, INFINITY, INFINITY, \
49             _rmode, RELAXED_OFF, _type                                         \
50     }
51 #define OPERATOR_ENTRY(_name, _operator, _ulp, _embedded_ulp, _rmode, _type)   \
52     {                                                                          \
53         STRINGIFY(_name), _operator, { NULL }, { NULL }, { NULL }, _ulp, _ulp, \
54             _embedded_ulp, INFINITY, INFINITY, _rmode, RELAXED_OFF, _type      \
55     }
56 #define unaryF NULL
57 #define i_unaryF NULL
58 #define unaryF_u NULL
59 #define macro_unaryF NULL
60 #define binaryF NULL
61 #define binaryOperatorF NULL
62 #define binaryF_i NULL
63 #define macro_binaryF NULL
64 #define ternaryF NULL
65 #define unaryF_two_results NULL
66 #define unaryF_two_results_i NULL
67 #define binaryF_two_results_i NULL
68 #define mad_function NULL
69 
70 #define reference_sqrt NULL
71 #define reference_sqrtl NULL
72 #define reference_divide NULL
73 #define reference_dividel NULL
74 #define reference_relaxed_divide NULL
75 
76 #else // FUNCTION_LIST_ULPS_ONLY
77 
78 #define ENTRY(_name, _ulp, _embedded_ulp, _rmode, _type)                       \
79     {                                                                          \
80         STRINGIFY(_name), STRINGIFY(_name), { (void*)reference_##_name },      \
81             { (void*)reference_##_name##l }, { (void*)reference_##_name },     \
82             _ulp, _ulp, _embedded_ulp, INFINITY, INFINITY, _rmode,             \
83             RELAXED_OFF, _type                                                 \
84     }
85 #define ENTRY_EXT(_name, _ulp, _embedded_ulp, _relaxed_ulp, _rmode, _type,     \
86                   _relaxed_embedded_ulp)                                       \
87     {                                                                          \
88         STRINGIFY(_name), STRINGIFY(_name), { (void*)reference_##_name },      \
89             { (void*)reference_##_name##l },                                   \
90             { (void*)reference_##relaxed_##_name }, _ulp, _ulp, _embedded_ulp, \
91             _relaxed_ulp, _relaxed_embedded_ulp, _rmode, RELAXED_ON, _type     \
92     }
93 #define HALF_ENTRY(_name, _ulp, _embedded_ulp, _rmode, _type)                  \
94     {                                                                          \
95         "half_" STRINGIFY(_name), "half_" STRINGIFY(_name),                    \
96             { (void*)reference_##_name }, { NULL }, { NULL }, _ulp, _ulp,      \
97             _embedded_ulp, INFINITY, INFINITY, _rmode, RELAXED_OFF, _type      \
98     }
99 #define OPERATOR_ENTRY(_name, _operator, _ulp, _embedded_ulp, _rmode, _type)   \
100     {                                                                          \
101         STRINGIFY(_name), _operator, { (void*)reference_##_name },             \
102             { (void*)reference_##_name##l }, { NULL }, _ulp, _ulp,             \
103             _embedded_ulp, INFINITY, INFINITY, _rmode, RELAXED_OFF, _type      \
104     }
105 
106 static constexpr vtbl _unary = {
107     "unary",
108     TestFunc_Float_Float,
109     TestFunc_Double_Double,
110 };
111 
112 static constexpr vtbl _i_unary = {
113     "i_unary",
114     TestFunc_Int_Float,
115     TestFunc_Int_Double,
116 };
117 
118 static constexpr vtbl _unary_u = {
119     "unary_u",
120     TestFunc_Float_UInt,
121     TestFunc_Double_ULong,
122 };
123 
124 static constexpr vtbl _macro_unary = {
125     "macro_unary",
126     TestMacro_Int_Float,
127     TestMacro_Int_Double,
128 };
129 
130 static constexpr vtbl _binary = {
131     "binary",
132     TestFunc_Float_Float_Float,
133     TestFunc_Double_Double_Double,
134 };
135 
136 static constexpr vtbl _binary_operator = {
137     "binaryOperator",
138     TestFunc_Float_Float_Float_Operator,
139     TestFunc_Double_Double_Double_Operator,
140 };
141 
142 static constexpr vtbl _binary_i = {
143     "binary_i",
144     TestFunc_Float_Float_Int,
145     TestFunc_Double_Double_Int,
146 };
147 
148 static constexpr vtbl _macro_binary = {
149     "macro_binary",
150     TestMacro_Int_Float_Float,
151     TestMacro_Int_Double_Double,
152 };
153 
154 static constexpr vtbl _ternary = {
155     "ternary",
156     TestFunc_Float_Float_Float_Float,
157     TestFunc_Double_Double_Double_Double,
158 };
159 
160 static constexpr vtbl _unary_two_results = {
161     "unary_two_results",
162     TestFunc_Float2_Float,
163     TestFunc_Double2_Double,
164 };
165 
166 static constexpr vtbl _unary_two_results_i = {
167     "unary_two_results_i",
168     TestFunc_FloatI_Float,
169     TestFunc_DoubleI_Double,
170 };
171 
172 static constexpr vtbl _binary_two_results_i = {
173     "binary_two_results_i",
174     TestFunc_FloatI_Float_Float,
175     TestFunc_DoubleI_Double_Double,
176 };
177 
178 static constexpr vtbl _mad_tbl = {
179     "ternary",
180     TestFunc_mad_Float,
181     TestFunc_mad_Double,
182 };
183 
184 #define unaryF &_unary
185 #define i_unaryF &_i_unary
186 #define unaryF_u &_unary_u
187 #define macro_unaryF &_macro_unary
188 #define binaryF &_binary
189 #define binaryOperatorF &_binary_operator
190 #define binaryF_i &_binary_i
191 #define macro_binaryF &_macro_binary
192 #define ternaryF &_ternary
193 #define unaryF_two_results &_unary_two_results
194 #define unaryF_two_results_i &_unary_two_results_i
195 #define binaryF_two_results_i &_binary_two_results_i
196 #define mad_function &_mad_tbl
197 
198 #endif // FUNCTION_LIST_ULPS_ONLY
199 
200 const Func functionList[] = {
201     ENTRY_EXT(acos, 4.0f, 4.0f, 4096.0f, FTZ_OFF, unaryF, 4096.0f),
202     ENTRY(acosh, 4.0f, 4.0f, FTZ_OFF, unaryF),
203     ENTRY(acospi, 5.0f, 5.0f, FTZ_OFF, unaryF),
204     ENTRY_EXT(asin, 4.0f, 4.0f, 4096.0f, FTZ_OFF, unaryF, 4096.0f),
205     ENTRY(asinh, 4.0f, 4.0f, FTZ_OFF, unaryF),
206     ENTRY(asinpi, 5.0f, 5.0f, FTZ_OFF, unaryF),
207     ENTRY_EXT(atan, 5.0f, 5.0f, 4096.0f, FTZ_OFF, unaryF, 4096.0f),
208     ENTRY(atanh, 5.0f, 5.0f, FTZ_OFF, unaryF),
209     ENTRY(atanpi, 5.0f, 5.0f, FTZ_OFF, unaryF),
210     ENTRY(atan2, 6.0f, 6.0f, FTZ_OFF, binaryF),
211     ENTRY(atan2pi, 6.0f, 6.0f, FTZ_OFF, binaryF),
212     ENTRY(cbrt, 2.0f, 4.0f, FTZ_OFF, unaryF),
213     ENTRY(ceil, 0.0f, 0.0f, FTZ_OFF, unaryF),
214     ENTRY(copysign, 0.0f, 0.0f, FTZ_OFF, binaryF),
215     ENTRY_EXT(cos, 4.0f, 4.0f, 0.00048828125f, FTZ_OFF, unaryF,
216               0.00048828125f), // relaxed ulp 2^-11
217     ENTRY(cosh, 4.0f, 4.0f, FTZ_OFF, unaryF),
218     ENTRY_EXT(cospi, 4.0f, 4.0f, 0.00048828125f, FTZ_OFF, unaryF,
219               0.00048828125f), // relaxed ulp 2^-11
220     //                                  ENTRY( erfc,                  16.0f,
221     //                                  16.0f,         FTZ_OFF,     unaryF),
222     //                                  //disabled for 1.0 due to lack of
223     //                                  reference implementation ENTRY( erf,
224     //                                  16.0f,         16.0f,         FTZ_OFF,
225     //                                  unaryF), //disabled for 1.0 due to lack
226     //                                  of reference implementation
227     ENTRY_EXT(exp, 3.0f, 4.0f, 3.0f, FTZ_OFF, unaryF,
228               4.0f), // relaxed error is actually overwritten in unary.c as it
229                      // is 3+floor(fabs(2*x))
230     ENTRY_EXT(exp2, 3.0f, 4.0f, 3.0f, FTZ_OFF, unaryF,
231               4.0f), // relaxed error is actually overwritten in unary.c as it
232                      // is 3+floor(fabs(2*x))
233     ENTRY_EXT(exp10, 3.0f, 4.0f, 8192.0f, FTZ_OFF, unaryF,
234               8192.0f), // relaxed error is actually overwritten in unary.c as
235                         // it is 3+floor(fabs(2*x)) in derived mode,
236     // in non-derived mode it uses the ulp error for half_exp10.
237     ENTRY(expm1, 3.0f, 4.0f, FTZ_OFF, unaryF),
238     ENTRY(fabs, 0.0f, 0.0f, FTZ_OFF, unaryF),
239     ENTRY(fdim, 0.0f, 0.0f, FTZ_OFF, binaryF),
240     ENTRY(floor, 0.0f, 0.0f, FTZ_OFF, unaryF),
241     ENTRY(fma, 0.0f, 0.0f, FTZ_OFF, ternaryF),
242     ENTRY(fmax, 0.0f, 0.0f, FTZ_OFF, binaryF),
243     ENTRY(fmin, 0.0f, 0.0f, FTZ_OFF, binaryF),
244     ENTRY(fmod, 0.0f, 0.0f, FTZ_OFF, binaryF),
245     ENTRY(fract, 0.0f, 0.0f, FTZ_OFF, unaryF_two_results),
246     ENTRY(frexp, 0.0f, 0.0f, FTZ_OFF, unaryF_two_results_i),
247     ENTRY(hypot, 4.0f, 4.0f, FTZ_OFF, binaryF),
248     ENTRY(ilogb, 0.0f, 0.0f, FTZ_OFF, i_unaryF),
249     ENTRY(isequal, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
250     ENTRY(isfinite, 0.0f, 0.0f, FTZ_OFF, macro_unaryF),
251     ENTRY(isgreater, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
252     ENTRY(isgreaterequal, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
253     ENTRY(isinf, 0.0f, 0.0f, FTZ_OFF, macro_unaryF),
254     ENTRY(isless, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
255     ENTRY(islessequal, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
256     ENTRY(islessgreater, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
257     ENTRY(isnan, 0.0f, 0.0f, FTZ_OFF, macro_unaryF),
258     ENTRY(isnormal, 0.0f, 0.0f, FTZ_OFF, macro_unaryF),
259     ENTRY(isnotequal, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
260     ENTRY(isordered, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
261     ENTRY(isunordered, 0.0f, 0.0f, FTZ_OFF, macro_binaryF),
262     ENTRY(ldexp, 0.0f, 0.0f, FTZ_OFF, binaryF_i),
263     ENTRY(lgamma, INFINITY, INFINITY, FTZ_OFF, unaryF),
264     ENTRY(lgamma_r, INFINITY, INFINITY, FTZ_OFF, unaryF_two_results_i),
265     ENTRY_EXT(log, 3.0f, 4.0f, 4.76837158203125e-7f, FTZ_OFF, unaryF,
266               4.76837158203125e-7f), // relaxed ulp 2^-21
267     ENTRY_EXT(log2, 3.0f, 4.0f, 4.76837158203125e-7f, FTZ_OFF, unaryF,
268               4.76837158203125e-7f), // relaxed ulp 2^-21
269     ENTRY_EXT(log10, 3.0f, 4.0f, 4.76837158203125e-7f, FTZ_OFF, unaryF,
270               4.76837158203125e-7f), // relaxed ulp 2^-21
271     ENTRY(log1p, 2.0f, 4.0f, FTZ_OFF, unaryF),
272     ENTRY(logb, 0.0f, 0.0f, FTZ_OFF, unaryF),
273     ENTRY_EXT(mad, INFINITY, INFINITY, INFINITY, FTZ_OFF, mad_function,
274               INFINITY), // in fast-relaxed-math mode it has to be either
275                          // exactly rounded fma or exactly rounded a*b+c
276     ENTRY(maxmag, 0.0f, 0.0f, FTZ_OFF, binaryF),
277     ENTRY(minmag, 0.0f, 0.0f, FTZ_OFF, binaryF),
278     ENTRY(modf, 0.0f, 0.0f, FTZ_OFF, unaryF_two_results),
279     ENTRY(nan, 0.0f, 0.0f, FTZ_OFF, unaryF_u),
280     ENTRY(nextafter, 0.0f, 0.0f, FTZ_OFF, binaryF),
281     ENTRY_EXT(pow, 16.0f, 16.0f, 8192.0f, FTZ_OFF, binaryF,
282               8192.0f), // in derived mode the ulp error is calculated as
283                         // exp2(y*log2(x)) and in non-derived it is the same as
284                         // half_pow
285     ENTRY(pown, 16.0f, 16.0f, FTZ_OFF, binaryF_i),
286     ENTRY(powr, 16.0f, 16.0f, FTZ_OFF, binaryF),
287     //                                  ENTRY( reciprocal,            1.0f,
288     //                                  1.0f,         FTZ_OFF,     unaryF),
289     ENTRY(remainder, 0.0f, 0.0f, FTZ_OFF, binaryF),
290     ENTRY(remquo, 0.0f, 0.0f, FTZ_OFF, binaryF_two_results_i),
291     ENTRY(rint, 0.0f, 0.0f, FTZ_OFF, unaryF),
292     ENTRY(rootn, 16.0f, 16.0f, FTZ_OFF, binaryF_i),
293     ENTRY(round, 0.0f, 0.0f, FTZ_OFF, unaryF),
294     ENTRY(rsqrt, 2.0f, 4.0f, FTZ_OFF, unaryF),
295     ENTRY(signbit, 0.0f, 0.0f, FTZ_OFF, macro_unaryF),
296     ENTRY_EXT(sin, 4.0f, 4.0f, 0.00048828125f, FTZ_OFF, unaryF,
297               0.00048828125f), // relaxed ulp 2^-11
298     ENTRY_EXT(sincos, 4.0f, 4.0f, 0.00048828125f, FTZ_OFF, unaryF_two_results,
299               0.00048828125f), // relaxed ulp 2^-11
300     ENTRY(sinh, 4.0f, 4.0f, FTZ_OFF, unaryF),
301     ENTRY_EXT(sinpi, 4.0f, 4.0f, 0.00048828125f, FTZ_OFF, unaryF,
302               0.00048828125f), // relaxed ulp 2^-11
303     { "sqrt",
304       "sqrt",
305       { (void*)reference_sqrt },
306       { (void*)reference_sqrtl },
307       { NULL },
308       3.0f,
309       0.0f,
310       4.0f,
311       INFINITY,
312       INFINITY,
313       FTZ_OFF,
314       RELAXED_OFF,
315       unaryF },
316     { "sqrt_cr",
317       "sqrt",
318       { (void*)reference_sqrt },
319       { (void*)reference_sqrtl },
320       { NULL },
321       0.0f,
322       0.0f,
323       0.0f,
324       INFINITY,
325       INFINITY,
326       FTZ_OFF,
327       RELAXED_OFF,
328       unaryF },
329     ENTRY_EXT(
330         tan, 5.0f, 5.0f, 8192.0f, FTZ_OFF, unaryF,
331         8192.0f), // in derived mode it the ulp error is calculated as sin/cos
332                   // and in non-derived mode it is the same as half_tan.
333     ENTRY(tanh, 5.0f, 5.0f, FTZ_OFF, unaryF),
334     ENTRY(tanpi, 6.0f, 6.0f, FTZ_OFF, unaryF),
335     //                                    ENTRY( tgamma,                 16.0f,
336     //                                    16.0f,         FTZ_OFF,     unaryF),
337     //                                    // Commented this out until we can be
338     //                                    sure this requirement is realistic
339     ENTRY(trunc, 0.0f, 0.0f, FTZ_OFF, unaryF),
340 
341     HALF_ENTRY(cos, 8192.0f, 8192.0f, FTZ_ON, unaryF),
342     HALF_ENTRY(divide, 8192.0f, 8192.0f, FTZ_ON, binaryF),
343     HALF_ENTRY(exp, 8192.0f, 8192.0f, FTZ_ON, unaryF),
344     HALF_ENTRY(exp2, 8192.0f, 8192.0f, FTZ_ON, unaryF),
345     HALF_ENTRY(exp10, 8192.0f, 8192.0f, FTZ_ON, unaryF),
346     HALF_ENTRY(log, 8192.0f, 8192.0f, FTZ_ON, unaryF),
347     HALF_ENTRY(log2, 8192.0f, 8192.0f, FTZ_ON, unaryF),
348     HALF_ENTRY(log10, 8192.0f, 8192.0f, FTZ_ON, unaryF),
349     HALF_ENTRY(powr, 8192.0f, 8192.0f, FTZ_ON, binaryF),
350     HALF_ENTRY(recip, 8192.0f, 8192.0f, FTZ_ON, unaryF),
351     HALF_ENTRY(rsqrt, 8192.0f, 8192.0f, FTZ_ON, unaryF),
352     HALF_ENTRY(sin, 8192.0f, 8192.0f, FTZ_ON, unaryF),
353     HALF_ENTRY(sqrt, 8192.0f, 8192.0f, FTZ_ON, unaryF),
354     HALF_ENTRY(tan, 8192.0f, 8192.0f, FTZ_ON, unaryF),
355 
356     // basic operations
357     OPERATOR_ENTRY(add, "+", 0.0f, 0.0f, FTZ_OFF, binaryOperatorF),
358     OPERATOR_ENTRY(subtract, "-", 0.0f, 0.0f, FTZ_OFF, binaryOperatorF),
359     { "divide",
360       "/",
361       { (void*)reference_divide },
362       { (void*)reference_dividel },
363       { (void*)reference_relaxed_divide },
364       2.5f,
365       0.0f,
366       3.0f,
367       2.5f,
368       INFINITY,
369       FTZ_OFF,
370       RELAXED_ON,
371       binaryOperatorF },
372     { "divide_cr",
373       "/",
374       { (void*)reference_divide },
375       { (void*)reference_dividel },
376       { (void*)reference_relaxed_divide },
377       0.0f,
378       0.0f,
379       0.0f,
380       0.f,
381       INFINITY,
382       FTZ_OFF,
383       RELAXED_OFF,
384       binaryOperatorF },
385     OPERATOR_ENTRY(multiply, "*", 0.0f, 0.0f, FTZ_OFF, binaryOperatorF),
386     OPERATOR_ENTRY(assignment, "", 0.0f, 0.0f, FTZ_OFF,
387                    unaryF), // A simple copy operation
388     OPERATOR_ENTRY(not, "!", 0.0f, 0.0f, FTZ_OFF, macro_unaryF),
389 };
390 
391 const size_t functionListCount = sizeof(functionList) / sizeof(functionList[0]);
392