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