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