1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Precision and range tests for builtins and types.
25 *//*--------------------------------------------------------------------*/
27 #include "vktShaderBuiltinPrecisionTests.hpp"
28 #include "vktShaderExecutor.hpp"
29 #include "amber/vktAmberTestCase.hpp"
33 #include "deFloat16.h"
35 #include "deRandom.hpp"
36 #include "deSTLUtil.hpp"
37 #include "deStringUtil.hpp"
38 #include "deUniquePtr.hpp"
39 #include "deSharedPtr.hpp"
40 #include "deArrayUtil.hpp"
42 #include "tcuCommandLine.hpp"
43 #include "tcuFloatFormat.hpp"
44 #include "tcuInterval.hpp"
45 #include "tcuTestLog.hpp"
46 #include "tcuVector.hpp"
47 #include "tcuMatrix.hpp"
48 #include "tcuResultCollector.hpp"
49 #include "tcuMaybe.hpp"
51 #include "gluContextInfo.hpp"
52 #include "gluVarType.hpp"
53 #include "gluRenderContext.hpp"
54 #include "glwDefs.hpp"
64 // Uncomment this to get evaluation trace dumps to std::cerr
65 // #define GLS_ENABLE_TRACE
67 // set this to true to dump even passing results
68 #define GLS_LOG_ALL_RESULTS false
70 #define FLOAT16_1_0 0x3C00 //1.0 float16bit
71 #define FLOAT16_180_0 0x59A0 //180.0 float16bit
72 #define FLOAT16_2_0 0x4000 //2.0 float16bit
73 #define FLOAT16_3_0 0x4200 //3.0 float16bit
74 #define FLOAT16_0_5 0x3800 //0.5 float16bit
75 #define FLOAT16_0_0 0x0000 //0.0 float16bit
79 typedef Vector<deFloat16, 1> Vec1_16Bit;
80 typedef Vector<deFloat16, 2> Vec2_16Bit;
81 typedef Vector<deFloat16, 3> Vec3_16Bit;
82 typedef Vector<deFloat16, 4> Vec4_16Bit;
84 typedef Vector<double, 1> Vec1_64Bit;
85 typedef Vector<double, 2> Vec2_64Bit;
86 typedef Vector<double, 3> Vec3_64Bit;
87 typedef Vector<double, 4> Vec4_64Bit;
91 // Computing reference intervals can take a non-trivial amount of time, especially on
92 // platforms where toggling floating-point rounding mode is slow (emulated arm on x86).
93 // As a workaround watchdog is kept happy by touching it periodically during reference
94 // interval computation.
95 TOUCH_WATCHDOG_VALUE_FREQUENCY = 512
100 namespace shaderexecutor
106 using std::ostringstream;
116 using tcu::FloatFormat;
117 using tcu::MessageBuilder;
121 using glu::Precision;
124 using glu::ShaderType;
126 enum PrecisionTestFeatureBits
128 PRECISION_TEST_FEATURES_NONE = 0u,
129 PRECISION_TEST_FEATURES_16BIT_BUFFER_ACCESS = (1u << 1),
130 PRECISION_TEST_FEATURES_16BIT_UNIFORM_AND_STORAGE_BUFFER_ACCESS = (1u << 2),
131 PRECISION_TEST_FEATURES_16BIT_PUSH_CONSTANT = (1u << 3),
132 PRECISION_TEST_FEATURES_16BIT_INPUT_OUTPUT = (1u << 4),
133 PRECISION_TEST_FEATURES_16BIT_SHADER_FLOAT = (1u << 5),
134 PRECISION_TEST_FEATURES_64BIT_SHADER_FLOAT = (1u << 6),
136 typedef deUint32 PrecisionTestFeatures;
139 void areFeaturesSupported (const Context& context, deUint32 toCheck)
141 if (toCheck == PRECISION_TEST_FEATURES_NONE) return;
143 const vk::VkPhysicalDevice16BitStorageFeatures& extensionFeatures = context.get16BitStorageFeatures();
145 if ((toCheck & PRECISION_TEST_FEATURES_16BIT_BUFFER_ACCESS) != 0 && extensionFeatures.storageBuffer16BitAccess == VK_FALSE)
146 TCU_THROW(NotSupportedError, "Requested 16bit storage features not supported");
148 if ((toCheck & PRECISION_TEST_FEATURES_16BIT_UNIFORM_AND_STORAGE_BUFFER_ACCESS) != 0 && extensionFeatures.uniformAndStorageBuffer16BitAccess == VK_FALSE)
149 TCU_THROW(NotSupportedError, "Requested 16bit storage features not supported");
151 if ((toCheck & PRECISION_TEST_FEATURES_16BIT_PUSH_CONSTANT) != 0 && extensionFeatures.storagePushConstant16 == VK_FALSE)
152 TCU_THROW(NotSupportedError, "Requested 16bit storage features not supported");
154 if ((toCheck & PRECISION_TEST_FEATURES_16BIT_INPUT_OUTPUT) != 0 && extensionFeatures.storageInputOutput16 == VK_FALSE)
155 TCU_THROW(NotSupportedError, "Requested 16bit storage features not supported");
157 if ((toCheck & PRECISION_TEST_FEATURES_16BIT_SHADER_FLOAT) != 0 && context.getShaderFloat16Int8Features().shaderFloat16 == VK_FALSE)
158 TCU_THROW(NotSupportedError, "Requested 16-bit floats (halfs) are not supported in shader code");
160 if ((toCheck & PRECISION_TEST_FEATURES_64BIT_SHADER_FLOAT) != 0 && context.getDeviceFeatures().shaderFloat64 == VK_FALSE)
161 TCU_THROW(NotSupportedError, "Requested 64-bit floats are not supported in shader code");
164 /*--------------------------------------------------------------------*//*!
165 * \brief Generic singleton creator.
167 * instance<T>() returns a reference to a unique default-constructed instance
168 * of T. This is mainly used for our GLSL function implementations: each
169 * function is implemented by an object, and each of the objects has a
170 * distinct class. It would be extremely toilsome to maintain a separate
171 * context object that contained individual instances of the function classes,
172 * so we have to resort to global singleton instances.
174 *//*--------------------------------------------------------------------*/
175 template <typename T>
176 const T& instance (void)
178 static const T s_instance = T();
182 /*--------------------------------------------------------------------*//*!
183 * \brief Empty placeholder type for unused template parameters.
185 * In the precision tests we are dealing with functions of different arities.
186 * To minimize code duplication, we only define templates with the maximum
187 * number of arguments, currently four. If a function's arity is less than the
188 * maximum, Void us used as the type for unused arguments.
190 * Although Voids are not used at run-time, they still must be compilable, so
191 * they must support all operations that other types do.
193 *//*--------------------------------------------------------------------*/
196 typedef Void Element;
202 template <typename T>
203 explicit Void (const T&) {}
205 operator double (void) const { return TCU_NAN; }
207 // These are used to make Voids usable as containers in container-generic code.
208 Void& operator[] (int) { return *this; }
209 const Void& operator[] (int) const { return *this; }
212 ostream& operator<< (ostream& os, Void) { return os << "()"; }
214 //! Returns true for all other types except Void
215 template <typename T> bool isTypeValid (void) { return true; }
216 template <> bool isTypeValid<Void> (void) { return false; }
218 template <typename T> bool isInteger (void) { return false; }
219 template <> bool isInteger<int> (void) { return true; }
220 template <> bool isInteger<tcu::IVec2> (void) { return true; }
221 template <> bool isInteger<tcu::IVec3> (void) { return true; }
222 template <> bool isInteger<tcu::IVec4> (void) { return true; }
224 //! Utility function for getting the name of a data type.
225 //! This is used in vector and matrix constructors.
226 template <typename T>
227 const char* dataTypeNameOf (void)
229 return glu::getDataTypeName(glu::dataTypeOf<T>());
233 const char* dataTypeNameOf<Void> (void)
235 DE_FATAL("Impossible");
239 template <typename T>
240 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
242 return glu::varTypeOf<T>(prec);
245 //! A hack to get Void support for VarType.
247 VarType getVarTypeOf<Void> (Precision)
249 DE_FATAL("Impossible");
253 /*--------------------------------------------------------------------*//*!
254 * \brief Type traits for generalized interval types.
256 * We are trying to compute sets of acceptable values not only for
257 * float-valued expressions but also for compound values: vectors and
258 * matrices. We approximate a set of vectors as a vector of intervals and
259 * likewise for matrices.
261 * We now need generalized operations for each type and its interval
262 * approximation. These are given in the type Traits<T>.
264 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
265 * scalar types, and a vector or matrix of intervals for container types.
267 * To allow template inference to take place, there are function wrappers for
268 * the actual operations in Traits<T>. Hence we can just use:
270 * makeIVal(someFloat)
274 * Traits<float>::doMakeIVal(value)
276 *//*--------------------------------------------------------------------*/
278 template <typename T> struct Traits;
280 //! Create container from elementwise singleton values.
281 template <typename T>
282 typename Traits<T>::IVal makeIVal (const T& value)
284 return Traits<T>::doMakeIVal(value);
287 //! Elementwise union of intervals.
288 template <typename T>
289 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
290 const typename Traits<T>::IVal& b)
292 return Traits<T>::doUnion(a, b);
295 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
296 template <typename T, typename U = Void>
297 bool contains (const typename Traits<T>::IVal& ival, const T& value, bool is16Bit = false, const tcu::Maybe<U>& modularDivisor = tcu::Nothing)
299 return Traits<T>::doContains(ival, value, is16Bit, modularDivisor);
302 //! Print out an interval with the precision of `fmt`.
303 template <typename T>
304 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
306 Traits<T>::doPrintIVal(fmt, ival, os);
309 template <typename T>
310 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
313 printIVal<T>(fmt, ival, oss);
317 //! Print out a value with the precision of `fmt`.
318 template <typename T>
319 void printValue16 (const FloatFormat& fmt, const T& value, ostream& os)
321 Traits<T>::doPrintValue16(fmt, value, os);
324 template <typename T>
325 string value16ToString(const FloatFormat& fmt, const T& val)
328 printValue16(fmt, val, oss);
332 const std::string getComparisonOperation(const int ndx)
334 const int operationCount = 10;
335 DE_ASSERT(de::inBounds(ndx, 0, operationCount));
336 const std::string operations[operationCount] =
339 "OpFOrdGreaterThan\t",
340 "OpFOrdLessThan\t\t",
341 "OpFOrdGreaterThanEqual",
342 "OpFOrdLessThanEqual\t",
344 "OpFUnordGreaterThan\t",
345 "OpFUnordLessThan\t",
346 "OpFUnordGreaterThanEqual",
347 "OpFUnordLessThanEqual"
349 return operations[ndx];
352 template <typename T>
353 string comparisonMessage(const T& val)
360 string comparisonMessage(const int& val)
365 for(int ndx = 0; ndx < 10; ++ndx)
367 oss << getComparisonOperation(ndx) << "\t:\t" << ((flags & 1) == 1 ? "TRUE" : "FALSE") << "\n";
374 string comparisonMessage(const tcu::IVec2& val)
377 tcu::IVec2 flags = val;
378 for (int ndx = 0; ndx < 10; ++ndx)
380 oss << getComparisonOperation(ndx) << "\t:\t" << ((flags.x() & 1) == 1 ? "TRUE" : "FALSE") << "\t" << ((flags.y() & 1) == 1 ? "TRUE" : "FALSE") << "\n";
381 flags.x() = flags.x() >> 1;
382 flags.y() = flags.y() >> 1;
388 string comparisonMessage(const tcu::IVec3& val)
391 tcu::IVec3 flags = val;
392 for (int ndx = 0; ndx < 10; ++ndx)
394 oss << getComparisonOperation(ndx) << "\t:\t" << ((flags.x() & 1) == 1 ? "TRUE" : "FALSE") << "\t"
395 << ((flags.y() & 1) == 1 ? "TRUE" : "FALSE") << "\t"
396 << ((flags.z() & 1) == 1 ? "TRUE" : "FALSE") << "\n";
397 flags.x() = flags.x() >> 1;
398 flags.y() = flags.y() >> 1;
399 flags.z() = flags.z() >> 1;
405 string comparisonMessage(const tcu::IVec4& val)
408 tcu::IVec4 flags = val;
409 for (int ndx = 0; ndx < 10; ++ndx)
411 oss << getComparisonOperation(ndx) << "\t:\t" << ((flags.x() & 1) == 1 ? "TRUE" : "FALSE") << "\t"
412 << ((flags.y() & 1) == 1 ? "TRUE" : "FALSE") << "\t"
413 << ((flags.z() & 1) == 1 ? "TRUE" : "FALSE") << "\t"
414 << ((flags.w() & 1) == 1 ? "TRUE" : "FALSE") << "\n";
415 flags.x() = flags.x() >> 1;
416 flags.y() = flags.y() >> 1;
417 flags.z() = flags.z() >> 1;
418 flags.w() = flags.z() >> 1;
422 //! Print out a value with the precision of `fmt`.
423 template <typename T>
424 void printValue32 (const FloatFormat& fmt, const T& value, ostream& os)
426 Traits<T>::doPrintValue32(fmt, value, os);
429 template <typename T>
430 string value32ToString (const FloatFormat& fmt, const T& val)
433 printValue32(fmt, val, oss);
437 template <typename T>
438 void printValue64 (const FloatFormat& fmt, const T& value, ostream& os)
440 Traits<T>::doPrintValue64(fmt, value, os);
443 template <typename T>
444 string value64ToString (const FloatFormat& fmt, const T& val)
447 printValue64(fmt, val, oss);
451 //! Approximate `value` elementwise to the float precision defined in `fmt`.
452 //! The resulting interval might not be a singleton if rounding in both
453 //! directions is allowed.
454 template <typename T>
455 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
457 return Traits<T>::doRound(fmt, value);
460 template <typename T>
461 typename Traits<T>::IVal convert (const FloatFormat& fmt,
462 const typename Traits<T>::IVal& value)
464 return Traits<T>::doConvert(fmt, value);
467 // Matching input and output types. We may be in a modulo case and modularDivisor may have an actual value.
468 template <typename T>
469 bool intervalContains (const Interval& interval, T value, const tcu::Maybe<T>& modularDivisor)
471 bool contained = interval.contains(value);
473 if (!contained && modularDivisor)
475 const T divisor = modularDivisor.get();
477 // In a modulo operation, if the calculated answer contains the divisor, allow exactly 0.0 as a replacement. Alternatively,
478 // if the calculated answer contains 0.0, allow exactly the divisor as a replacement.
479 if (interval.contains(static_cast<double>(divisor)))
480 contained |= (value == 0.0);
481 if (interval.contains(0.0))
482 contained |= (value == divisor);
487 // When the input and output types do not match, we are not in a real modulo operation. Do not take the divisor into account. This
488 // version is provided for syntactical compatibility only.
489 template <typename T, typename U>
490 bool intervalContains (const Interval& interval, T value, const tcu::Maybe<U>& modularDivisor)
492 DE_UNREF(modularDivisor); // For release builds.
493 DE_ASSERT(!modularDivisor);
494 return interval.contains(value);
497 //! Common traits for scalar types.
498 template <typename T>
501 typedef Interval IVal;
503 static Interval doMakeIVal (const T& value)
505 // Thankfully all scalar types have a well-defined conversion to `double`,
506 // hence Interval can represent their ranges without problems.
507 return Interval(double(value));
510 static Interval doUnion (const Interval& a, const Interval& b)
515 static bool doContains (const Interval& a, T value)
517 return a.contains(double(value));
520 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
522 return fmt.convert(ival);
525 static Interval doConvert (const FloatFormat& fmt, const IVal& ival, bool is16Bit)
528 return fmt.convert(ival);
531 static Interval doRound (const FloatFormat& fmt, T value)
533 return fmt.roundOut(double(value), false);
538 struct ScalarTraits<deUint16>
540 typedef Interval IVal;
542 static Interval doMakeIVal (const deUint16& value)
544 // Thankfully all scalar types have a well-defined conversion to `double`,
545 // hence Interval can represent their ranges without problems.
546 return Interval(double(deFloat16To32(value)));
549 static Interval doUnion (const Interval& a, const Interval& b)
554 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
556 return fmt.convert(ival);
559 static Interval doRound (const FloatFormat& fmt, deUint16 value)
561 return fmt.roundOut(double(deFloat16To32(value)), false);
566 struct Traits<float> : ScalarTraits<float>
568 static void doPrintIVal (const FloatFormat& fmt,
569 const Interval& ival,
572 os << fmt.intervalToHex(ival);
575 static void doPrintValue16 (const FloatFormat& fmt,
579 const deUint32 iRep = reinterpret_cast<const deUint32 & >(value);
580 float res0 = deFloat16To32((deFloat16)(iRep & 0xFFFF));
581 float res1 = deFloat16To32((deFloat16)(iRep >> 16));
582 os << fmt.floatToHex(res0) << " " << fmt.floatToHex(res1);
585 static void doPrintValue32 (const FloatFormat& fmt,
589 os << fmt.floatToHex(value);
592 static void doPrintValue64 (const FloatFormat& fmt,
596 os << fmt.floatToHex(value);
599 template <typename U>
600 static bool doContains (const Interval& a, const float& value, bool is16Bit, const tcu::Maybe<U>& modularDivisor)
604 // Note: for deFloat16s packed in 32 bits, the original divisor is provided as a float to the shader in the input
605 // buffer, so U is also float here and we call the right interlvalContains() version.
606 const deUint32 iRep = reinterpret_cast<const deUint32&>(value);
607 float res0 = deFloat16To32((deFloat16)(iRep & 0xFFFF));
608 float res1 = deFloat16To32((deFloat16)(iRep >> 16));
609 return intervalContains(a, res0, modularDivisor) && (res1 == -1.0);
611 return intervalContains(a, value, modularDivisor);
616 struct Traits<double> : ScalarTraits<double>
618 static void doPrintIVal (const FloatFormat& fmt,
619 const Interval& ival,
622 os << fmt.intervalToHex(ival);
625 static void doPrintValue16 (const FloatFormat& fmt,
629 const deUint64 iRep = reinterpret_cast<const deUint64&>(value);
630 double byte0 = deFloat16To64((deFloat16)((iRep ) & 0xffff));
631 double byte1 = deFloat16To64((deFloat16)((iRep >> 16) & 0xffff));
632 double byte2 = deFloat16To64((deFloat16)((iRep >> 32) & 0xffff));
633 double byte3 = deFloat16To64((deFloat16)((iRep >> 48) & 0xffff));
634 os << fmt.floatToHex(byte0) << " " << fmt.floatToHex(byte1) << " " << fmt.floatToHex(byte2) << " " << fmt.floatToHex(byte3);
637 static void doPrintValue32 (const FloatFormat& fmt,
641 const deUint64 iRep = reinterpret_cast<const deUint64&>(value);
642 double res0 = static_cast<double>((float)((iRep ) & 0xffffffff));
643 double res1 = static_cast<double>((float)((iRep >> 32) & 0xffffffff));
644 os << fmt.floatToHex(res0) << " " << fmt.floatToHex(res1);
647 static void doPrintValue64 (const FloatFormat& fmt,
651 os << fmt.floatToHex(value);
655 static bool doContains (const Interval& a, const double& value, bool is16Bit, const tcu::Maybe<U>& modularDivisor)
659 return intervalContains(a, value, modularDivisor);
664 struct Traits<deFloat16> : ScalarTraits<deFloat16>
666 static void doPrintIVal (const FloatFormat& fmt,
667 const Interval& ival,
670 os << fmt.intervalToHex(ival);
673 static void doPrintValue16 (const FloatFormat& fmt,
674 const deFloat16& value,
677 const float res0 = deFloat16To32(value);
678 os << fmt.floatToHex(static_cast<double>(res0));
680 static void doPrintValue32 (const FloatFormat& fmt,
681 const deFloat16& value,
684 const float res0 = deFloat16To32(value);
685 os << fmt.floatToHex(static_cast<double>(res0));
688 static void doPrintValue64 (const FloatFormat& fmt,
689 const deFloat16& value,
692 const double res0 = deFloat16To64(value);
693 os << fmt.floatToHex(res0);
696 // When the value and divisor are both deFloat16, convert both to float to call the right intervalContains version.
697 static bool doContains (const Interval& a, const deFloat16& value, bool is16Bit, const tcu::Maybe<deFloat16>& modularDivisor)
700 float res0 = deFloat16To32(value);
701 const tcu::Maybe<float> convertedDivisor = (modularDivisor ? tcu::just(deFloat16To32(modularDivisor.get())) : tcu::Nothing);
702 return intervalContains(a, res0, convertedDivisor);
705 // If the types don't match we should not be in a modulo operation, so no conversion should take place.
707 static bool doContains (const Interval& a, const deFloat16& value, bool is16Bit, const tcu::Maybe<U>& modularDivisor)
710 float res0 = deFloat16To32(value);
711 return intervalContains(a, res0, modularDivisor);
716 struct Traits<bool> : ScalarTraits<bool>
718 static void doPrintValue16 (const FloatFormat&,
722 os << (value != 0.0f ? "true" : "false");
725 static void doPrintValue32 (const FloatFormat&,
729 os << (value != 0.0f ? "true" : "false");
732 static void doPrintValue64 (const FloatFormat&,
736 os << (value != 0.0f ? "true" : "false");
739 static void doPrintIVal (const FloatFormat&,
740 const Interval& ival,
744 if (ival.contains(false))
746 if (ival.contains(false) && ival.contains(true))
748 if (ival.contains(true))
755 struct Traits<int> : ScalarTraits<int>
757 static void doPrintValue16 (const FloatFormat&,
761 int res0 = value & 0xFFFF;
762 int res1 = value >> 16;
763 os << res0 << " " << res1;
766 static void doPrintValue32 (const FloatFormat&,
773 static void doPrintValue64 (const FloatFormat&,
780 static void doPrintIVal (const FloatFormat&,
781 const Interval& ival,
784 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
787 template <typename U>
788 static bool doContains (const Interval& a, const int& value, bool is16Bit, const tcu::Maybe<U>& modularDivisor)
791 return intervalContains(a, value, modularDivisor);
795 //! Common traits for containers, i.e. vectors and matrices.
796 //! T is the container type itself, I is the same type with interval elements.
797 template <typename T, typename I>
798 struct ContainerTraits
800 typedef typename T::Element Element;
803 static IVal doMakeIVal (const T& value)
807 for (int ndx = 0; ndx < T::SIZE; ++ndx)
808 ret[ndx] = makeIVal(value[ndx]);
813 static IVal doUnion (const IVal& a, const IVal& b)
817 for (int ndx = 0; ndx < T::SIZE; ++ndx)
818 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
823 // When the input and output types match, we may be in a modulo operation. If the divisor is provided, use each of its
824 // components to determine if the obtained result is fine.
825 static bool doContains (const IVal& ival, const T& value, bool is16Bit, const tcu::Maybe<T>& modularDivisor)
827 using DivisorElement = typename T::Element;
829 for (int ndx = 0; ndx < T::SIZE; ++ndx)
831 const tcu::Maybe<DivisorElement> divisorElement = (modularDivisor ? tcu::just((*modularDivisor)[ndx]) : tcu::Nothing);
832 if (!contains(ival[ndx], value[ndx], is16Bit, divisorElement))
839 // When the input and output types do not match we should not be in a modulo operation. This version is provided for syntactical
841 template <typename U>
842 static bool doContains (const IVal& ival, const T& value, bool is16Bit, const tcu::Maybe<U>& modularDivisor)
844 for (int ndx = 0; ndx < T::SIZE; ++ndx)
846 if (!contains(ival[ndx], value[ndx], is16Bit, modularDivisor))
853 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
857 for (int ndx = 0; ndx < T::SIZE; ++ndx)
862 printIVal<Element>(fmt, ival[ndx], os);
868 static void doPrintValue16 (const FloatFormat& fmt, const T& value, ostream& os)
870 os << dataTypeNameOf<T>() << "(";
872 for (int ndx = 0; ndx < T::SIZE; ++ndx)
877 printValue16<Element>(fmt, value[ndx], os);
883 static void doPrintValue32 (const FloatFormat& fmt, const T& value, ostream& os)
885 os << dataTypeNameOf<T>() << "(";
887 for (int ndx = 0; ndx < T::SIZE; ++ndx)
892 printValue32<Element>(fmt, value[ndx], os);
898 static void doPrintValue64 (const FloatFormat& fmt, const T& value, ostream& os)
900 os << dataTypeNameOf<T>() << "(";
902 for (int ndx = 0; ndx < T::SIZE; ++ndx)
907 printValue64<Element>(fmt, value[ndx], os);
913 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
917 for (int ndx = 0; ndx < T::SIZE; ++ndx)
918 ret[ndx] = convert<Element>(fmt, value[ndx]);
923 static IVal doRound (const FloatFormat& fmt, T value)
927 for (int ndx = 0; ndx < T::SIZE; ++ndx)
928 ret[ndx] = round(fmt, value[ndx]);
934 template <typename T, int Size>
935 struct Traits<Vector<T, Size> > :
936 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
940 template <typename T, int Rows, int Cols>
941 struct Traits<Matrix<T, Rows, Cols> > :
942 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
946 //! Void traits. These are just dummies, but technically valid: a Void is a
947 //! unit type with a single possible value.
953 static Void doMakeIVal (const Void& value) { return value; }
954 static Void doUnion (const Void&, const Void&) { return Void(); }
955 static bool doContains (const Void&, Void) { return true; }
956 template <typename U>
957 static bool doContains (const Void&, const Void& value, bool is16Bit, const tcu::Maybe<U>& modularDivisor) { DE_UNREF(value); DE_UNREF(is16Bit); DE_UNREF(modularDivisor); return true; }
958 static Void doRound (const FloatFormat&, const Void& value) { return value; }
959 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
961 static void doPrintValue16 (const FloatFormat&, const Void&, ostream& os)
966 static void doPrintValue32 (const FloatFormat&, const Void&, ostream& os)
971 static void doPrintValue64 (const FloatFormat&, const Void&, ostream& os)
976 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
982 //! This is needed for container-generic operations.
983 //! We want a scalar type T to be its own "one-element vector".
984 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
986 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
987 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
989 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
990 template <typename T> struct ElementOf { typedef typename T::Element Element; };
991 template <> struct ElementOf<float> { typedef void Element; };
992 template <> struct ElementOf<double>{ typedef void Element; };
993 template <> struct ElementOf<bool> { typedef void Element; };
994 template <> struct ElementOf<int> { typedef void Element; };
996 template <typename T>
997 string comparisonMessageInterval(const typename Traits<T>::IVal& val)
1004 string comparisonMessageInterval<int>(const Traits<int>::IVal& val)
1006 return comparisonMessage(static_cast<int>(val.lo()));
1010 string comparisonMessageInterval<float>(const Traits<float>::IVal& val)
1012 return comparisonMessage(static_cast<int>(val.lo()));
1016 string comparisonMessageInterval<tcu::Vector<int, 2> >(const tcu::Vector<tcu::Interval, 2> & val)
1018 tcu::IVec2 result(static_cast<int>(val[0].lo()), static_cast<int>(val[1].lo()));
1019 return comparisonMessage(result);
1023 string comparisonMessageInterval<tcu::Vector<int, 3> >(const tcu::Vector<tcu::Interval, 3> & val)
1025 tcu::IVec3 result(static_cast<int>(val[0].lo()), static_cast<int>(val[1].lo()), static_cast<int>(val[2].lo()));
1026 return comparisonMessage(result);
1030 string comparisonMessageInterval<tcu::Vector<int, 4> >(const tcu::Vector<tcu::Interval, 4> & val)
1032 tcu::IVec4 result(static_cast<int>(val[0].lo()), static_cast<int>(val[1].lo()), static_cast<int>(val[2].lo()), static_cast<int>(val[3].lo()));
1033 return comparisonMessage(result);
1036 /*--------------------------------------------------------------------*//*!
1038 * \name Abstract syntax for expressions and statements.
1040 * We represent GLSL programs as syntax objects: an Expr<T> represents an
1041 * expression whose GLSL type corresponds to the C++ type T, and a Statement
1042 * represents a statement.
1044 * To ease memory management, we use shared pointers to refer to expressions
1045 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
1046 * is a shared pointer to a Statement.
1050 *//*--------------------------------------------------------------------*/
1053 class ExpandContext;
1057 template <typename T> class ExprP;
1058 template <typename T> class Variable;
1059 template <typename T> class VariableP;
1060 template <typename T> class DefaultSampling;
1062 typedef set<const FuncBase*> FuncSet;
1064 template <typename T>
1065 VariableP<T> variable (const string& name);
1066 StatementP compoundStatement (const vector<StatementP>& statements);
1068 /*--------------------------------------------------------------------*//*!
1069 * \brief A variable environment.
1071 * An Environment object maintains the mapping between variables of the
1072 * abstract syntax tree and their values.
1074 * \todo [2014-03-28 lauri] At least run-time type safety.
1076 *//*--------------------------------------------------------------------*/
1080 template<typename T>
1081 void bind (const Variable<T>& variable,
1082 const typename Traits<T>::IVal& value)
1084 deUint8* const data = new deUint8[sizeof(value)];
1086 deMemcpy(data, &value, sizeof(value));
1087 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
1090 template<typename T>
1091 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
1093 deUint8* const data = de::lookup(m_map, variable.getName()).get();
1095 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
1099 map<string, SharedPtr<deUint8> > m_map;
1102 /*--------------------------------------------------------------------*//*!
1103 * \brief Evaluation context.
1105 * The evaluation context contains everything that separates one execution of
1106 * an expression from the next. Currently this means the desired floating
1107 * point precision and the current variable environment.
1109 *//*--------------------------------------------------------------------*/
1112 EvalContext (const FloatFormat& format_,
1113 Precision floatPrecision_,
1117 , floatPrecision (floatPrecision_)
1119 , callDepth (callDepth_) {}
1122 Precision floatPrecision;
1127 /*--------------------------------------------------------------------*//*!
1128 * \brief Simple incremental counter.
1130 * This is used to make sure that different ExpandContexts will not produce
1131 * overlapping temporary names.
1133 *//*--------------------------------------------------------------------*/
1137 Counter (int count = 0) : m_count(count) {}
1138 int operator() (void) { return m_count++; }
1147 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
1148 ExpandContext (const ExpandContext& parent)
1149 : m_symCounter(parent.m_symCounter) {}
1151 template<typename T>
1152 VariableP<T> genSym (const string& baseName)
1154 return variable<T>(baseName + de::toString(m_symCounter()));
1157 void addStatement (const StatementP& stmt)
1159 m_statements.push_back(stmt);
1162 vector<StatementP> getStatements (void) const
1164 return m_statements;
1167 Counter& m_symCounter;
1168 vector<StatementP> m_statements;
1171 /*--------------------------------------------------------------------*//*!
1172 * \brief A statement or declaration.
1174 * Statements have no values. Instead, they are executed for their side
1175 * effects only: the execute() method should modify at least one variable in
1178 * As a bit of a kludge, a Statement object can also represent a declaration:
1179 * when it is evaluated, it can add a variable binding to the environment
1180 * instead of modifying a current one.
1182 *//*--------------------------------------------------------------------*/
1186 virtual ~Statement (void) { }
1187 //! Execute the statement, modifying the environment of `ctx`
1188 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
1189 void print (ostream& os) const { this->doPrint(os); }
1190 //! Add the functions used in this statement to `dst`.
1191 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
1192 void failed (EvalContext& ctx) const { this->doFail(ctx); }
1195 virtual void doPrint (ostream& os) const = 0;
1196 virtual void doExecute (EvalContext& ctx) const = 0;
1197 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1198 virtual void doFail (EvalContext& ctx) const { DE_UNREF(ctx); }
1201 ostream& operator<<(ostream& os, const Statement& stmt)
1207 /*--------------------------------------------------------------------*//*!
1208 * \brief Smart pointer for statements (and declarations)
1210 *//*--------------------------------------------------------------------*/
1211 class StatementP : public SharedPtr<const Statement>
1214 typedef SharedPtr<const Statement> Super;
1216 StatementP (void) {}
1217 explicit StatementP (const Statement* ptr) : Super(ptr) {}
1218 StatementP (const Super& ptr) : Super(ptr) {}
1221 /*--------------------------------------------------------------------*//*!
1224 * A statement that modifies a variable or a declaration that binds a variable.
1226 *//*--------------------------------------------------------------------*/
1227 template <typename T>
1228 class VariableStatement : public Statement
1231 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
1233 : m_variable (variable)
1235 , m_isDeclaration (isDeclaration) {}
1238 void doPrint (ostream& os) const
1240 if (m_isDeclaration)
1241 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
1243 os << m_variable->getName();
1246 os<< *m_value << ";\n";
1249 void doExecute (EvalContext& ctx) const
1251 if (m_isDeclaration)
1252 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
1254 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
1257 void doGetUsedFuncs (FuncSet& dst) const
1259 m_value->getUsedFuncs(dst);
1262 virtual void doFail (EvalContext& ctx) const
1264 if (m_isDeclaration)
1265 ctx.env.bind(*m_variable, m_value->fails(ctx));
1267 ctx.env.lookup(*m_variable) = m_value->fails(ctx);
1270 VariableP<T> m_variable;
1272 bool m_isDeclaration;
1275 template <typename T>
1276 StatementP variableStatement (const VariableP<T>& variable,
1277 const ExprP<T>& value,
1280 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
1283 template <typename T>
1284 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
1286 return variableStatement(variable, definiens, true);
1289 template <typename T>
1290 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
1292 return variableStatement(variable, value, false);
1295 /*--------------------------------------------------------------------*//*!
1296 * \brief A compound statement, i.e. a block.
1298 * A compound statement is executed by executing its constituent statements in
1301 *//*--------------------------------------------------------------------*/
1302 class CompoundStatement : public Statement
1305 CompoundStatement (const vector<StatementP>& statements)
1306 : m_statements (statements) {}
1309 void doPrint (ostream& os) const
1313 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
1314 os << *m_statements[ndx];
1319 void doExecute (EvalContext& ctx) const
1321 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
1322 m_statements[ndx]->execute(ctx);
1325 void doGetUsedFuncs (FuncSet& dst) const
1327 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
1328 m_statements[ndx]->getUsedFuncs(dst);
1331 vector<StatementP> m_statements;
1334 StatementP compoundStatement(const vector<StatementP>& statements)
1336 return StatementP(new CompoundStatement(statements));
1339 //! Common base class for all expressions regardless of their type.
1343 virtual ~ExprBase (void) {}
1344 void printExpr (ostream& os) const { this->doPrintExpr(os); }
1346 //! Output the functions that this expression refers to
1347 void getUsedFuncs (FuncSet& dst) const
1349 this->doGetUsedFuncs(dst);
1353 virtual void doPrintExpr (ostream&) const {}
1354 virtual void doGetUsedFuncs (FuncSet&) const {}
1357 //! Type-specific operations for an expression representing type T.
1358 template <typename T>
1359 class Expr : public ExprBase
1363 typedef typename Traits<T>::IVal IVal;
1365 IVal evaluate (const EvalContext& ctx) const;
1366 IVal fails (const EvalContext& ctx) const { return this->doFails(ctx); }
1369 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
1370 virtual IVal doFails (const EvalContext& ctx) const {return doEvaluate(ctx);}
1373 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
1374 template <typename T>
1375 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
1377 #ifdef GLS_ENABLE_TRACE
1378 static const FloatFormat highpFmt (-126, 127, 23, true,
1382 EvalContext newCtx (ctx.format, ctx.floatPrecision,
1383 ctx.env, ctx.callDepth + 1);
1384 const IVal ret = this->doEvaluate(newCtx);
1386 if (isTypeValid<T>())
1388 std::cerr << string(ctx.callDepth, ' ');
1389 this->printExpr(std::cerr);
1390 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
1394 return this->doEvaluate(ctx);
1398 template <typename T>
1399 class ExprPBase : public SharedPtr<const Expr<T> >
1404 ostream& operator<< (ostream& os, const ExprBase& expr)
1410 /*--------------------------------------------------------------------*//*!
1411 * \brief Shared pointer to an expression of a container type.
1413 * Container types (i.e. vectors and matrices) support the subscription
1414 * operator. This class provides a bit of syntactic sugar to allow us to use
1415 * the C++ subscription operator to create a subscription expression.
1416 *//*--------------------------------------------------------------------*/
1417 template <typename T>
1418 class ContainerExprPBase : public ExprPBase<T>
1421 ExprP<typename T::Element> operator[] (int i) const;
1424 template <typename T>
1425 class ExprP : public ExprPBase<T> {};
1427 // We treat Voids as containers since the unused parameters in generalized
1428 // vector functions are represented as Voids.
1430 class ExprP<Void> : public ContainerExprPBase<Void> {};
1432 template <typename T, int Size>
1433 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
1435 template <typename T, int Rows, int Cols>
1436 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
1438 template <typename T> ExprP<T> exprP (void)
1443 template <typename T>
1444 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
1447 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
1451 template <typename T>
1452 ExprP<T> exprP (const Expr<T>* ptr)
1454 return exprP(SharedPtr<const Expr<T> >(ptr));
1457 /*--------------------------------------------------------------------*//*!
1458 * \brief A shared pointer to a variable expression.
1460 * This is just a narrowing of ExprP for the operations that require a variable
1461 * instead of an arbitrary expression.
1463 *//*--------------------------------------------------------------------*/
1464 template <typename T>
1465 class VariableP : public SharedPtr<const Variable<T> >
1468 typedef SharedPtr<const Variable<T> > Super;
1469 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
1471 VariableP (const Super& ptr) : Super(ptr) {}
1473 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
1476 /*--------------------------------------------------------------------*//*!
1477 * \name Syntactic sugar operators for expressions.
1481 * These operators allow the use of C++ syntax to construct GLSL expressions
1482 * containing operators: e.g. "a+b" creates an addition expression with
1483 * operands a and b, and so on.
1485 *//*--------------------------------------------------------------------*/
1486 ExprP<float> operator+ (const ExprP<float>& arg0,
1487 const ExprP<float>& arg1);
1488 ExprP<deFloat16> operator+ (const ExprP<deFloat16>& arg0,
1489 const ExprP<deFloat16>& arg1);
1490 ExprP<double> operator+ (const ExprP<double>& arg0,
1491 const ExprP<double>& arg1);
1492 template <typename T>
1493 ExprP<T> operator- (const ExprP<T>& arg0);
1494 template <typename T>
1495 ExprP<T> operator- (const ExprP<T>& arg0,
1496 const ExprP<T>& arg1);
1497 template<int Left, int Mid, int Right, typename T>
1498 ExprP<Matrix<T, Left, Right> > operator* (const ExprP<Matrix<T, Left, Mid> >& left,
1499 const ExprP<Matrix<T, Mid, Right> >& right);
1500 ExprP<float> operator* (const ExprP<float>& arg0,
1501 const ExprP<float>& arg1);
1502 ExprP<deFloat16> operator* (const ExprP<deFloat16>& arg0,
1503 const ExprP<deFloat16>& arg1);
1504 ExprP<double> operator* (const ExprP<double>& arg0,
1505 const ExprP<double>& arg1);
1506 template <typename T>
1507 ExprP<T> operator/ (const ExprP<T>& arg0,
1508 const ExprP<T>& arg1);
1509 template<typename T, int Size>
1510 ExprP<Vector<T, Size> > operator- (const ExprP<Vector<T, Size> >& arg0);
1511 template<typename T, int Size>
1512 ExprP<Vector<T, Size> > operator- (const ExprP<Vector<T, Size> >& arg0,
1513 const ExprP<Vector<T, Size> >& arg1);
1514 template<int Size, typename T>
1515 ExprP<Vector<T, Size> > operator* (const ExprP<Vector<T, Size> >& arg0,
1516 const ExprP<T>& arg1);
1517 template<typename T, int Size>
1518 ExprP<Vector<T, Size> > operator* (const ExprP<Vector<T, Size> >& arg0,
1519 const ExprP<Vector<T, Size> >& arg1);
1520 template<int Rows, int Cols, typename T>
1521 ExprP<Vector<T, Rows> > operator* (const ExprP<Vector<T, Cols> >& left,
1522 const ExprP<Matrix<T, Rows, Cols> >& right);
1523 template<int Rows, int Cols, typename T>
1524 ExprP<Vector<T, Cols> > operator* (const ExprP<Matrix<T, Rows, Cols> >& left,
1525 const ExprP<Vector<T, Rows> >& right);
1526 template<int Rows, int Cols, typename T>
1527 ExprP<Matrix<T, Rows, Cols> > operator* (const ExprP<Matrix<T, Rows, Cols> >& left,
1528 const ExprP<T>& right);
1529 template<int Rows, int Cols>
1530 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
1531 const ExprP<Matrix<float, Rows, Cols> >& right);
1532 template<int Rows, int Cols>
1533 ExprP<Matrix<deFloat16, Rows, Cols> > operator+ (const ExprP<Matrix<deFloat16, Rows, Cols> >& left,
1534 const ExprP<Matrix<deFloat16, Rows, Cols> >& right);
1535 template<int Rows, int Cols>
1536 ExprP<Matrix<double, Rows, Cols> > operator+ (const ExprP<Matrix<double, Rows, Cols> >& left,
1537 const ExprP<Matrix<double, Rows, Cols> >& right);
1538 template<typename T, int Rows, int Cols>
1539 ExprP<Matrix<T, Rows, Cols> > operator- (const ExprP<Matrix<T, Rows, Cols> >& mat);
1543 /*--------------------------------------------------------------------*//*!
1544 * \brief Variable expression.
1546 * A variable is evaluated by looking up its range of possible values from an
1548 *//*--------------------------------------------------------------------*/
1549 template <typename T>
1550 class Variable : public Expr<T>
1553 typedef typename Expr<T>::IVal IVal;
1555 Variable (const string& name) : m_name (name) {}
1556 string getName (void) const { return m_name; }
1559 void doPrintExpr (ostream& os) const { os << m_name; }
1560 IVal doEvaluate (const EvalContext& ctx) const
1562 return ctx.env.lookup<T>(*this);
1569 template <typename T>
1570 VariableP<T> variable (const string& name)
1572 return VariableP<T>(new Variable<T>(name));
1575 template <typename T>
1576 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1578 VariableP<T> var = ctx.genSym<T>(name);
1579 ctx.addStatement(variableDeclaration(var, expr));
1583 /*--------------------------------------------------------------------*//*!
1584 * \brief Constant expression.
1586 * A constant is evaluated by rounding it to a set of possible values allowed
1587 * by the current floating point precision.
1588 *//*--------------------------------------------------------------------*/
1589 template <typename T>
1590 class Constant : public Expr<T>
1593 typedef typename Expr<T>::IVal IVal;
1595 Constant (const T& value) : m_value(value) {}
1598 void doPrintExpr (ostream& os) const { os << m_value; }
1599 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1605 template <typename T>
1606 ExprP<T> constant (const T& value)
1608 return exprP(new Constant<T>(value));
1611 //! Return a reference to a singleton void constant.
1612 const ExprP<Void>& voidP (void)
1614 static const ExprP<Void> singleton = constant(Void());
1619 /*--------------------------------------------------------------------*//*!
1620 * \brief Four-element tuple.
1622 * This is used for various things where we need one thing for each possible
1623 * function parameter. Currently the maximum supported number of parameters is
1625 *//*--------------------------------------------------------------------*/
1626 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1629 explicit Tuple4 (const T0 e0 = T0(),
1646 /*--------------------------------------------------------------------*//*!
1647 * \brief Function signature.
1649 * This is a purely compile-time structure used to bundle all types in a
1650 * function signature together. This makes passing the signature around in
1651 * templates easier, since we only need to take and pass a single Sig instead
1652 * of a bunch of parameter types and a return type.
1654 *//*--------------------------------------------------------------------*/
1655 template <typename R,
1656 typename P0 = Void, typename P1 = Void,
1657 typename P2 = Void, typename P3 = Void>
1665 typedef typename Traits<Ret>::IVal IRet;
1666 typedef typename Traits<Arg0>::IVal IArg0;
1667 typedef typename Traits<Arg1>::IVal IArg1;
1668 typedef typename Traits<Arg2>::IVal IArg2;
1669 typedef typename Traits<Arg3>::IVal IArg3;
1671 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1672 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1673 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1676 typedef vector<const ExprBase*> BaseArgExprs;
1678 /*--------------------------------------------------------------------*//*!
1679 * \brief Type-independent operations for function objects.
1681 *//*--------------------------------------------------------------------*/
1685 virtual ~FuncBase (void) {}
1686 virtual string getName (void) const = 0;
1687 //! Name of extension that this function requires, or empty.
1688 virtual string getRequiredExtension (void) const { return ""; }
1689 virtual Interval getInputRange (const bool is16bit) const {DE_UNREF(is16bit); return Interval(true, -TCU_INFINITY, TCU_INFINITY); }
1690 virtual void print (ostream&,
1691 const BaseArgExprs&) const = 0;
1692 //! Index of output parameter, or -1 if none of the parameters is output.
1693 virtual int getOutParamIndex (void) const { return -1; }
1695 virtual SpirVCaseT getSpirvCase (void) const { return SPIRV_CASETYPE_NONE; }
1697 void printDefinition (ostream& os) const
1699 doPrintDefinition(os);
1702 void getUsedFuncs (FuncSet& dst) const
1704 this->doGetUsedFuncs(dst);
1708 virtual void doPrintDefinition (ostream& os) const = 0;
1709 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1712 typedef Tuple4<string, string, string, string> ParamNames;
1714 /*--------------------------------------------------------------------*//*!
1715 * \brief Function objects.
1717 * Each Func object represents a GLSL function. It can be applied to interval
1718 * arguments, and it returns the an interval that is a conservative
1719 * approximation of the image of the GLSL function over the argument
1720 * intervals. That is, it is given a set of possible arguments and it returns
1721 * the set of possible values.
1723 *//*--------------------------------------------------------------------*/
1724 template <typename Sig_>
1725 class Func : public FuncBase
1729 typedef typename Sig::Ret Ret;
1730 typedef typename Sig::Arg0 Arg0;
1731 typedef typename Sig::Arg1 Arg1;
1732 typedef typename Sig::Arg2 Arg2;
1733 typedef typename Sig::Arg3 Arg3;
1734 typedef typename Sig::IRet IRet;
1735 typedef typename Sig::IArg0 IArg0;
1736 typedef typename Sig::IArg1 IArg1;
1737 typedef typename Sig::IArg2 IArg2;
1738 typedef typename Sig::IArg3 IArg3;
1739 typedef typename Sig::Args Args;
1740 typedef typename Sig::IArgs IArgs;
1741 typedef typename Sig::ArgExprs ArgExprs;
1743 void print (ostream& os,
1744 const BaseArgExprs& args) const
1746 this->doPrint(os, args);
1749 IRet apply (const EvalContext& ctx,
1750 const IArg0& arg0 = IArg0(),
1751 const IArg1& arg1 = IArg1(),
1752 const IArg2& arg2 = IArg2(),
1753 const IArg3& arg3 = IArg3()) const
1755 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1758 IRet fail (const EvalContext& ctx,
1759 const IArg0& arg0 = IArg0(),
1760 const IArg1& arg1 = IArg1(),
1761 const IArg2& arg2 = IArg2(),
1762 const IArg3& arg3 = IArg3()) const
1764 return this->doFail(ctx, IArgs(arg0, arg1, arg2, arg3));
1766 IRet applyArgs (const EvalContext& ctx,
1767 const IArgs& args) const
1769 return this->doApply(ctx, args);
1771 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1772 const ExprP<Arg1>& arg1 = voidP(),
1773 const ExprP<Arg2>& arg2 = voidP(),
1774 const ExprP<Arg3>& arg3 = voidP()) const;
1776 const ParamNames& getParamNames (void) const
1778 return this->doGetParamNames();
1782 virtual IRet doApply (const EvalContext&,
1783 const IArgs&) const = 0;
1784 virtual IRet doFail (const EvalContext& ctx,
1785 const IArgs& args) const
1787 return this->doApply(ctx, args);
1789 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1791 os << getName() << "(";
1793 if (isTypeValid<Arg0>())
1796 if (isTypeValid<Arg1>())
1797 os << ", " << *args[1];
1799 if (isTypeValid<Arg2>())
1800 os << ", " << *args[2];
1802 if (isTypeValid<Arg3>())
1803 os << ", " << *args[3];
1808 virtual const ParamNames& doGetParamNames (void) const
1810 static ParamNames names ("a", "b", "c", "d");
1815 template <typename Sig>
1816 class Apply : public Expr<typename Sig::Ret>
1819 typedef typename Sig::Ret Ret;
1820 typedef typename Sig::Arg0 Arg0;
1821 typedef typename Sig::Arg1 Arg1;
1822 typedef typename Sig::Arg2 Arg2;
1823 typedef typename Sig::Arg3 Arg3;
1824 typedef typename Expr<Ret>::Val Val;
1825 typedef typename Expr<Ret>::IVal IVal;
1826 typedef Func<Sig> ApplyFunc;
1827 typedef typename ApplyFunc::ArgExprs ArgExprs;
1829 Apply (const ApplyFunc& func,
1830 const ExprP<Arg0>& arg0 = voidP(),
1831 const ExprP<Arg1>& arg1 = voidP(),
1832 const ExprP<Arg2>& arg2 = voidP(),
1833 const ExprP<Arg3>& arg3 = voidP())
1835 m_args (arg0, arg1, arg2, arg3) {}
1837 Apply (const ApplyFunc& func,
1838 const ArgExprs& args)
1842 void doPrintExpr (ostream& os) const
1845 args.push_back(m_args.a.get());
1846 args.push_back(m_args.b.get());
1847 args.push_back(m_args.c.get());
1848 args.push_back(m_args.d.get());
1849 m_func.print(os, args);
1852 IVal doEvaluate (const EvalContext& ctx) const
1854 return m_func.apply(ctx,
1855 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1856 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1859 void doGetUsedFuncs (FuncSet& dst) const
1861 m_func.getUsedFuncs(dst);
1862 m_args.a->getUsedFuncs(dst);
1863 m_args.b->getUsedFuncs(dst);
1864 m_args.c->getUsedFuncs(dst);
1865 m_args.d->getUsedFuncs(dst);
1868 const ApplyFunc& m_func;
1872 template<typename T>
1873 class Alternatives : public Func<Signature<T, T, T> >
1876 typedef typename Alternatives::Sig Sig;
1879 typedef typename Alternatives::IRet IRet;
1880 typedef typename Alternatives::IArgs IArgs;
1882 virtual string getName (void) const { return "alternatives"; }
1883 virtual void doPrintDefinition (std::ostream&) const {}
1884 void doGetUsedFuncs (FuncSet&) const {}
1886 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1888 return unionIVal<T>(args.a, args.b);
1891 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1893 os << "{" << *args[0] << " | " << *args[1] << "}";
1897 template <typename Sig>
1898 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1899 const typename Func<Sig>::ArgExprs& args)
1901 return exprP(new Apply<Sig>(func, args));
1904 template <typename Sig>
1905 ExprP<typename Sig::Ret> createApply (
1906 const Func<Sig>& func,
1907 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1908 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1909 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1910 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1912 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1915 template <typename Sig>
1916 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1917 const ExprP<typename Sig::Arg1>& arg1,
1918 const ExprP<typename Sig::Arg2>& arg2,
1919 const ExprP<typename Sig::Arg3>& arg3) const
1921 return createApply(*this, arg0, arg1, arg2, arg3);
1924 template <typename F>
1925 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1926 const ExprP<typename F::Arg1>& arg1 = voidP(),
1927 const ExprP<typename F::Arg2>& arg2 = voidP(),
1928 const ExprP<typename F::Arg3>& arg3 = voidP())
1930 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1933 template <typename F>
1934 typename F::IRet call (const EvalContext& ctx,
1935 const typename F::IArg0& arg0 = Void(),
1936 const typename F::IArg1& arg1 = Void(),
1937 const typename F::IArg2& arg2 = Void(),
1938 const typename F::IArg3& arg3 = Void())
1940 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1943 template <typename T>
1944 ExprP<T> alternatives (const ExprP<T>& arg0,
1945 const ExprP<T>& arg1)
1947 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1950 template <typename Sig>
1951 class ApplyVar : public Apply<Sig>
1954 typedef typename Sig::Ret Ret;
1955 typedef typename Sig::Arg0 Arg0;
1956 typedef typename Sig::Arg1 Arg1;
1957 typedef typename Sig::Arg2 Arg2;
1958 typedef typename Sig::Arg3 Arg3;
1959 typedef typename Expr<Ret>::Val Val;
1960 typedef typename Expr<Ret>::IVal IVal;
1961 typedef Func<Sig> ApplyFunc;
1962 typedef typename ApplyFunc::ArgExprs ArgExprs;
1964 ApplyVar (const ApplyFunc& func,
1965 const VariableP<Arg0>& arg0,
1966 const VariableP<Arg1>& arg1,
1967 const VariableP<Arg2>& arg2,
1968 const VariableP<Arg3>& arg3)
1969 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1971 IVal doEvaluate (const EvalContext& ctx) const
1973 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1974 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1975 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1976 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1977 return this->m_func.apply(ctx,
1978 ctx.env.lookup(var0), ctx.env.lookup(var1),
1979 ctx.env.lookup(var2), ctx.env.lookup(var3));
1982 IVal doFails (const EvalContext& ctx) const
1984 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1985 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1986 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1987 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1988 return this->m_func.fail(ctx,
1989 ctx.env.lookup(var0), ctx.env.lookup(var1),
1990 ctx.env.lookup(var2), ctx.env.lookup(var3));
1994 template <typename Sig>
1995 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1996 const VariableP<typename Sig::Arg0>& arg0,
1997 const VariableP<typename Sig::Arg1>& arg1,
1998 const VariableP<typename Sig::Arg2>& arg2,
1999 const VariableP<typename Sig::Arg3>& arg3)
2001 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
2004 template <typename Sig_>
2005 class DerivedFunc : public Func<Sig_>
2008 typedef typename DerivedFunc::ArgExprs ArgExprs;
2009 typedef typename DerivedFunc::IRet IRet;
2010 typedef typename DerivedFunc::IArgs IArgs;
2011 typedef typename DerivedFunc::Ret Ret;
2012 typedef typename DerivedFunc::Arg0 Arg0;
2013 typedef typename DerivedFunc::Arg1 Arg1;
2014 typedef typename DerivedFunc::Arg2 Arg2;
2015 typedef typename DerivedFunc::Arg3 Arg3;
2016 typedef typename DerivedFunc::IArg0 IArg0;
2017 typedef typename DerivedFunc::IArg1 IArg1;
2018 typedef typename DerivedFunc::IArg2 IArg2;
2019 typedef typename DerivedFunc::IArg3 IArg3;
2022 void doPrintDefinition (ostream& os) const
2024 const ParamNames& paramNames = this->getParamNames();
2028 os << dataTypeNameOf<Ret>() << " " << this->getName()
2030 if (isTypeValid<Arg0>())
2031 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
2032 if (isTypeValid<Arg1>())
2033 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
2034 if (isTypeValid<Arg2>())
2035 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
2036 if (isTypeValid<Arg3>())
2037 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
2040 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
2042 os << "return " << *m_ret << ";\n";
2046 IRet doApply (const EvalContext& ctx,
2047 const IArgs& args) const
2050 IArgs& mutArgs = const_cast<IArgs&>(args);
2055 funEnv.bind(*m_var0, args.a);
2056 funEnv.bind(*m_var1, args.b);
2057 funEnv.bind(*m_var2, args.c);
2058 funEnv.bind(*m_var3, args.d);
2061 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
2063 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
2064 m_body[ndx]->execute(funCtx);
2066 ret = m_ret->evaluate(funCtx);
2069 // \todo [lauri] Store references instead of values in environment
2070 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
2071 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
2072 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
2073 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
2078 void doGetUsedFuncs (FuncSet& dst) const
2081 if (dst.insert(this).second)
2083 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
2084 m_body[ndx]->getUsedFuncs(dst);
2085 m_ret->getUsedFuncs(dst);
2089 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
2091 // These are transparently initialized when first needed. They cannot be
2092 // initialized in the constructor because they depend on the doExpand
2093 // method of the subclass.
2095 mutable VariableP<Arg0> m_var0;
2096 mutable VariableP<Arg1> m_var1;
2097 mutable VariableP<Arg2> m_var2;
2098 mutable VariableP<Arg3> m_var3;
2099 mutable vector<StatementP> m_body;
2100 mutable ExprP<Ret> m_ret;
2104 void initialize (void) const
2108 const ParamNames& paramNames = this->getParamNames();
2110 ExpandContext ctx (symCounter);
2113 args.a = m_var0 = variable<Arg0>(paramNames.a);
2114 args.b = m_var1 = variable<Arg1>(paramNames.b);
2115 args.c = m_var2 = variable<Arg2>(paramNames.c);
2116 args.d = m_var3 = variable<Arg3>(paramNames.d);
2118 m_ret = this->doExpand(ctx, args);
2119 m_body = ctx.getStatements();
2124 template <typename Sig>
2125 class PrimitiveFunc : public Func<Sig>
2128 typedef typename PrimitiveFunc::Ret Ret;
2129 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
2132 void doPrintDefinition (ostream&) const {}
2133 void doGetUsedFuncs (FuncSet&) const {}
2136 template <typename T>
2137 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
2140 typedef typename Cond::IArgs IArgs;
2141 typedef typename Cond::IRet IRet;
2143 string getName (void) const
2150 void doPrint (ostream& os, const BaseArgExprs& args) const
2152 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
2155 IRet doApply (const EvalContext&, const IArgs& iargs)const
2159 if (iargs.a.contains(true))
2160 ret = unionIVal<T>(ret, iargs.b);
2162 if (iargs.a.contains(false))
2163 ret = unionIVal<T>(ret, iargs.c);
2169 template <typename T>
2170 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
2173 typedef typename CompareOperator::IArgs IArgs;
2174 typedef typename CompareOperator::IArg0 IArg0;
2175 typedef typename CompareOperator::IArg1 IArg1;
2176 typedef typename CompareOperator::IRet IRet;
2179 void doPrint (ostream& os, const BaseArgExprs& args) const
2181 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
2184 Interval doApply (const EvalContext&, const IArgs& iargs) const
2186 const IArg0& arg0 = iargs.a;
2187 const IArg1& arg1 = iargs.b;
2190 if (canSucceed(arg0, arg1))
2192 if (canFail(arg0, arg1))
2198 virtual string getSymbol (void) const = 0;
2199 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
2200 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
2203 template <typename T>
2204 class LessThan : public CompareOperator<T>
2207 string getName (void) const { return "lessThan"; }
2210 string getSymbol (void) const { return "<"; }
2212 bool canSucceed (const Interval& a, const Interval& b) const
2214 return (a.lo() < b.hi());
2217 bool canFail (const Interval& a, const Interval& b) const
2219 return !(a.hi() < b.lo());
2223 template <typename T>
2224 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
2226 return app<LessThan<T> >(a, b);
2229 template <typename T>
2230 ExprP<T> cond (const ExprP<bool>& test,
2231 const ExprP<T>& consequent,
2232 const ExprP<T>& alternative)
2234 return app<Cond<T> >(test, consequent, alternative);
2237 /*--------------------------------------------------------------------*//*!
2241 *//*--------------------------------------------------------------------*/
2242 //Proper parameters for template T
2243 // Signature<float, float> 32bit tests
2244 // Signature<float, deFloat16> 16bit tests
2245 // Signature<double, double> 64bit tests
2247 class FloatFunc1 : public PrimitiveFunc<T>
2250 Interval doApply (const EvalContext& ctx, const typename Signature<typename T::Ret, typename T::Arg0>::IArgs& iargs) const
2252 return this->applyMonotone(ctx, iargs.a);
2255 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
2259 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
2260 TCU_SET_INTERVAL(val, point,
2261 point = this->applyPoint(ctx, arg0)));
2263 ret |= innerExtrema(ctx, iarg0);
2264 ret &= (this->getCodomain(ctx) | TCU_NAN);
2266 return ctx.format.convert(ret);
2269 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
2271 return Interval(); // empty interval, i.e. no extrema
2274 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
2276 const double exact = this->applyExact(arg0);
2277 const double prec = this->precision(ctx, exact, arg0);
2279 return exact + Interval(-prec, prec);
2282 virtual double applyExact (double) const
2284 TCU_THROW(InternalError, "Cannot apply");
2287 virtual Interval getCodomain (const EvalContext&) const
2289 return Interval::unbounded(true);
2292 virtual double precision (const EvalContext& ctx, double, double) const = 0;
2295 /*Proper parameters for template T
2296 Signature<double, double> 64bit tests
2297 Signature<float, float> 32bit tests
2298 Signature<float, deFloat16> 16bit tests*/
2300 class CFloatFunc1 : public FloatFunc1<T>
2303 CFloatFunc1 (const string& name, tcu::DoubleFunc1& func)
2304 : m_name(name), m_func(func) {}
2306 string getName (void) const { return m_name; }
2309 double applyExact (double x) const { return m_func(x); }
2311 const string m_name;
2312 tcu::DoubleFunc1& m_func;
2315 //<Signature<float, deFloat16, deFloat16> >
2316 //<Signature<float, float, float> >
2317 //<Signature<double, double, double> >
2319 class FloatFunc2 : public PrimitiveFunc<T>
2322 Interval doApply (const EvalContext& ctx, const typename Signature<typename T::Ret, typename T::Arg0, typename T::Arg1>::IArgs& iargs) const
2324 return this->applyMonotone(ctx, iargs.a, iargs.b);
2327 Interval applyMonotone (const EvalContext& ctx,
2329 const Interval& yi) const
2333 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
2334 TCU_SET_INTERVAL(ret, point,
2335 point = this->applyPoint(ctx, x, y)));
2336 reti |= innerExtrema(ctx, xi, yi);
2337 reti &= (this->getCodomain(ctx) | TCU_NAN);
2339 return ctx.format.convert(reti);
2342 virtual Interval innerExtrema (const EvalContext&,
2344 const Interval&) const
2346 return Interval(); // empty interval, i.e. no extrema
2349 virtual Interval applyPoint (const EvalContext& ctx,
2353 const double exact = this->applyExact(x, y);
2354 const double prec = this->precision(ctx, exact, x, y);
2356 return exact + Interval(-prec, prec);
2359 virtual double applyExact (double, double) const
2361 TCU_THROW(InternalError, "Cannot apply");
2364 virtual Interval getCodomain (const EvalContext&) const
2366 return Interval::unbounded(true);
2369 virtual double precision (const EvalContext& ctx,
2372 double y) const = 0;
2376 class CFloatFunc2 : public FloatFunc2<T>
2379 CFloatFunc2 (const string& name,
2380 tcu::DoubleFunc2& func)
2386 string getName (void) const { return m_name; }
2389 double applyExact (double x, double y) const { return m_func(x, y); }
2391 const string m_name;
2392 tcu::DoubleFunc2& m_func;
2396 class InfixOperator : public FloatFunc2<T>
2399 virtual string getSymbol (void) const = 0;
2401 void doPrint (ostream& os, const BaseArgExprs& args) const
2403 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
2406 Interval applyPoint (const EvalContext& ctx,
2410 const double exact = this->applyExact(x, y);
2412 // Allow either representable number on both sides of the exact value,
2413 // but require exactly representable values to be preserved.
2414 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
2417 double precision (const EvalContext&, double, double, double) const
2423 class InfixOperator16Bit : public FloatFunc2 <Signature<float, deFloat16, deFloat16> >
2426 virtual string getSymbol (void) const = 0;
2428 void doPrint (ostream& os, const BaseArgExprs& args) const
2430 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
2433 Interval applyPoint (const EvalContext& ctx,
2437 const double exact = this->applyExact(x, y);
2439 // Allow either representable number on both sides of the exact value,
2440 // but require exactly representable values to be preserved.
2441 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
2444 double precision (const EvalContext&, double, double, double) const
2451 class FloatFunc3 : public PrimitiveFunc<T>
2454 Interval doApply (const EvalContext& ctx, const typename Signature<typename T::Ret, typename T::Arg0, typename T::Arg1, typename T::Arg2>::IArgs& iargs) const
2456 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
2459 Interval applyMonotone (const EvalContext& ctx,
2462 const Interval& zi) const
2465 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
2466 TCU_SET_INTERVAL(ret, point,
2467 point = this->applyPoint(ctx, x, y, z)));
2468 return ctx.format.convert(reti);
2471 virtual Interval applyPoint (const EvalContext& ctx,
2476 const double exact = this->applyExact(x, y, z);
2477 const double prec = this->precision(ctx, exact, x, y, z);
2478 return exact + Interval(-prec, prec);
2481 virtual double applyExact (double, double, double) const
2483 TCU_THROW(InternalError, "Cannot apply");
2486 virtual double precision (const EvalContext& ctx,
2490 double z) const = 0;
2493 // We define syntactic sugar functions for expression constructors. Since
2494 // these have the same names as ordinary mathematical operations (sin, log
2495 // etc.), it's better to give them a dedicated namespace.
2499 using namespace tcu;
2502 class Comparison : public InfixOperator < T >
2505 string getName (void) const { return "comparison"; }
2506 string getSymbol (void) const { return ""; }
2508 SpirVCaseT getSpirvCase () const { return SPIRV_CASETYPE_COMPARE; }
2510 Interval doApply (const EvalContext& ctx,
2511 const typename Comparison<T>::IArgs& iargs) const
2514 if (iargs.a.hasNaN() || iargs.b.hasNaN())
2516 return TCU_NAN; // one of the floats is NaN: block analysis
2519 int operationFlag = 1;
2521 const double a = iargs.a.midpoint();
2522 const double b = iargs.b.midpoint();
2524 for (int i = 0; i<2; ++i)
2527 result += operationFlag;
2528 operationFlag = operationFlag << 1;
2531 result += operationFlag;
2532 operationFlag = operationFlag << 1;
2535 result += operationFlag;
2536 operationFlag = operationFlag << 1;
2539 result += operationFlag;
2540 operationFlag = operationFlag << 1;
2543 result += operationFlag;
2544 operationFlag = operationFlag << 1;
2551 class Add : public InfixOperator < T >
2554 string getName (void) const { return "add"; }
2555 string getSymbol (void) const { return "+"; }
2557 Interval doApply (const EvalContext& ctx,
2558 const typename Signature<typename T::Ret, typename T::Arg0, typename T::Arg1>::IArgs& iargs) const
2560 // Fast-path for common case
2561 if (iargs.a.isOrdinary(ctx.format.getMaxValue()) && iargs.b.isOrdinary(ctx.format.getMaxValue()))
2564 TCU_SET_INTERVAL_BOUNDS(ret, sum,
2565 sum = iargs.a.lo() + iargs.b.lo(),
2566 sum = iargs.a.hi() + iargs.b.hi());
2567 return ctx.format.convert(ctx.format.roundOut(ret, true));
2569 return this->applyMonotone(ctx, iargs.a, iargs.b);
2573 double applyExact (double x, double y) const { return x + y; }
2577 class Mul : public InfixOperator<T>
2580 string getName (void) const { return "mul"; }
2581 string getSymbol (void) const { return "*"; }
2583 Interval doApply (const EvalContext& ctx, const typename Signature<typename T::Ret, typename T::Arg0, typename T::Arg1>::IArgs& iargs) const
2585 Interval a = iargs.a;
2586 Interval b = iargs.b;
2588 // Fast-path for common case
2589 if (a.isOrdinary(ctx.format.getMaxValue()) && b.isOrdinary(ctx.format.getMaxValue()))
2597 if (a.lo() >= 0 && b.lo() >= 0)
2599 TCU_SET_INTERVAL_BOUNDS(ret, prod,
2600 prod = a.lo() * b.lo(),
2601 prod = a.hi() * b.hi());
2602 return ctx.format.convert(ctx.format.roundOut(ret, true));
2604 if (a.lo() >= 0 && b.hi() <= 0)
2606 TCU_SET_INTERVAL_BOUNDS(ret, prod,
2607 prod = a.hi() * b.lo(),
2608 prod = a.lo() * b.hi());
2609 return ctx.format.convert(ctx.format.roundOut(ret, true));
2612 return this->applyMonotone(ctx, iargs.a, iargs.b);
2616 double applyExact (double x, double y) const { return x * y; }
2618 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
2620 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
2621 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
2622 return Interval(TCU_NAN);
2629 class Sub : public InfixOperator <T>
2632 string getName (void) const { return "sub"; }
2633 string getSymbol (void) const { return "-"; }
2635 Interval doApply (const EvalContext& ctx, const typename Signature<typename T::Ret, typename T::Arg0, typename T::Arg1>::IArgs& iargs) const
2637 // Fast-path for common case
2638 if (iargs.a.isOrdinary(ctx.format.getMaxValue()) && iargs.b.isOrdinary(ctx.format.getMaxValue()))
2642 TCU_SET_INTERVAL_BOUNDS(ret, diff,
2643 diff = iargs.a.lo() - iargs.b.hi(),
2644 diff = iargs.a.hi() - iargs.b.lo());
2645 return ctx.format.convert(ctx.format.roundOut(ret, true));
2650 return this->applyMonotone(ctx, iargs.a, iargs.b);
2655 double applyExact (double x, double y) const { return x - y; }
2659 class Negate : public FloatFunc1<T>
2662 string getName (void) const { return "_negate"; }
2663 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
2666 double precision (const EvalContext&, double, double) const { return 0.0; }
2667 double applyExact (double x) const { return -x; }
2671 class Div : public InfixOperator<T>
2674 string getName (void) const { return "div"; }
2677 string getSymbol (void) const { return "/"; }
2679 Interval innerExtrema (const EvalContext&,
2680 const Interval& nom,
2681 const Interval& den) const
2685 if (den.contains(0.0))
2687 if (nom.contains(0.0))
2690 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2691 ret |= Interval::unbounded();
2697 double applyExact (double x, double y) const { return x / y; }
2699 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2701 Interval ret = FloatFunc2<T>::applyPoint(ctx, x, y);
2703 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2705 const Interval dst = ctx.format.convert(ret);
2706 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2707 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2713 double precision (const EvalContext& ctx, double ret, double, double den) const
2715 const FloatFormat& fmt = ctx.format;
2717 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2718 // For now, we assume that division's precision is 2.5 ULP when the value is within
2719 // [2^MINEXP, 2^MAXEXP-1]
2722 return 0.0; // Result must be exactly inf
2723 else if (de::inBounds(deAbs(den),
2724 deLdExp(1.0, fmt.getMinExp()),
2725 deLdExp(1.0, fmt.getMaxExp() - 1)))
2726 return fmt.ulp(ret, 2.5);
2728 return TCU_INFINITY; // Can be any number, but must be a number.
2733 class InverseSqrt : public FloatFunc1 <T>
2736 string getName (void) const { return "inversesqrt"; }
2739 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2741 double precision (const EvalContext& ctx, double ret, double x) const
2743 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2746 Interval getCodomain (const EvalContext&) const
2748 return Interval(0.0, TCU_INFINITY);
2753 class ExpFunc : public CFloatFunc1<T>
2756 ExpFunc (const string& name, DoubleFunc1& func)
2757 : CFloatFunc1<T> (name, func)
2760 double precision (const EvalContext& ctx, double ret, double x) const;
2761 Interval getCodomain (const EvalContext&) const
2763 return Interval(0.0, TCU_INFINITY);
2768 double ExpFunc <Signature<float, float> >::precision (const EvalContext& ctx, double ret, double x) const
2770 switch (ctx.floatPrecision)
2772 case glu::PRECISION_HIGHP:
2773 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2774 case glu::PRECISION_MEDIUMP:
2775 case glu::PRECISION_LAST:
2776 return ctx.format.ulp(ret, 1.0 + 2.0 * deAbs(x));
2778 DE_FATAL("Impossible");
2785 double ExpFunc <Signature<deFloat16, deFloat16> >::precision(const EvalContext& ctx, double ret, double x) const
2787 return ctx.format.ulp(ret, 1.0 + 2.0 * deAbs(x));
2791 double ExpFunc <Signature<double, double> >::precision(const EvalContext& ctx, double ret, double x) const
2793 return ctx.format.ulp(ret, 1.0 + 2.0 * deAbs(x));
2797 class Exp2 : public ExpFunc<T> { public: Exp2 (void) : ExpFunc<T>("exp2", deExp2) {} };
2799 class Exp : public ExpFunc<T> { public: Exp (void) : ExpFunc<T>("exp", deExp) {} };
2801 template <typename T>
2802 ExprP<T> exp2 (const ExprP<T>& x) { return app<Exp2< Signature<T, T> > >(x); }
2803 template <typename T>
2804 ExprP<T> exp (const ExprP<T>& x) { return app<Exp< Signature<T, T> > >(x); }
2807 class LogFunc : public CFloatFunc1<T>
2810 LogFunc (const string& name, DoubleFunc1& func)
2811 : CFloatFunc1<T>(name, func) {}
2814 double precision (const EvalContext& ctx, double ret, double x) const;
2818 double LogFunc<Signature<float, float> >::precision(const EvalContext& ctx, double ret, double x) const
2823 switch (ctx.floatPrecision)
2825 case glu::PRECISION_HIGHP:
2826 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2827 case glu::PRECISION_MEDIUMP:
2828 case glu::PRECISION_LAST:
2829 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 3.0);
2831 DE_FATAL("Impossible");
2838 double LogFunc<Signature<deFloat16, deFloat16> >::precision(const EvalContext& ctx, double ret, double x) const
2842 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 3.0);
2845 // Spec: "The precision of double-precision instructions is at least that of single precision."
2846 // Lets pick float high precision as a reference.
2848 double LogFunc<Signature<double, double> >::precision(const EvalContext& ctx, double ret, double x) const
2852 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2856 class Log2 : public LogFunc<T> { public: Log2 (void) : LogFunc<T>("log2", deLog2) {} };
2858 class Log : public LogFunc<T> { public: Log (void) : LogFunc<T>("log", deLog) {} };
2860 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2< Signature<float, float> > >(x); }
2861 ExprP<float> log (const ExprP<float>& x) { return app<Log< Signature<float, float> > >(x); }
2863 ExprP<deFloat16> log2 (const ExprP<deFloat16>& x) { return app<Log2< Signature<deFloat16, deFloat16> > >(x); }
2864 ExprP<deFloat16> log (const ExprP<deFloat16>& x) { return app<Log< Signature<deFloat16, deFloat16> > >(x); }
2866 ExprP<double> log2 (const ExprP<double>& x) { return app<Log2< Signature<double, double> > >(x); }
2867 ExprP<double> log (const ExprP<double>& x) { return app<Log< Signature<double, double> > >(x); }
2869 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2870 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2872 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2873 class CLASS : public DerivedFunc<Signature<TRET, T0> > /* NOLINT(CLASS) */ \
2876 string getName (void) const { return #NAME; } \
2879 ExprP<TRET> doExpand (ExpandContext&, \
2880 const CLASS::ArgExprs& args_) const \
2882 const ExprP<T0>& ARG0 = args_.a; \
2886 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2888 #define DEFINE_DERIVED_DOUBLE1(CLASS, NAME, ARG0, EXPANSION) \
2889 DEFINE_DERIVED1(CLASS, double, NAME, double, ARG0, EXPANSION)
2891 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2892 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2895 #define DEFINE_DERIVED1_INPUTRANGE(CLASS, TRET, NAME, T0, ARG0, EXPANSION, INTERVAL) \
2896 class CLASS : public DerivedFunc<Signature<TRET, T0> > /* NOLINT(CLASS) */ \
2899 string getName (void) const { return #NAME; } \
2902 ExprP<TRET> doExpand (ExpandContext&, \
2903 const CLASS::ArgExprs& args_) const \
2905 const ExprP<T0>& ARG0 = args_.a; \
2908 Interval getInputRange (const bool /*is16bit*/) const \
2913 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2915 #define DEFINE_DERIVED_FLOAT1_INPUTRANGE(CLASS, NAME, ARG0, EXPANSION, INTERVAL) \
2916 DEFINE_DERIVED1_INPUTRANGE(CLASS, float, NAME, float, ARG0, EXPANSION, INTERVAL)
2918 #define DEFINE_DERIVED_DOUBLE1_INPUTRANGE(CLASS, NAME, ARG0, EXPANSION, INTERVAL) \
2919 DEFINE_DERIVED1_INPUTRANGE(CLASS, double, NAME, double, ARG0, EXPANSION, INTERVAL)
2921 #define DEFINE_DERIVED_FLOAT1_16BIT(CLASS, NAME, ARG0, EXPANSION) \
2922 DEFINE_DERIVED1(CLASS, deFloat16, NAME, deFloat16, ARG0, EXPANSION)
2924 #define DEFINE_DERIVED_FLOAT1_INPUTRANGE_16BIT(CLASS, NAME, ARG0, EXPANSION, INTERVAL) \
2925 DEFINE_DERIVED1_INPUTRANGE(CLASS, deFloat16, NAME, deFloat16, ARG0, EXPANSION, INTERVAL)
2927 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2928 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2930 return app<CLASS>(arg0, arg1); \
2933 #define DEFINE_CASED_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION, SPIRVCASE) \
2934 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > /* NOLINT(CLASS) */ \
2937 string getName (void) const { return #NAME; } \
2939 SpirVCaseT getSpirvCase(void) const { return SPIRVCASE; } \
2942 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2944 const ExprP<T0>& Arg0 = args_.a; \
2945 const ExprP<T1>& Arg1 = args_.b; \
2949 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2951 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2952 DEFINE_CASED_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION, SPIRV_CASETYPE_NONE)
2954 #define DEFINE_DERIVED_DOUBLE2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2955 DEFINE_DERIVED2(CLASS, double, NAME, double, Arg0, double, Arg1, EXPANSION)
2957 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2958 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2960 #define DEFINE_DERIVED_FLOAT2_16BIT(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2961 DEFINE_DERIVED2(CLASS, deFloat16, NAME, deFloat16, Arg0, deFloat16, Arg1, EXPANSION)
2963 #define DEFINE_CASED_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION, SPIRVCASE) \
2964 DEFINE_CASED_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION, SPIRVCASE)
2966 #define DEFINE_CASED_DERIVED_FLOAT2_16BIT(CLASS, NAME, Arg0, Arg1, EXPANSION, SPIRVCASE) \
2967 DEFINE_CASED_DERIVED2(CLASS, deFloat16, NAME, deFloat16, Arg0, deFloat16, Arg1, EXPANSION, SPIRVCASE)
2969 #define DEFINE_CASED_DERIVED_DOUBLE2(CLASS, NAME, Arg0, Arg1, EXPANSION, SPIRVCASE) \
2970 DEFINE_CASED_DERIVED2(CLASS, double, NAME, double, Arg0, double, Arg1, EXPANSION, SPIRVCASE)
2972 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2973 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2975 return app<CLASS>(arg0, arg1, arg2); \
2978 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2979 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > /* NOLINT(CLASS) */ \
2982 string getName (void) const { return #NAME; } \
2985 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2987 const ExprP<T0>& ARG0 = args_.a; \
2988 const ExprP<T1>& ARG1 = args_.b; \
2989 const ExprP<T2>& ARG2 = args_.c; \
2993 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2995 #define DEFINE_DERIVED_DOUBLE3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2996 DEFINE_DERIVED3(CLASS, double, NAME, double, ARG0, double, ARG1, double, ARG2, EXPANSION)
2998 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2999 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
3001 #define DEFINE_DERIVED_FLOAT3_16BIT(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
3002 DEFINE_DERIVED3(CLASS, deFloat16, NAME, deFloat16, ARG0, deFloat16, ARG1, deFloat16, ARG2, EXPANSION)
3004 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
3005 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
3006 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
3008 return app<CLASS>(arg0, arg1, arg2, arg3); \
3011 typedef InverseSqrt< Signature<deFloat16, deFloat16> > InverseSqrt16Bit;
3012 typedef InverseSqrt< Signature<float, float> > InverseSqrt32Bit;
3013 typedef InverseSqrt< Signature<double, double> > InverseSqrt64Bit;
3015 DEFINE_DERIVED_FLOAT1(Sqrt32Bit, sqrt, x, constant(1.0f) / app<InverseSqrt32Bit>(x))
3016 DEFINE_DERIVED_FLOAT1_16BIT(Sqrt16Bit, sqrt, x, constant((deFloat16)FLOAT16_1_0) / app<InverseSqrt16Bit>(x))
3017 DEFINE_DERIVED_DOUBLE1(Sqrt64Bit, sqrt, x, constant(1.0) / app<InverseSqrt64Bit>(x))
3018 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2<float>(y * log2(x)))
3019 DEFINE_DERIVED_FLOAT2_16BIT(Pow16, pow, x, y, exp2<deFloat16>(y * log2(x)))
3020 DEFINE_DERIVED_DOUBLE2(Pow64, pow, x, y, exp2<double>(y * log2(x)))
3021 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d)
3022 DEFINE_DERIVED_FLOAT1_16BIT(Radians16, radians, d, (constant((deFloat16)DE_PI_16BIT) / constant((deFloat16)FLOAT16_180_0)) * d)
3023 DEFINE_DERIVED_DOUBLE1(Radians64, radians, d, (constant((double)(DE_PI)) / constant(180.0)) * d)
3024 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r)
3025 DEFINE_DERIVED_FLOAT1_16BIT(Degrees16, degrees, r, (constant((deFloat16)FLOAT16_180_0) / constant((deFloat16)DE_PI_16BIT)) * r)
3026 DEFINE_DERIVED_DOUBLE1(Degrees64, degrees, r, (constant(180.0) / constant((double)(DE_PI))) * r)
3028 /*Proper parameters for template T
3029 Signature<float, float> 32bit tests
3030 Signature<float, deFloat16> 16bit tests*/
3032 class TrigFunc : public CFloatFunc1<T>
3035 TrigFunc (const string& name,
3037 const Interval& loEx,
3038 const Interval& hiEx)
3039 : CFloatFunc1<T> (name, func)
3040 , m_loExtremum (loEx)
3041 , m_hiExtremum (hiEx) {}
3044 Interval innerExtrema (const EvalContext&, const Interval& angle) const
3046 const double lo = angle.lo();
3047 const double hi = angle.hi();
3048 const int loSlope = doGetSlope(lo);
3049 const int hiSlope = doGetSlope(hi);
3051 // Detect the high and low values the function can take between the
3052 // interval endpoints.
3053 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
3055 // The interval is longer than a full cycle, so it must get all possible values.
3056 return m_hiExtremum | m_loExtremum;
3058 else if (loSlope == 1 && hiSlope == -1)
3060 // The slope can change from positive to negative only at the maximum value.
3061 return m_hiExtremum;
3063 else if (loSlope == -1 && hiSlope == 1)
3065 // The slope can change from negative to positive only at the maximum value.
3066 return m_loExtremum;
3068 else if (loSlope == hiSlope &&
3069 deIntSign(CFloatFunc1<T>::applyExact(hi) - CFloatFunc1<T>::applyExact(lo)) * loSlope == -1)
3071 // The slope has changed twice between the endpoints, so both extrema are included.
3072 return m_hiExtremum | m_loExtremum;
3078 Interval getCodomain (const EvalContext&) const
3080 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
3081 return Interval(-1.0, 1.0) | TCU_NAN;
3084 double precision (const EvalContext& ctx, double ret, double arg) const;
3086 Interval getInputRange (const bool is16bit) const;
3087 virtual int doGetSlope (double angle) const = 0;
3089 Interval m_loExtremum;
3090 Interval m_hiExtremum;
3093 //Only -DE_PI_DOUBLE, DE_PI_DOUBLE input range
3095 Interval TrigFunc<Signature<float, float> >::getInputRange(const bool is16bit) const
3098 return Interval(false, -DE_PI_DOUBLE, DE_PI_DOUBLE);
3101 //Only -DE_PI_DOUBLE, DE_PI_DOUBLE input range
3103 Interval TrigFunc<Signature<deFloat16, deFloat16> >::getInputRange(const bool is16bit) const
3106 return Interval(false, -DE_PI_DOUBLE, DE_PI_DOUBLE);
3109 //Only -DE_PI_DOUBLE, DE_PI_DOUBLE input range
3111 Interval TrigFunc<Signature<double, double> >::getInputRange(const bool is16bit) const
3114 return Interval(false, -DE_PI_DOUBLE, DE_PI_DOUBLE);
3118 double TrigFunc<Signature<float, float> >::precision(const EvalContext& ctx, double ret, double arg) const
3121 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
3123 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
3124 return deLdExp(1.0, -11);
3127 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
3128 // 2^-11 at x == pi.
3129 return deLdExp(deAbs(arg), -12);
3134 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_MEDIUMP || ctx.floatPrecision == glu::PRECISION_LAST);
3136 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
3137 return deLdExp(1.0, -7);
3140 // |x| * 2^-8, slightly larger than 2^-7 at x == pi
3141 return deLdExp(deAbs(arg), -8);
3149 * Absolute error 2^{-7} inside the range [-pi, pi].
3152 double TrigFunc<Signature<deFloat16, deFloat16> >::precision(const EvalContext& ctx, double ret, double arg) const
3157 DE_ASSERT(-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE && ctx.floatPrecision == glu::PRECISION_LAST);
3158 return deLdExp(1.0, -7);
3161 // Spec: "The precision of double-precision instructions is at least that of single precision."
3162 // Lets pick float high precision as a reference.
3164 double TrigFunc<Signature<double, double> >::precision(const EvalContext& ctx, double ret, double arg) const
3168 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
3169 return deLdExp(1.0, -11);
3172 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
3173 // 2^-11 at x == pi.
3174 return deLdExp(deAbs(arg), -12);
3178 /*Proper parameters for template T
3179 Signature<float, float> 32bit tests
3180 Signature<float, deFloat16> 16bit tests*/
3182 class Sin : public TrigFunc<T>
3185 Sin (void) : TrigFunc<T>("sin", deSin, -1.0, 1.0) {}
3188 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
3191 ExprP<float> sin (const ExprP<float>& x) { return app<Sin<Signature<float, float> > >(x); }
3192 ExprP<deFloat16> sin (const ExprP<deFloat16>& x) { return app<Sin<Signature<deFloat16, deFloat16> > >(x); }
3193 ExprP<double> sin (const ExprP<double>& x) { return app<Sin<Signature<double, double> > >(x); }
3196 class Cos : public TrigFunc<T>
3199 Cos (void) : TrigFunc<T> ("cos", deCos, -1.0, 1.0) {}
3202 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
3205 ExprP<float> cos (const ExprP<float>& x) { return app<Cos<Signature<float, float> > >(x); }
3206 ExprP<deFloat16> cos (const ExprP<deFloat16>& x) { return app<Cos<Signature<deFloat16, deFloat16> > >(x); }
3207 ExprP<double> cos (const ExprP<double>& x) { return app<Cos<Signature<double, double> > >(x); }
3209 DEFINE_DERIVED_FLOAT1_INPUTRANGE(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)), Interval(false, -DE_PI_DOUBLE, DE_PI_DOUBLE))
3210 DEFINE_DERIVED_FLOAT1_INPUTRANGE_16BIT(Tan16Bit, tan, x, sin(x) * (constant((deFloat16)FLOAT16_1_0) / cos(x)), Interval(false, -DE_PI_DOUBLE, DE_PI_DOUBLE))
3211 DEFINE_DERIVED_DOUBLE1_INPUTRANGE(Tan64Bit, tan, x, sin(x) * (constant(1.0) / cos(x)), Interval(false, -DE_PI_DOUBLE, DE_PI_DOUBLE))
3214 class ATan : public CFloatFunc1<T>
3217 ATan (void) : CFloatFunc1<T> ("atan", deAtanOver) {}
3220 double precision (const EvalContext& ctx, double ret, double) const
3222 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
3223 return ctx.format.ulp(ret, 4096.0);
3225 return ctx.format.ulp(ret, 5.0);
3228 Interval getCodomain(const EvalContext& ctx) const
3230 return ctx.format.roundOut(Interval(-0.5 * DE_PI_DOUBLE, 0.5 * DE_PI_DOUBLE), true);
3235 class ATan2 : public CFloatFunc2<T>
3238 ATan2 (void) : CFloatFunc2<T> ("atan", deAtan2) {}
3241 Interval innerExtrema (const EvalContext& ctx,
3243 const Interval& xi) const
3247 if (yi.contains(0.0))
3249 if (xi.contains(0.0))
3251 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
3252 ret |= ctx.format.roundOut(Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE), true);
3255 if (!yi.isFinite(ctx.format.getMaxValue()) || !xi.isFinite(ctx.format.getMaxValue()))
3257 // Infinities may not be supported, allow anything, including NaN
3264 double precision (const EvalContext& ctx, double ret, double, double) const
3266 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
3267 return ctx.format.ulp(ret, 4096.0);
3269 return ctx.format.ulp(ret, 5.0);
3272 Interval getCodomain(const EvalContext& ctx) const
3274 return ctx.format.roundOut(Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE), true);
3278 ExprP<float> atan2 (const ExprP<float>& x, const ExprP<float>& y) { return app<ATan2<Signature<float, float, float> > >(x, y); }
3280 ExprP<deFloat16> atan2 (const ExprP<deFloat16>& x, const ExprP<deFloat16>& y) { return app<ATan2<Signature<deFloat16, deFloat16, deFloat16> > >(x, y); }
3282 ExprP<double> atan2 (const ExprP<double>& x, const ExprP<double>& y) { return app<ATan2<Signature<double, double, double> > >(x, y); }
3285 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp<float>(x) - exp<float>(-x)) / constant(2.0f))
3286 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp<float>(x) + exp<float>(-x)) / constant(2.0f))
3287 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x))
3289 DEFINE_DERIVED_FLOAT1_16BIT(Sinh16Bit, sinh, x, (exp(x) - exp(-x)) / constant((deFloat16)FLOAT16_2_0))
3290 DEFINE_DERIVED_FLOAT1_16BIT(Cosh16Bit, cosh, x, (exp(x) + exp(-x)) / constant((deFloat16)FLOAT16_2_0))
3291 DEFINE_DERIVED_FLOAT1_16BIT(Tanh16Bit, tanh, x, sinh(x) / cosh(x))
3293 DEFINE_DERIVED_DOUBLE1(Sinh64Bit, sinh, x, (exp<double>(x) - exp<double>(-x)) / constant(2.0))
3294 DEFINE_DERIVED_DOUBLE1(Cosh64Bit, cosh, x, (exp<double>(x) + exp<double>(-x)) / constant(2.0))
3295 DEFINE_DERIVED_DOUBLE1(Tanh64Bit, tanh, x, sinh(x) / cosh(x))
3297 DEFINE_DERIVED_FLOAT1(ASin, asin, x, atan2(x, sqrt(constant(1.0f) - x * x)))
3298 DEFINE_DERIVED_FLOAT1(ACos, acos, x, atan2(sqrt(constant(1.0f) - x * x), x))
3299 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))))
3300 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
3301 (x * x - constant(1.0f))))))
3302 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
3303 (constant(1.0f) - x)))
3305 DEFINE_DERIVED_FLOAT1_16BIT(ASin16Bit, asin, x, atan2(x, sqrt(constant((deFloat16)FLOAT16_1_0) - x * x)))
3306 DEFINE_DERIVED_FLOAT1_16BIT(ACos16Bit, acos, x, atan2(sqrt(constant((deFloat16)FLOAT16_1_0) - x * x), x))
3307 DEFINE_DERIVED_FLOAT1_16BIT(ASinh16Bit, asinh, x, log(x + sqrt(x * x + constant((deFloat16)FLOAT16_1_0))))
3308 DEFINE_DERIVED_FLOAT1_16BIT(ACosh16Bit, acosh, x, log(x + sqrt(alternatives((x + constant((deFloat16)FLOAT16_1_0)) * (x - constant((deFloat16)FLOAT16_1_0)),
3309 (x * x - constant((deFloat16)FLOAT16_1_0))))))
3310 DEFINE_DERIVED_FLOAT1_16BIT(ATanh16Bit, atanh, x, constant((deFloat16)FLOAT16_0_5) * log((constant((deFloat16)FLOAT16_1_0) + x) /
3311 (constant((deFloat16)FLOAT16_1_0) - x)))
3313 DEFINE_DERIVED_DOUBLE1(ASin64Bit, asin, x, atan2(x, sqrt(constant(1.0) - pow(x, constant(2.0)))))
3314 DEFINE_DERIVED_DOUBLE1(ACos64Bit, acos, x, atan2(sqrt(constant(1.0) - pow(x, constant(2.0))), x))
3315 DEFINE_DERIVED_DOUBLE1(ASinh64Bit, asinh, x, log(x + sqrt(x * x + constant(1.0))))
3316 DEFINE_DERIVED_DOUBLE1(ACosh64Bit, acosh, x, log(x + sqrt(alternatives((x + constant(1.0)) * (x - constant(1.0)),
3317 (x * x - constant(1.0))))))
3318 DEFINE_DERIVED_DOUBLE1(ATanh64Bit, atanh, x, constant(0.5) * log((constant(1.0) + x) /
3319 (constant(1.0) - x)))
3321 template <typename T>
3322 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
3325 typedef typename GetComponent::IRet IRet;
3327 string getName (void) const { return "_getComponent"; }
3329 void print (ostream& os,
3330 const BaseArgExprs& args) const
3332 os << *args[0] << "[" << *args[1] << "]";
3336 IRet doApply (const EvalContext&,
3337 const typename GetComponent::IArgs& iargs) const
3341 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
3343 if (iargs.b.contains(compNdx))
3344 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
3352 template <typename T>
3353 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
3355 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
3356 return app<GetComponent<T> >(container, constant(ndx));
3359 template <typename T> string vecNamePrefix (void);
3360 template <> string vecNamePrefix<float> (void) { return ""; }
3361 template <> string vecNamePrefix<deFloat16>(void) { return ""; }
3362 template <> string vecNamePrefix<double> (void) { return "d"; }
3363 template <> string vecNamePrefix<int> (void) { return "i"; }
3364 template <> string vecNamePrefix<bool> (void) { return "b"; }
3366 template <typename T, int Size>
3367 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
3369 template <typename T, int Size> class GenVec;
3371 template <typename T>
3372 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
3375 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
3377 string getName (void) const
3379 return "_" + vecName<T, 1>();
3384 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
3387 template <typename T>
3388 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
3391 typedef typename GenVec::IRet IRet;
3392 typedef typename GenVec::IArgs IArgs;
3394 string getName (void) const
3396 return vecName<T, 2>();
3400 IRet doApply (const EvalContext&, const IArgs& iargs) const
3402 return IRet(iargs.a, iargs.b);
3406 template <typename T>
3407 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
3410 typedef typename GenVec::IRet IRet;
3411 typedef typename GenVec::IArgs IArgs;
3413 string getName (void) const
3415 return vecName<T, 3>();
3419 IRet doApply (const EvalContext&, const IArgs& iargs) const
3421 return IRet(iargs.a, iargs.b, iargs.c);
3425 template <typename T>
3426 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
3429 typedef typename GenVec::IRet IRet;
3430 typedef typename GenVec::IArgs IArgs;
3432 string getName (void) const { return vecName<T, 4>(); }
3435 IRet doApply (const EvalContext&, const IArgs& iargs) const
3437 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
3441 template <typename T, int Rows, int Columns>
3444 template <typename T, int Rows>
3445 class GenMat<T, Rows, 2> : public PrimitiveFunc<
3446 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
3449 typedef typename GenMat::Ret Ret;
3450 typedef typename GenMat::IRet IRet;
3451 typedef typename GenMat::IArgs IArgs;
3453 string getName (void) const
3455 return dataTypeNameOf<Ret>();
3460 IRet doApply (const EvalContext&, const IArgs& iargs) const
3469 template <typename T, int Rows>
3470 class GenMat<T, Rows, 3> : public PrimitiveFunc<
3471 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
3474 typedef typename GenMat::Ret Ret;
3475 typedef typename GenMat::IRet IRet;
3476 typedef typename GenMat::IArgs IArgs;
3478 string getName (void) const
3480 return dataTypeNameOf<Ret>();
3485 IRet doApply (const EvalContext&, const IArgs& iargs) const
3495 template <typename T, int Rows>
3496 class GenMat<T, Rows, 4> : public PrimitiveFunc<
3497 Signature<Matrix<T, Rows, 4>,
3498 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
3501 typedef typename GenMat::Ret Ret;
3502 typedef typename GenMat::IRet IRet;
3503 typedef typename GenMat::IArgs IArgs;
3505 string getName (void) const
3507 return dataTypeNameOf<Ret>();
3511 IRet doApply (const EvalContext&, const IArgs& iargs) const
3522 template <typename T, int Rows>
3523 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
3524 const ExprP<Vector<T, Rows> >& arg1)
3526 return app<GenMat<T, Rows, 2> >(arg0, arg1);
3529 template <typename T, int Rows>
3530 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
3531 const ExprP<Vector<T, Rows> >& arg1,
3532 const ExprP<Vector<T, Rows> >& arg2)
3534 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
3537 template <typename T, int Rows>
3538 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
3539 const ExprP<Vector<T, Rows> >& arg1,
3540 const ExprP<Vector<T, Rows> >& arg2,
3541 const ExprP<Vector<T, Rows> >& arg3)
3543 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
3546 template <typename T, int Rows, int Cols>
3547 class MatNeg : public PrimitiveFunc<Signature<Matrix<T, Rows, Cols>,
3548 Matrix<T, Rows, Cols> > >
3551 typedef typename MatNeg::IRet IRet;
3552 typedef typename MatNeg::IArgs IArgs;
3554 string getName (void) const
3560 void doPrint (ostream& os, const BaseArgExprs& args) const
3562 os << "-(" << *args[0] << ")";
3565 IRet doApply (const EvalContext&, const IArgs& iargs) const
3569 for (int col = 0; col < Cols; ++col)
3571 for (int row = 0; row < Rows; ++row)
3572 ret[col][row] = -iargs.a[col][row];
3579 template <typename T, typename Sig>
3580 class CompWiseFunc : public PrimitiveFunc<Sig>
3583 typedef Func<Signature<T, T, T> > ScalarFunc;
3585 string getName (void) const
3587 return doGetScalarFunc().getName();
3590 void doPrint (ostream& os,
3591 const BaseArgExprs& args) const
3593 doGetScalarFunc().print(os, args);
3597 const ScalarFunc& doGetScalarFunc (void) const = 0;
3600 template <typename T, int Rows, int Cols>
3601 class CompMatFuncBase : public CompWiseFunc<T, Signature<Matrix<T, Rows, Cols>,
3602 Matrix<T, Rows, Cols>,
3603 Matrix<T, Rows, Cols> > >
3606 typedef typename CompMatFuncBase::IRet IRet;
3607 typedef typename CompMatFuncBase::IArgs IArgs;
3611 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3615 for (int col = 0; col < Cols; ++col)
3617 for (int row = 0; row < Rows; ++row)
3618 ret[col][row] = this->doGetScalarFunc().apply(ctx,
3627 template <typename F, typename T, int Rows, int Cols>
3628 class CompMatFunc : public CompMatFuncBase<T, Rows, Cols>
3631 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
3633 return instance<F>();
3638 class ScalarMatrixCompMult : public Mul< Signature<T, T, T> >
3642 string getName (void) const
3644 return "matrixCompMult";
3647 void doPrint (ostream& os, const BaseArgExprs& args) const
3649 Func<Signature<T, T, T> >::doPrint(os, args);
3653 template <int Rows, int Cols, class T>
3654 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult<T>, T, Rows, Cols>
3658 template <int Rows, int Cols>
3659 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
3660 Matrix<float, Rows, Cols>,
3664 typedef typename ScalarMatFuncBase::IRet IRet;
3665 typedef typename ScalarMatFuncBase::IArgs IArgs;
3669 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3673 for (int col = 0; col < Cols; ++col)
3675 for (int row = 0; row < Rows; ++row)
3676 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
3683 template <typename F, int Rows, int Cols>
3684 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
3687 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
3689 return instance<F>();
3693 template<typename T, int Size> struct GenXType;
3695 template<typename T>
3696 struct GenXType<T, 1>
3698 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
3701 template<typename T>
3702 struct GenXType<T, 2>
3704 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
3706 return app<GenVec<T, 2> >(x, x);
3710 template<typename T>
3711 struct GenXType<T, 3>
3713 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
3715 return app<GenVec<T, 3> >(x, x, x);
3719 template<typename T>
3720 struct GenXType<T, 4>
3722 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
3724 return app<GenVec<T, 4> >(x, x, x, x);
3728 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
3729 //! with each element initialized with the expression `x`.
3730 template<typename T, int Size>
3731 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
3733 return GenXType<T, Size>::genXType(x);
3736 typedef GenVec<float, 2> FloatVec2;
3737 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
3739 typedef GenVec<deFloat16, 2> FloatVec2_16bit;
3740 DEFINE_CONSTRUCTOR2(FloatVec2_16bit, Vec2_16Bit, vec2, deFloat16, deFloat16)
3742 typedef GenVec<double, 2> DoubleVec2;
3743 DEFINE_CONSTRUCTOR2(DoubleVec2, Vec2_64Bit, vec2, double, double)
3745 typedef GenVec<float, 3> FloatVec3;
3746 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
3748 typedef GenVec<deFloat16, 3> FloatVec3_16bit;
3749 DEFINE_CONSTRUCTOR3(FloatVec3_16bit, Vec3_16Bit, vec3, deFloat16, deFloat16, deFloat16)
3751 typedef GenVec<double, 3> DoubleVec3;
3752 DEFINE_CONSTRUCTOR3(DoubleVec3, Vec3_64Bit, vec3, double, double, double)
3754 typedef GenVec<float, 4> FloatVec4;
3755 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
3757 typedef GenVec<deFloat16, 4> FloatVec4_16bit;
3758 DEFINE_CONSTRUCTOR4(FloatVec4_16bit, Vec4_16Bit, vec4, deFloat16, deFloat16, deFloat16, deFloat16)
3760 typedef GenVec<double, 4> DoubleVec4;
3761 DEFINE_CONSTRUCTOR4(DoubleVec4, Vec4_64Bit, vec4, double, double, double, double)
3764 const ExprP<T> getConstZero(void);
3766 const ExprP<T> getConstOne(void);
3768 const ExprP<T> getConstTwo(void);
3771 const ExprP<float> getConstZero<float>(void)
3773 return constant(0.0f);
3777 const ExprP<deFloat16> getConstZero<deFloat16>(void)
3779 return constant((deFloat16)FLOAT16_0_0);
3783 const ExprP<double> getConstZero<double>(void)
3785 return constant(0.0);
3789 const ExprP<float> getConstOne<float>(void)
3791 return constant(1.0f);
3795 const ExprP<deFloat16> getConstOne<deFloat16>(void)
3797 return constant((deFloat16)FLOAT16_1_0);
3801 const ExprP<double> getConstOne<double>(void)
3803 return constant(1.0);
3807 const ExprP<float> getConstTwo<float>(void)
3809 return constant(2.0f);
3813 const ExprP<deFloat16> getConstTwo<deFloat16>(void)
3815 return constant((deFloat16)FLOAT16_2_0);
3819 const ExprP<double> getConstTwo<double>(void)
3821 return constant(2.0);
3824 template <int Size, class T>
3825 class Dot : public DerivedFunc<Signature<T, Vector<T, Size>, Vector<T, Size> > >
3828 typedef typename Dot::ArgExprs ArgExprs;
3830 string getName (void) const
3836 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const
3839 // Precompute all products.
3840 for (int ndx = 0; ndx < Size; ++ndx)
3841 op[ndx] = args.a[ndx] * args.b[ndx];
3844 //Prepare an array of indices.
3845 for (int ndx = 0; ndx < Size; ++ndx)
3848 ExprP<T> res = op[0];
3849 // Compute the first dot alternative: SUM(a[i]*b[i]), i = 0 .. Size-1
3850 for (int ndx = 1; ndx < Size; ++ndx)
3851 res = res + op[ndx];
3853 // Generate all permutations of indices and
3854 // using a permutation compute a dot alternative.
3855 // Generates all possible variants fo summation of products in the dot product expansion expression.
3857 ExprP<T> alt = getConstZero<T>();
3858 for (int ndx = 0; ndx < Size; ++ndx)
3859 alt = alt + op[idx[ndx]];
3860 res = alternatives(res, alt);
3861 } while (std::next_permutation(idx, idx + Size));
3868 class Dot<1, T> : public DerivedFunc<Signature<T, T, T> >
3871 typedef typename DerivedFunc<Signature<T, T, T> >::ArgExprs TArgExprs;
3873 string getName (void) const
3878 ExprP<T> doExpand (ExpandContext&, const TArgExprs& args) const
3880 return args.a * args.b;
3885 ExprP<deFloat16> dot (const ExprP<Vector<deFloat16, Size> >& x, const ExprP<Vector<deFloat16, Size> >& y)
3887 return app<Dot<Size, deFloat16> >(x, y);
3890 ExprP<deFloat16> dot (const ExprP<deFloat16>& x, const ExprP<deFloat16>& y)
3892 return app<Dot<1, deFloat16> >(x, y);
3896 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
3898 return app<Dot<Size, float> >(x, y);
3901 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
3903 return app<Dot<1, float> >(x, y);
3907 ExprP<double> dot (const ExprP<Vector<double, Size> >& x, const ExprP<Vector<double, Size> >& y)
3909 return app<Dot<Size, double> >(x, y);
3912 ExprP<double> dot (const ExprP<double>& x, const ExprP<double>& y)
3914 return app<Dot<1, double> >(x, y);
3917 template <int Size, class T>
3918 class Length : public DerivedFunc<
3919 Signature<T, typename ContainerOf<T, Size>::Container> >
3922 typedef typename Length::ArgExprs ArgExprs;
3924 string getName (void) const
3930 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const
3932 return sqrt(dot(args.a, args.a));
3937 template <class T, class TRet>
3938 ExprP<TRet> length (const ExprP<T>& x)
3940 return app<Length<1, T> >(x);
3943 template <int Size, class T, class TRet>
3944 ExprP<TRet> length (const ExprP<typename ContainerOf<T, Size>::Container>& x)
3946 return app<Length<Size, T> >(x);
3949 template <int Size, class T>
3950 class Distance : public DerivedFunc<
3952 typename ContainerOf<T, Size>::Container,
3953 typename ContainerOf<T, Size>::Container> >
3956 typedef typename Distance::Ret Ret;
3957 typedef typename Distance::ArgExprs ArgExprs;
3959 string getName (void) const
3965 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3967 return length<Size, T, Ret>(args.a - args.b);
3973 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3976 string getName (void) const
3982 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3984 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3985 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3986 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3990 class Cross16Bit : public DerivedFunc<Signature<Vec3_16Bit, Vec3_16Bit, Vec3_16Bit> >
3993 string getName (void) const
3999 ExprP<Vec3_16Bit> doExpand (ExpandContext&, const ArgExprs& x) const
4001 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
4002 x.a[2] * x.b[0] - x.b[2] * x.a[0],
4003 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
4007 class Cross64Bit : public DerivedFunc<Signature<Vec3_64Bit, Vec3_64Bit, Vec3_64Bit> >
4010 string getName (void) const
4016 ExprP<Vec3_64Bit> doExpand (ExpandContext&, const ArgExprs& x) const
4018 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
4019 x.a[2] * x.b[0] - x.b[2] * x.a[0],
4020 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
4024 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
4025 DEFINE_CONSTRUCTOR2(Cross16Bit, Vec3_16Bit, cross, Vec3_16Bit, Vec3_16Bit)
4026 DEFINE_CONSTRUCTOR2(Cross64Bit, Vec3_64Bit, cross, Vec3_64Bit, Vec3_64Bit)
4028 template<int Size, class T>
4029 class Normalize : public DerivedFunc<
4030 Signature<typename ContainerOf<T, Size>::Container,
4031 typename ContainerOf<T, Size>::Container> >
4034 typedef typename Normalize::Ret Ret;
4035 typedef typename Normalize::ArgExprs ArgExprs;
4037 string getName (void) const
4043 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
4045 return args.a / length<Size, T, T>(args.a);
4049 template <int Size, class T>
4050 class FaceForward : public DerivedFunc<
4051 Signature<typename ContainerOf<T, Size>::Container,
4052 typename ContainerOf<T, Size>::Container,
4053 typename ContainerOf<T, Size>::Container,
4054 typename ContainerOf<T, Size>::Container> >
4057 typedef typename FaceForward::Ret Ret;
4058 typedef typename FaceForward::ArgExprs ArgExprs;
4060 string getName (void) const
4062 return "faceforward";
4066 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
4068 return cond(dot(args.c, args.b) < getConstZero<T>(), args.a, -args.a);
4072 template <int Size, class T>
4073 class Reflect : public DerivedFunc<
4074 Signature<typename ContainerOf<T, Size>::Container,
4075 typename ContainerOf<T, Size>::Container,
4076 typename ContainerOf<T, Size>::Container> >
4079 typedef typename Reflect::Ret Ret;
4080 typedef typename Reflect::Arg0 Arg0;
4081 typedef typename Reflect::Arg1 Arg1;
4082 typedef typename Reflect::ArgExprs ArgExprs;
4084 string getName (void) const
4090 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
4092 const ExprP<Arg0>& i = args.a;
4093 const ExprP<Arg1>& n = args.b;
4094 const ExprP<T> dotNI = bindExpression("dotNI", ctx, dot(n, i));
4096 return i - alternatives((n * dotNI) * getConstTwo<T>(),
4097 alternatives( n * (dotNI * getConstTwo<T>()),
4098 alternatives(n * dot(i * getConstTwo<T>(), n),
4099 n * dot(i, n * getConstTwo<T>())
4107 class Reflect<1, T> : public DerivedFunc<
4108 Signature<T, T, T> >
4111 typedef typename Reflect::Ret Ret;
4112 typedef typename Reflect::Arg0 Arg0;
4113 typedef typename Reflect::Arg1 Arg1;
4114 typedef typename Reflect::ArgExprs ArgExprs;
4116 string getName (void) const
4122 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
4124 const ExprP<Arg0>& i = args.a;
4125 const ExprP<Arg1>& n = args.b;
4126 const ExprP<T> dotNI = bindExpression("dotNI", ctx, dot(n, i));
4128 return i - alternatives((n * dotNI) * getConstTwo<T>(),
4129 alternatives( n * (dotNI * getConstTwo<T>()),
4130 alternatives(n * dot(i * getConstTwo<T>(), n),
4131 alternatives(n * dot(i, n * getConstTwo<T>()),
4132 dot(n * n, i * getConstTwo<T>()))
4139 template <int Size, class T>
4140 class Refract : public DerivedFunc<
4141 Signature<typename ContainerOf<T, Size>::Container,
4142 typename ContainerOf<T, Size>::Container,
4143 typename ContainerOf<T, Size>::Container,
4147 typedef typename Refract::Ret Ret;
4148 typedef typename Refract::Arg0 Arg0;
4149 typedef typename Refract::Arg1 Arg1;
4150 typedef typename Refract::Arg2 Arg2;
4151 typedef typename Refract::ArgExprs ArgExprs;
4153 string getName (void) const
4159 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
4161 const ExprP<Arg0>& i = args.a;
4162 const ExprP<Arg1>& n = args.b;
4163 const ExprP<Arg2>& eta = args.c;
4164 const ExprP<T> dotNI = bindExpression("dotNI", ctx, dot(n, i));
4165 const ExprP<T> k = bindExpression("k", ctx, getConstOne<T>() - eta * eta *
4166 (getConstOne<T>() - dotNI * dotNI));
4167 return cond(k < getConstZero<T>(),
4168 genXType<T, Size>(getConstZero<T>()),
4169 i * eta - n * (eta * dotNI + sqrt(k)));
4174 class PreciseFunc1 : public CFloatFunc1<T>
4177 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1<T> (name, func) {}
4179 double precision (const EvalContext&, double, double) const { return 0.0; }
4183 class Abs : public PreciseFunc1<T>
4186 Abs (void) : PreciseFunc1<T> ("abs", deAbs) {}
4190 class Sign : public PreciseFunc1<T>
4193 Sign (void) : PreciseFunc1<T> ("sign", deSign) {}
4197 class Floor : public PreciseFunc1<T>
4200 Floor (void) : PreciseFunc1<T> ("floor", deFloor) {}
4204 class Trunc : public PreciseFunc1<T>
4207 Trunc (void) : PreciseFunc1<T> ("trunc", deTrunc) {}
4211 class Round : public FloatFunc1<T>
4214 string getName (void) const { return "round"; }
4217 Interval applyPoint (const EvalContext&, double x) const
4219 double truncated = 0.0;
4220 const double fract = deModf(x, &truncated);
4223 if (fabs(fract) <= 0.5)
4225 if (fabs(fract) >= 0.5)
4226 ret |= truncated + deSign(fract);
4231 double precision (const EvalContext&, double, double) const { return 0.0; }
4235 class RoundEven : public PreciseFunc1<T>
4238 RoundEven (void) : PreciseFunc1<T> ("roundEven", deRoundEven) {}
4242 class Ceil : public PreciseFunc1<T>
4245 Ceil (void) : PreciseFunc1<T> ("ceil", deCeil) {}
4248 typedef Floor< Signature<float, float> > Floor32Bit;
4249 typedef Floor< Signature<deFloat16, deFloat16> > Floor16Bit;
4250 typedef Floor< Signature<double, double> > Floor64Bit;
4252 typedef Trunc< Signature<float, float> > Trunc32Bit;
4253 typedef Trunc< Signature<deFloat16, deFloat16> > Trunc16Bit;
4254 typedef Trunc< Signature<double, double> > Trunc64Bit;
4256 typedef Trunc< Signature<float, float> > Trunc32Bit;
4257 typedef Trunc< Signature<deFloat16, deFloat16> > Trunc16Bit;
4259 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor32Bit>(x))
4260 DEFINE_DERIVED_FLOAT1_16BIT(Fract16Bit, fract, x, x - app<Floor16Bit>(x))
4261 DEFINE_DERIVED_DOUBLE1(Fract64Bit, fract, x, x - app<Floor64Bit>(x))
4264 class PreciseFunc2 : public CFloatFunc2<T>
4267 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2<T> (name, func) {}
4269 double precision (const EvalContext&, double, double, double) const { return 0.0; }
4272 DEFINE_DERIVED_FLOAT2(Mod32Bit, mod, x, y, x - y * app<Floor32Bit>(x / y))
4273 DEFINE_DERIVED_FLOAT2_16BIT(Mod16Bit, mod, x, y, x - y * app<Floor16Bit>(x / y))
4274 DEFINE_DERIVED_DOUBLE2(Mod64Bit, mod, x, y, x - y * app<Floor64Bit>(x / y))
4276 DEFINE_CASED_DERIVED_FLOAT2(FRem32Bit, frem, x, y, x - y * app<Trunc32Bit>(x / y), SPIRV_CASETYPE_FREM)
4277 DEFINE_CASED_DERIVED_FLOAT2_16BIT(FRem16Bit, frem, x, y, x - y * app<Trunc16Bit>(x / y), SPIRV_CASETYPE_FREM)
4278 DEFINE_CASED_DERIVED_DOUBLE2(FRem64Bit, frem, x, y, x - y * app<Trunc64Bit>(x / y), SPIRV_CASETYPE_FREM)
4281 class Modf : public PrimitiveFunc<T>
4284 typedef typename Modf<T>::IArgs TIArgs;
4285 typedef typename Modf<T>::IRet TIRet;
4286 string getName (void) const
4292 TIRet doApply (const EvalContext& ctx, const TIArgs& iargs) const
4295 Interval& wholeIV = const_cast<Interval&>(iargs.b);
4298 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
4299 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
4300 deModf(x, &intPart); whole = intPart);
4302 if (!iargs.a.isFinite(ctx.format.getMaxValue()))
4304 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
4305 // See Khronos bug 13907
4312 int getOutParamIndex (void) const
4317 typedef Modf< Signature<float, float, float> > Modf32Bit;
4318 typedef Modf< Signature<deFloat16, deFloat16, deFloat16> > Modf16Bit;
4319 typedef Modf< Signature<double, double, double> > Modf64Bit;
4322 class ModfStruct : public Modf<T>
4325 virtual string getName (void) const { return "modfstruct"; }
4326 virtual SpirVCaseT getSpirvCase (void) const { return SPIRV_CASETYPE_MODFSTRUCT; }
4328 typedef ModfStruct< Signature<float, float, float> > ModfStruct32Bit;
4329 typedef ModfStruct< Signature<deFloat16, deFloat16, deFloat16> > ModfStruct16Bit;
4330 typedef ModfStruct< Signature<double, double, double> > ModfStruct64Bit;
4333 class Min : public PreciseFunc2<T> { public: Min (void) : PreciseFunc2<T> ("min", deMin) {} };
4335 class Max : public PreciseFunc2<T> { public: Max (void) : PreciseFunc2<T> ("max", deMax) {} };
4338 class Clamp : public FloatFunc3<T>
4341 string getName (void) const { return "clamp"; }
4343 double applyExact (double x, double minVal, double maxVal) const
4345 return de::min(de::max(x, minVal), maxVal);
4348 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
4350 return minVal > maxVal ? TCU_NAN : 0.0;
4354 ExprP<deFloat16> clamp(const ExprP<deFloat16>& x, const ExprP<deFloat16>& minVal, const ExprP<deFloat16>& maxVal)
4356 return app<Clamp< Signature<deFloat16, deFloat16, deFloat16, deFloat16> > >(x, minVal, maxVal);
4359 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
4361 return app<Clamp< Signature<float, float, float, float> > >(x, minVal, maxVal);
4364 ExprP<double> clamp(const ExprP<double>& x, const ExprP<double>& minVal, const ExprP<double>& maxVal)
4366 return app<Clamp< Signature<double, double, double, double> > >(x, minVal, maxVal);
4370 class NanIfGreaterOrEqual : public FloatFunc2<T>
4373 string getName (void) const { return "nanIfGreaterOrEqual"; }
4375 double applyExact (double edge0, double edge1) const
4377 return (edge0 >= edge1) ? TCU_NAN : 0.0;
4380 double precision (const EvalContext&, double, double edge0, double edge1) const
4382 return (edge0 >= edge1) ? TCU_NAN : 0.0;
4386 ExprP<deFloat16> nanIfGreaterOrEqual(const ExprP<deFloat16>& edge0, const ExprP<deFloat16>& edge1)
4388 return app<NanIfGreaterOrEqual< Signature<deFloat16, deFloat16, deFloat16> > >(edge0, edge1);
4391 ExprP<float> nanIfGreaterOrEqual(const ExprP<float>& edge0, const ExprP<float>& edge1)
4393 return app<NanIfGreaterOrEqual< Signature<float, float, float> > >(edge0, edge1);
4396 ExprP<double> nanIfGreaterOrEqual(const ExprP<double>& edge0, const ExprP<double>& edge1)
4398 return app<NanIfGreaterOrEqual< Signature<double, double, double> > >(edge0, edge1);
4401 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
4404 DEFINE_DERIVED_FLOAT3_16BIT(Mix16Bit, mix, x, y, a, alternatives((x * (constant((deFloat16)FLOAT16_1_0) - a)) + y * a,
4407 DEFINE_DERIVED_DOUBLE3(Mix64Bit, mix, x, y, a, alternatives((x * (constant(1.0) - a)) + y * a,
4410 static double step (double edge, double x)
4412 return x < edge ? 0.0 : 1.0;
4416 class Step : public PreciseFunc2<T> { public: Step (void) : PreciseFunc2<T> ("step", step) {} };
4419 class SmoothStep : public DerivedFunc<T>
4422 typedef typename SmoothStep<T>::ArgExprs TArgExprs;
4423 typedef typename SmoothStep<T>::Ret TRet;
4424 string getName (void) const
4426 return "smoothstep";
4431 ExprP<TRet> doExpand (ExpandContext& ctx, const TArgExprs& args) const;
4435 ExprP<SmoothStep< Signature<float, float, float, float> >::Ret> SmoothStep< Signature<float, float, float, float> >::doExpand (ExpandContext& ctx, const SmoothStep< Signature<float, float, float, float> >::ArgExprs& args) const
4437 const ExprP<float>& edge0 = args.a;
4438 const ExprP<float>& edge1 = args.b;
4439 const ExprP<float>& x = args.c;
4440 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0), constant(0.0f), constant(1.0f))
4441 + nanIfGreaterOrEqual(edge0, edge1); // force NaN (and non-analyzable result) for cases edge0 >= edge1
4442 const ExprP<float> t = bindExpression("t", ctx, tExpr);
4444 return (t * t * (constant(3.0f) - constant(2.0f) * t));
4448 ExprP<SmoothStep< Signature<deFloat16, deFloat16, deFloat16, deFloat16> >::TRet> SmoothStep< Signature<deFloat16, deFloat16, deFloat16, deFloat16> >::doExpand (ExpandContext& ctx, const TArgExprs& args) const
4450 const ExprP<deFloat16>& edge0 = args.a;
4451 const ExprP<deFloat16>& edge1 = args.b;
4452 const ExprP<deFloat16>& x = args.c;
4453 const ExprP<deFloat16> tExpr = clamp(( x - edge0 ) / ( edge1 - edge0 ),
4454 constant((deFloat16)FLOAT16_0_0), constant((deFloat16)FLOAT16_1_0))
4455 + nanIfGreaterOrEqual(edge0, edge1); // force NaN (and non-analyzable result) for cases edge0 >= edge1
4456 const ExprP<deFloat16> t = bindExpression("t", ctx, tExpr);
4458 return (t * t * (constant((deFloat16)FLOAT16_3_0) - constant((deFloat16)FLOAT16_2_0) * t));
4462 ExprP<SmoothStep< Signature<double, double, double, double> >::Ret> SmoothStep< Signature<double, double, double, double> >::doExpand (ExpandContext& ctx, const SmoothStep< Signature<double, double, double, double> >::ArgExprs& args) const
4464 const ExprP<double>& edge0 = args.a;
4465 const ExprP<double>& edge1 = args.b;
4466 const ExprP<double>& x = args.c;
4467 const ExprP<double> tExpr = clamp((x - edge0) / (edge1 - edge0), constant(0.0), constant(1.0))
4468 + nanIfGreaterOrEqual(edge0, edge1); // force NaN (and non-analyzable result) for cases edge0 >= edge1
4469 const ExprP<double> t = bindExpression("t", ctx, tExpr);
4471 return (t * t * (constant(3.0) - constant(2.0) * t));
4474 //Signature<float, float, int>
4475 //Signature<float, deFloat16, int>
4476 //Signature<double, double, int>
4478 class FrExp : public PrimitiveFunc<T>
4481 string getName (void) const
4486 typedef typename FrExp::IRet IRet;
4487 typedef typename FrExp::IArgs IArgs;
4488 typedef typename FrExp::IArg0 IArg0;
4489 typedef typename FrExp::IArg1 IArg1;
4492 IRet doApply (const EvalContext&, const IArgs& iargs) const
4495 const IArg0& x = iargs.a;
4496 IArg1& exponent = const_cast<IArg1&>(iargs.b);
4498 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
4500 // GLSL (in contrast to IEEE) says that result of applying frexp
4501 // to infinity is undefined
4502 ret = Interval::unbounded() | TCU_NAN;
4503 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
4505 else if (!x.empty())
4508 const double loFrac = deFrExp(x.lo(), &loExp);
4510 const double hiFrac = deFrExp(x.hi(), &hiExp);
4512 if (deSign(loFrac) != deSign(hiFrac))
4514 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
4516 if (deSign(loFrac) < 0)
4517 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
4518 if (deSign(hiFrac) > 0)
4519 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
4523 exponent = Interval(loExp, hiExp);
4525 ret = Interval(loFrac, hiFrac);
4527 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
4534 int getOutParamIndex (void) const
4539 typedef FrExp< Signature<float, float, int> > Frexp32Bit;
4540 typedef FrExp< Signature<deFloat16, deFloat16, int> > Frexp16Bit;
4541 typedef FrExp< Signature<double, double, int> > Frexp64Bit;
4544 class FrexpStruct : public FrExp<T>
4547 virtual string getName (void) const { return "frexpstruct"; }
4548 virtual SpirVCaseT getSpirvCase (void) const { return SPIRV_CASETYPE_FREXPSTRUCT; }
4550 typedef FrexpStruct< Signature<float, float, int> > FrexpStruct32Bit;
4551 typedef FrexpStruct< Signature<deFloat16, deFloat16, int> > FrexpStruct16Bit;
4552 typedef FrexpStruct< Signature<double, double, int> > FrexpStruct64Bit;
4554 //Signature<float, float, int>
4555 //Signature<deFloat16, deFloat16, int>
4556 //Signature<double, double, int>
4558 class LdExp : public PrimitiveFunc<T >
4561 typedef typename LdExp::IRet IRet;
4562 typedef typename LdExp::IArgs IArgs;
4564 string getName (void) const
4570 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
4572 const int minExp = ctx.format.getMinExp();
4573 const int maxExp = ctx.format.getMaxExp();
4574 // Restrictions from the GLSL.std.450 instruction set.
4575 // See Khronos bugzilla 11180 for rationale.
4576 bool any = iargs.a.hasNaN() || iargs.b.hi() > (maxExp + 1);
4577 Interval ret(any, ldexp(iargs.a.lo(), (int)iargs.b.lo()), ldexp(iargs.a.hi(), (int)iargs.b.hi()));
4578 if (iargs.b.lo() < minExp) ret |= 0.0;
4579 if (!ret.isFinite(ctx.format.getMaxValue())) ret |= TCU_NAN;
4580 return ctx.format.convert(ret);
4585 Interval LdExp <Signature<double, double, int>>::doApply(const EvalContext& ctx, const IArgs& iargs) const
4587 const int minExp = ctx.format.getMinExp();
4588 const int maxExp = ctx.format.getMaxExp();
4589 // Restrictions from the GLSL.std.450 instruction set.
4590 // See Khronos bugzilla 11180 for rationale.
4591 bool any = iargs.a.hasNaN() || iargs.b.hi() > (maxExp + 1);
4592 Interval ret(any, ldexp(iargs.a.lo(), (int)iargs.b.lo()), ldexp(iargs.a.hi(), (int)iargs.b.hi()));
4593 // Add 1ULP precision tolerance to account for differing rounding modes between the GPU and deLdExp.
4594 ret += Interval(-ctx.format.ulp(ret.lo()), ctx.format.ulp(ret.hi()));
4595 if (iargs.b.lo() < minExp) ret |= 0.0;
4596 if (!ret.isFinite(ctx.format.getMaxValue())) ret |= TCU_NAN;
4597 return ctx.format.convert(ret);
4600 template<int Rows, int Columns, class T>
4601 class Transpose : public PrimitiveFunc<Signature<Matrix<T, Rows, Columns>,
4602 Matrix<T, Columns, Rows> > >
4605 typedef typename Transpose::IRet IRet;
4606 typedef typename Transpose::IArgs IArgs;
4608 string getName (void) const
4614 IRet doApply (const EvalContext&, const IArgs& iargs) const
4618 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4620 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4621 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
4628 template<typename Ret, typename Arg0, typename Arg1>
4629 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
4632 string getName (void) const { return "mul"; }
4635 void doPrint (ostream& os, const BaseArgExprs& args) const
4637 os << "(" << *args[0] << " * " << *args[1] << ")";
4641 template<typename T, int LeftRows, int Middle, int RightCols>
4642 class MatMul : public MulFunc<Matrix<T, LeftRows, RightCols>,
4643 Matrix<T, LeftRows, Middle>,
4644 Matrix<T, Middle, RightCols> >
4647 typedef typename MatMul::IRet IRet;
4648 typedef typename MatMul::IArgs IArgs;
4649 typedef typename MatMul::IArg0 IArg0;
4650 typedef typename MatMul::IArg1 IArg1;
4652 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
4654 const IArg0& left = iargs.a;
4655 const IArg1& right = iargs.b;
4658 for (int row = 0; row < LeftRows; ++row)
4660 for (int col = 0; col < RightCols; ++col)
4662 Interval element (0.0);
4664 for (int ndx = 0; ndx < Middle; ++ndx)
4665 element = call<Add< Signature<T, T, T> > >(ctx, element,
4666 call<Mul< Signature<T, T, T> > >(ctx, left[ndx][row], right[col][ndx]));
4668 ret[col][row] = element;
4676 template<typename T, int Rows, int Cols>
4677 class VecMatMul : public MulFunc<Vector<T, Cols>,
4679 Matrix<T, Rows, Cols> >
4682 typedef typename VecMatMul::IRet IRet;
4683 typedef typename VecMatMul::IArgs IArgs;
4684 typedef typename VecMatMul::IArg0 IArg0;
4685 typedef typename VecMatMul::IArg1 IArg1;
4688 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
4690 const IArg0& left = iargs.a;
4691 const IArg1& right = iargs.b;
4694 for (int col = 0; col < Cols; ++col)
4696 Interval element (0.0);
4698 for (int row = 0; row < Rows; ++row)
4699 element = call<Add< Signature<T, T, T> > >(ctx, element, call<Mul< Signature<T, T, T> > >(ctx, left[row], right[col][row]));
4708 template<int Rows, int Cols, class T>
4709 class MatVecMul : public MulFunc<Vector<T, Rows>,
4710 Matrix<T, Rows, Cols>,
4714 typedef typename MatVecMul::IRet IRet;
4715 typedef typename MatVecMul::IArgs IArgs;
4716 typedef typename MatVecMul::IArg0 IArg0;
4717 typedef typename MatVecMul::IArg1 IArg1;
4720 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
4722 const IArg0& left = iargs.a;
4723 const IArg1& right = iargs.b;
4725 return call<VecMatMul<T, Cols, Rows> >(ctx, right,
4726 call<Transpose<Rows, Cols, T> >(ctx, left));
4730 template<int Rows, int Cols, class T>
4731 class OuterProduct : public PrimitiveFunc<Signature<Matrix<T, Rows, Cols>,
4736 typedef typename OuterProduct::IRet IRet;
4737 typedef typename OuterProduct::IArgs IArgs;
4739 string getName (void) const
4741 return "outerProduct";
4745 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
4749 for (int row = 0; row < Rows; ++row)
4751 for (int col = 0; col < Cols; ++col)
4752 ret[col][row] = call<Mul< Signature<T, T, T> > >(ctx, iargs.a[row], iargs.b[col]);
4759 template<int Rows, int Cols, class T>
4760 ExprP<Matrix<T, Rows, Cols> > outerProduct (const ExprP<Vector<T, Rows> >& left,
4761 const ExprP<Vector<T, Cols> >& right)
4763 return app<OuterProduct<Rows, Cols, T> >(left, right);
4767 class DeterminantBase : public DerivedFunc<T>
4770 string getName (void) const { return "determinant"; }
4773 template<int Size> class Determinant;
4774 template<int Size> class Determinant16bit;
4775 template<int Size> class Determinant64bit;
4778 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
4780 return app<Determinant<Size> >(mat);
4784 ExprP<deFloat16> determinant (ExprP<Matrix<deFloat16, Size, Size> > mat)
4786 return app<Determinant16bit<Size> >(mat);
4790 ExprP<double> determinant (ExprP<Matrix<double, Size, Size> > mat)
4792 return app<Determinant64bit<Size> >(mat);
4796 class Determinant<2> : public DeterminantBase<Signature<float, Matrix<float, 2, 2> > >
4799 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
4801 ExprP<Mat2> mat = args.a;
4803 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
4808 class Determinant<3> : public DeterminantBase<Signature<float, Matrix<float, 3, 3> > >
4811 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
4813 ExprP<Mat3> mat = args.a;
4815 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
4816 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
4817 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
4822 class Determinant<4> : public DeterminantBase<Signature<float, Matrix<float, 4, 4> > >
4825 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
4827 ExprP<Mat4> mat = args.a;
4828 ExprP<Mat3> minors[4];
4830 for (int ndx = 0; ndx < 4; ++ndx)
4832 ExprP<Vec4> minorColumns[3];
4833 ExprP<Vec3> columns[3];
4835 for (int col = 0; col < 3; ++col)
4836 minorColumns[col] = mat[col < ndx ? col : col + 1];
4838 for (int col = 0; col < 3; ++col)
4839 columns[col] = vec3(minorColumns[0][col+1],
4840 minorColumns[1][col+1],
4841 minorColumns[2][col+1]);
4843 minors[ndx] = bindExpression("minor", ctx,
4844 mat3(columns[0], columns[1], columns[2]));
4847 return (mat[0][0] * determinant(minors[0]) -
4848 mat[1][0] * determinant(minors[1]) +
4849 mat[2][0] * determinant(minors[2]) -
4850 mat[3][0] * determinant(minors[3]));
4855 class Determinant16bit<2> : public DeterminantBase<Signature<deFloat16, Matrix<deFloat16, 2, 2> > >
4858 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
4860 ExprP<Mat2_16b> mat = args.a;
4862 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
4867 class Determinant16bit<3> : public DeterminantBase<Signature<deFloat16, Matrix<deFloat16, 3, 3> > >
4870 ExprP<Ret> doExpand(ExpandContext&, const ArgExprs& args) const
4872 ExprP<Mat3_16b> mat = args.a;
4874 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
4875 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
4876 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
4881 class Determinant16bit<4> : public DeterminantBase<Signature<deFloat16, Matrix<deFloat16, 4, 4> > >
4884 ExprP<Ret> doExpand(ExpandContext& ctx, const ArgExprs& args) const
4886 ExprP<Mat4_16b> mat = args.a;
4887 ExprP<Mat3_16b> minors[4];
4889 for (int ndx = 0; ndx < 4; ++ndx)
4891 ExprP<Vec4_16Bit> minorColumns[3];
4892 ExprP<Vec3_16Bit> columns[3];
4894 for (int col = 0; col < 3; ++col)
4895 minorColumns[col] = mat[col < ndx ? col : col + 1];
4897 for (int col = 0; col < 3; ++col)
4898 columns[col] = vec3(minorColumns[0][col + 1],
4899 minorColumns[1][col + 1],
4900 minorColumns[2][col + 1]);
4902 minors[ndx] = bindExpression("minor", ctx,
4903 mat3(columns[0], columns[1], columns[2]));
4906 return (mat[0][0] * determinant(minors[0]) -
4907 mat[1][0] * determinant(minors[1]) +
4908 mat[2][0] * determinant(minors[2]) -
4909 mat[3][0] * determinant(minors[3]));
4914 class Determinant64bit<2> : public DeterminantBase<Signature<double, Matrix<double, 2, 2> > >
4917 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
4919 ExprP<Matrix2d> mat = args.a;
4921 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
4926 class Determinant64bit<3> : public DeterminantBase<Signature<double, Matrix<double, 3, 3> > >
4929 ExprP<Ret> doExpand(ExpandContext&, const ArgExprs& args) const
4931 ExprP<Matrix3d> mat = args.a;
4933 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
4934 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
4935 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
4940 class Determinant64bit<4> : public DeterminantBase<Signature<double, Matrix<double, 4, 4> > >
4943 ExprP<Ret> doExpand(ExpandContext& ctx, const ArgExprs& args) const
4945 ExprP<Matrix4d> mat = args.a;
4946 ExprP<Matrix3d> minors[4];
4948 for (int ndx = 0; ndx < 4; ++ndx)
4950 ExprP<Vec4_64Bit> minorColumns[3];
4951 ExprP<Vec3_64Bit> columns[3];
4953 for (int col = 0; col < 3; ++col)
4954 minorColumns[col] = mat[col < ndx ? col : col + 1];
4956 for (int col = 0; col < 3; ++col)
4957 columns[col] = vec3(minorColumns[0][col + 1],
4958 minorColumns[1][col + 1],
4959 minorColumns[2][col + 1]);
4961 minors[ndx] = bindExpression("minor", ctx,
4962 mat3(columns[0], columns[1], columns[2]));
4965 return (mat[0][0] * determinant(minors[0]) -
4966 mat[1][0] * determinant(minors[1]) +
4967 mat[2][0] * determinant(minors[2]) -
4968 mat[3][0] * determinant(minors[3]));
4972 template<int Size> class Inverse;
4975 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
4977 return app<Inverse<Size> >(mat);
4980 template<int Size> class Inverse16bit;
4983 ExprP<Matrix<deFloat16, Size, Size> > inverse (ExprP<Matrix<deFloat16, Size, Size> > mat)
4985 return app<Inverse16bit<Size> >(mat);
4988 template<int Size> class Inverse64bit;
4991 ExprP<Matrix<double, Size, Size> > inverse (ExprP<Matrix<double, Size, Size> > mat)
4993 return app<Inverse64bit<Size> >(mat);
4997 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
5000 string getName (void) const
5006 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
5008 ExprP<Mat2> mat = args.a;
5009 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
5011 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
5012 vec2(-mat[1][0] / det, mat[0][0] / det));
5017 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
5020 string getName (void) const
5026 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
5028 ExprP<Mat3> mat = args.a;
5029 ExprP<Mat2> invA = bindExpression("invA", ctx,
5030 inverse(mat2(vec2(mat[0][0], mat[0][1]),
5031 vec2(mat[1][0], mat[1][1]))));
5033 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
5034 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
5035 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
5037 ExprP<float> schur = bindExpression("schur", ctx,
5039 (matD - dot(matC * invA, matB)));
5041 ExprP<Vec2> t1 = invA * matB;
5042 ExprP<Vec2> t2 = t1 * schur;
5043 ExprP<Mat2> t3 = outerProduct(t2, matC);
5044 ExprP<Mat2> t4 = t3 * invA;
5045 ExprP<Mat2> t5 = invA + t4;
5046 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
5047 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
5048 (invA * matB) * -schur);
5049 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
5050 (matC * invA) * -schur);
5052 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
5053 vec3(blockA[1][0], blockA[1][1], blockC[1]),
5054 vec3(blockB[0], blockB[1], schur));
5059 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
5062 string getName (void) const { return "inverse"; }
5065 ExprP<Ret> doExpand (ExpandContext& ctx,
5066 const ArgExprs& args) const
5068 ExprP<Mat4> mat = args.a;
5069 ExprP<Mat2> invA = bindExpression("invA", ctx,
5070 inverse(mat2(vec2(mat[0][0], mat[0][1]),
5071 vec2(mat[1][0], mat[1][1]))));
5072 ExprP<Mat2> matB = bindExpression("matB", ctx,
5073 mat2(vec2(mat[2][0], mat[2][1]),
5074 vec2(mat[3][0], mat[3][1])));
5075 ExprP<Mat2> matC = bindExpression("matC", ctx,
5076 mat2(vec2(mat[0][2], mat[0][3]),
5077 vec2(mat[1][2], mat[1][3])));
5078 ExprP<Mat2> matD = bindExpression("matD", ctx,
5079 mat2(vec2(mat[2][2], mat[2][3]),
5080 vec2(mat[3][2], mat[3][3])));
5081 ExprP<Mat2> schur = bindExpression("schur", ctx,
5082 inverse(matD + -(matC * invA * matB)));
5083 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
5084 invA + (invA * matB * schur * matC * invA));
5085 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
5086 (-invA) * matB * schur);
5087 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
5088 (-schur) * matC * invA);
5090 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
5091 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
5092 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
5093 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
5098 class Inverse16bit<2> : public DerivedFunc<Signature<Mat2_16b, Mat2_16b> >
5101 string getName (void) const
5107 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
5109 ExprP<Mat2_16b> mat = args.a;
5110 ExprP<deFloat16> det = bindExpression("det", ctx, determinant(mat));
5112 return mat2(vec2((mat[1][1] / det), (-mat[0][1] / det)),
5113 vec2((-mat[1][0] / det), (mat[0][0] / det)));
5118 class Inverse16bit<3> : public DerivedFunc<Signature<Mat3_16b, Mat3_16b> >
5121 string getName(void) const
5127 ExprP<Ret> doExpand(ExpandContext& ctx, const ArgExprs& args) const
5129 ExprP<Mat3_16b> mat = args.a;
5130 ExprP<Mat2_16b> invA = bindExpression("invA", ctx,
5131 inverse(mat2(vec2(mat[0][0], mat[0][1]),
5132 vec2(mat[1][0], mat[1][1]))));
5134 ExprP<Vec2_16Bit> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
5135 ExprP<Vec2_16Bit> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
5136 ExprP<Mat3_16b::Scalar> matD = bindExpression("matD", ctx, mat[2][2]);
5138 ExprP<Mat3_16b::Scalar> schur = bindExpression("schur", ctx,
5139 constant((deFloat16)FLOAT16_1_0) /
5140 (matD - dot(matC * invA, matB)));
5142 ExprP<Vec2_16Bit> t1 = invA * matB;
5143 ExprP<Vec2_16Bit> t2 = t1 * schur;
5144 ExprP<Mat2_16b> t3 = outerProduct(t2, matC);
5145 ExprP<Mat2_16b> t4 = t3 * invA;
5146 ExprP<Mat2_16b> t5 = invA + t4;
5147 ExprP<Mat2_16b> blockA = bindExpression("blockA", ctx, t5);
5148 ExprP<Vec2_16Bit> blockB = bindExpression("blockB", ctx,
5149 (invA * matB) * -schur);
5150 ExprP<Vec2_16Bit> blockC = bindExpression("blockC", ctx,
5151 (matC * invA) * -schur);
5153 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
5154 vec3(blockA[1][0], blockA[1][1], blockC[1]),
5155 vec3(blockB[0], blockB[1], schur));
5160 class Inverse16bit<4> : public DerivedFunc<Signature<Mat4_16b, Mat4_16b> >
5163 string getName(void) const { return "inverse"; }
5166 ExprP<Ret> doExpand(ExpandContext& ctx,
5167 const ArgExprs& args) const
5169 ExprP<Mat4_16b> mat = args.a;
5170 ExprP<Mat2_16b> invA = bindExpression("invA", ctx,
5171 inverse(mat2(vec2(mat[0][0], mat[0][1]),
5172 vec2(mat[1][0], mat[1][1]))));
5173 ExprP<Mat2_16b> matB = bindExpression("matB", ctx,
5174 mat2(vec2(mat[2][0], mat[2][1]),
5175 vec2(mat[3][0], mat[3][1])));
5176 ExprP<Mat2_16b> matC = bindExpression("matC", ctx,
5177 mat2(vec2(mat[0][2], mat[0][3]),
5178 vec2(mat[1][2], mat[1][3])));
5179 ExprP<Mat2_16b> matD = bindExpression("matD", ctx,
5180 mat2(vec2(mat[2][2], mat[2][3]),
5181 vec2(mat[3][2], mat[3][3])));
5182 ExprP<Mat2_16b> schur = bindExpression("schur", ctx,
5183 inverse(matD + -(matC * invA * matB)));
5184 ExprP<Mat2_16b> blockA = bindExpression("blockA", ctx,
5185 invA + (invA * matB * schur * matC * invA));
5186 ExprP<Mat2_16b> blockB = bindExpression("blockB", ctx,
5187 (-invA) * matB * schur);
5188 ExprP<Mat2_16b> blockC = bindExpression("blockC", ctx,
5189 (-schur) * matC * invA);
5191 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
5192 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
5193 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
5194 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
5199 class Inverse64bit<2> : public DerivedFunc<Signature<Matrix2d, Matrix2d> >
5202 string getName (void) const
5208 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
5210 ExprP<Matrix2d> mat = args.a;
5211 ExprP<double> det = bindExpression("det", ctx, determinant(mat));
5213 return mat2(vec2((mat[1][1] / det), (-mat[0][1] / det)),
5214 vec2((-mat[1][0] / det), (mat[0][0] / det)));
5219 class Inverse64bit<3> : public DerivedFunc<Signature<Matrix3d, Matrix3d> >
5222 string getName(void) const
5228 ExprP<Ret> doExpand(ExpandContext& ctx, const ArgExprs& args) const
5230 ExprP<Matrix3d> mat = args.a;
5231 ExprP<Matrix2d> invA = bindExpression("invA", ctx,
5232 inverse(mat2(vec2(mat[0][0], mat[0][1]),
5233 vec2(mat[1][0], mat[1][1]))));
5235 ExprP<Vec2_64Bit> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
5236 ExprP<Vec2_64Bit> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
5237 ExprP<Matrix3d::Scalar> matD = bindExpression("matD", ctx, mat[2][2]);
5239 ExprP<Matrix3d::Scalar> schur = bindExpression("schur", ctx,
5241 (matD - dot(matC * invA, matB)));
5243 ExprP<Vec2_64Bit> t1 = invA * matB;
5244 ExprP<Vec2_64Bit> t2 = t1 * schur;
5245 ExprP<Matrix2d> t3 = outerProduct(t2, matC);
5246 ExprP<Matrix2d> t4 = t3 * invA;
5247 ExprP<Matrix2d> t5 = invA + t4;
5248 ExprP<Matrix2d> blockA = bindExpression("blockA", ctx, t5);
5249 ExprP<Vec2_64Bit> blockB = bindExpression("blockB", ctx,
5250 (invA * matB) * -schur);
5251 ExprP<Vec2_64Bit> blockC = bindExpression("blockC", ctx,
5252 (matC * invA) * -schur);
5254 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
5255 vec3(blockA[1][0], blockA[1][1], blockC[1]),
5256 vec3(blockB[0], blockB[1], schur));
5261 class Inverse64bit<4> : public DerivedFunc<Signature<Matrix4d, Matrix4d> >
5264 string getName(void) const { return "inverse"; }
5267 ExprP<Ret> doExpand(ExpandContext& ctx,
5268 const ArgExprs& args) const
5270 ExprP<Matrix4d> mat = args.a;
5271 ExprP<Matrix2d> invA = bindExpression("invA", ctx,
5272 inverse(mat2(vec2(mat[0][0], mat[0][1]),
5273 vec2(mat[1][0], mat[1][1]))));
5274 ExprP<Matrix2d> matB = bindExpression("matB", ctx,
5275 mat2(vec2(mat[2][0], mat[2][1]),
5276 vec2(mat[3][0], mat[3][1])));
5277 ExprP<Matrix2d> matC = bindExpression("matC", ctx,
5278 mat2(vec2(mat[0][2], mat[0][3]),
5279 vec2(mat[1][2], mat[1][3])));
5280 ExprP<Matrix2d> matD = bindExpression("matD", ctx,
5281 mat2(vec2(mat[2][2], mat[2][3]),
5282 vec2(mat[3][2], mat[3][3])));
5283 ExprP<Matrix2d> schur = bindExpression("schur", ctx,
5284 inverse(matD + -(matC * invA * matB)));
5285 ExprP<Matrix2d> blockA = bindExpression("blockA", ctx,
5286 invA + (invA * matB * schur * matC * invA));
5287 ExprP<Matrix2d> blockB = bindExpression("blockB", ctx,
5288 (-invA) * matB * schur);
5289 ExprP<Matrix2d> blockC = bindExpression("blockC", ctx,
5290 (-schur) * matC * invA);
5292 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
5293 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
5294 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
5295 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
5299 //Signature<float, float, float, float>
5300 //Signature<deFloat16, deFloat16, deFloat16, deFloat16>
5301 //Signature<double, double, double, double>
5303 class Fma : public DerivedFunc<T>
5306 typedef typename Fma::ArgExprs ArgExprs;
5307 typedef typename Fma::Ret Ret;
5309 string getName (void) const
5315 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& x) const
5317 return x.a * x.b + x.c;
5323 using namespace Functions;
5325 template <typename T>
5326 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
5328 return Functions::getComponent(exprP<T>(*this), i);
5331 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
5333 return app<Add< Signature<float, float, float> > >(arg0, arg1);
5336 ExprP<deFloat16> operator+ (const ExprP<deFloat16>& arg0, const ExprP<deFloat16>& arg1)
5338 return app<Add< Signature<deFloat16, deFloat16, deFloat16> > >(arg0, arg1);
5341 ExprP<double> operator+ (const ExprP<double>& arg0, const ExprP<double>& arg1)
5343 return app<Add< Signature<double, double, double> > >(arg0, arg1);
5346 template <typename T>
5347 ExprP<T> operator- (const ExprP<T>& arg0, const ExprP<T>& arg1)
5349 return app<Sub <Signature <T,T,T> > >(arg0, arg1);
5352 template <typename T>
5353 ExprP<T> operator- (const ExprP<T>& arg0)
5355 return app<Negate< Signature<T, T> > >(arg0);
5358 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
5360 return app<Mul< Signature<float, float, float> > >(arg0, arg1);
5363 ExprP<deFloat16> operator* (const ExprP<deFloat16>& arg0, const ExprP<deFloat16>& arg1)
5365 return app<Mul< Signature<deFloat16, deFloat16, deFloat16> > >(arg0, arg1);
5368 ExprP<double> operator* (const ExprP<double>& arg0, const ExprP<double>& arg1)
5370 return app<Mul< Signature<double, double, double> > >(arg0, arg1);
5373 template <typename T>
5374 ExprP<T> operator/ (const ExprP<T>& arg0, const ExprP<T>& arg1)
5376 return app<Div< Signature<T, T, T> > >(arg0, arg1);
5380 template <typename Sig_, int Size>
5381 class GenFunc : public PrimitiveFunc<Signature<
5382 typename ContainerOf<typename Sig_::Ret, Size>::Container,
5383 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
5384 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
5385 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
5386 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
5389 typedef typename GenFunc::IArgs IArgs;
5390 typedef typename GenFunc::IRet IRet;
5392 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
5394 SpirVCaseT getSpirvCase (void) const
5396 return m_func.getSpirvCase();
5399 string getName (void) const
5401 return m_func.getName();
5404 int getOutParamIndex (void) const
5406 return m_func.getOutParamIndex();
5409 string getRequiredExtension (void) const
5411 return m_func.getRequiredExtension();
5414 Interval getInputRange (const bool is16bit) const
5416 return m_func.getInputRange(is16bit);
5420 void doPrint (ostream& os, const BaseArgExprs& args) const
5422 m_func.print(os, args);
5425 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
5429 for (int ndx = 0; ndx < Size; ++ndx)
5432 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
5438 IRet doFail (const EvalContext& ctx, const IArgs& iargs) const
5442 for (int ndx = 0; ndx < Size; ++ndx)
5445 m_func.fail(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
5451 void doGetUsedFuncs (FuncSet& dst) const
5453 m_func.getUsedFuncs(dst);
5456 const Func<Sig_>& m_func;
5459 template <typename F, int Size>
5460 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
5463 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
5466 template <typename Sig_, int Size>
5467 class FixedGenFunc : public PrimitiveFunc <Signature<
5468 typename ContainerOf<typename Sig_::Ret, Size>::Container,
5469 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
5470 typename Sig_::Arg1,
5471 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
5472 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
5475 typedef typename FixedGenFunc::IArgs IArgs;
5476 typedef typename FixedGenFunc::IRet IRet;
5478 string getName (void) const
5480 return this->doGetScalarFunc().getName();
5483 SpirVCaseT getSpirvCase (void) const
5485 return this->doGetScalarFunc().getSpirvCase();
5489 void doPrint (ostream& os, const BaseArgExprs& args) const
5491 this->doGetScalarFunc().print(os, args);
5494 IRet doApply (const EvalContext& ctx,
5495 const IArgs& iargs) const
5498 const Func<Sig_>& func = this->doGetScalarFunc();
5500 for (int ndx = 0; ndx < Size; ++ndx)
5501 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
5506 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
5509 template <typename F, int Size>
5510 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
5513 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
5516 template<typename Sig>
5519 GenFuncs (const Func<Sig>& func_,
5520 const GenFunc<Sig, 2>& func2_,
5521 const GenFunc<Sig, 3>& func3_,
5522 const GenFunc<Sig, 4>& func4_)
5529 const Func<Sig>& func;
5530 const GenFunc<Sig, 2>& func2;
5531 const GenFunc<Sig, 3>& func3;
5532 const GenFunc<Sig, 4>& func4;
5535 template<typename F>
5536 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
5538 return GenFuncs<typename F::Sig>(instance<F>(),
5539 instance<VectorizedFunc<F, 2> >(),
5540 instance<VectorizedFunc<F, 3> >(),
5541 instance<VectorizedFunc<F, 4> >());
5544 template<typename T, int Size>
5545 ExprP<Vector<T, Size> > operator/(const ExprP<Vector<T, Size> >& arg0,
5546 const ExprP<T>& arg1)
5548 return app<FixedVecFunc<Div< Signature<T, T, T> >, Size> >(arg0, arg1);
5551 template<typename T, int Size>
5552 ExprP<Vector<T, Size> > operator-(const ExprP<Vector<T, Size> >& arg0)
5554 return app<VectorizedFunc<Negate< Signature<T, T> >, Size> >(arg0);
5557 template<typename T, int Size>
5558 ExprP<Vector<T, Size> > operator-(const ExprP<Vector<T, Size> >& arg0,
5559 const ExprP<Vector<T, Size> >& arg1)
5561 return app<VectorizedFunc<Sub<Signature<T, T, T> >, Size> >(arg0, arg1);
5564 template<int Size, typename T>
5565 ExprP<Vector<T, Size> > operator*(const ExprP<Vector<T, Size> >& arg0,
5566 const ExprP<T>& arg1)
5568 return app<FixedVecFunc<Mul< Signature<T, T, T> >, Size> >(arg0, arg1);
5571 template<typename T, int Size>
5572 ExprP<Vector<T, Size> > operator*(const ExprP<Vector<T, Size> >& arg0,
5573 const ExprP<Vector<T, Size> >& arg1)
5575 return app<VectorizedFunc<Mul< Signature<T, T, T> >, Size> >(arg0, arg1);
5578 template<int LeftRows, int Middle, int RightCols, typename T>
5579 ExprP<Matrix<T, LeftRows, RightCols> >
5580 operator* (const ExprP<Matrix<T, LeftRows, Middle> >& left,
5581 const ExprP<Matrix<T, Middle, RightCols> >& right)
5583 return app<MatMul<T, LeftRows, Middle, RightCols> >(left, right);
5586 template<int Rows, int Cols, typename T>
5587 ExprP<Vector<T, Rows> > operator* (const ExprP<Vector<T, Cols> >& left,
5588 const ExprP<Matrix<T, Rows, Cols> >& right)
5590 return app<VecMatMul<T, Rows, Cols> >(left, right);
5593 template<int Rows, int Cols, class T>
5594 ExprP<Vector<T, Cols> > operator* (const ExprP<Matrix<T, Rows, Cols> >& left,
5595 const ExprP<Vector<T, Rows> >& right)
5597 return app<MatVecMul<Rows, Cols, T> >(left, right);
5600 template<int Rows, int Cols, typename T>
5601 ExprP<Matrix<T, Rows, Cols> > operator* (const ExprP<Matrix<T, Rows, Cols> >& left,
5602 const ExprP<T>& right)
5604 return app<ScalarMatFunc<Mul< Signature<T, T, T> >, Rows, Cols> >(left, right);
5607 template<int Rows, int Cols>
5608 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
5609 const ExprP<Matrix<float, Rows, Cols> >& right)
5611 return app<CompMatFunc<Add< Signature<float, float, float> >,float, Rows, Cols> >(left, right);
5614 template<int Rows, int Cols>
5615 ExprP<Matrix<deFloat16, Rows, Cols> > operator+ (const ExprP<Matrix<deFloat16, Rows, Cols> >& left,
5616 const ExprP<Matrix<deFloat16, Rows, Cols> >& right)
5618 return app<CompMatFunc<Add< Signature<deFloat16, deFloat16, deFloat16> >, deFloat16, Rows, Cols> >(left, right);
5621 template<int Rows, int Cols>
5622 ExprP<Matrix<double, Rows, Cols> > operator+ (const ExprP<Matrix<double, Rows, Cols> >& left,
5623 const ExprP<Matrix<double, Rows, Cols> >& right)
5625 return app<CompMatFunc<Add< Signature<double, double, double> >, double, Rows, Cols> >(left, right);
5628 template<typename T, int Rows, int Cols>
5629 ExprP<Matrix<T, Rows, Cols> > operator- (const ExprP<Matrix<T, Rows, Cols> >& mat)
5631 return app<MatNeg<T, Rows, Cols> >(mat);
5634 template <typename T>
5638 virtual void genFixeds (const FloatFormat&, const Precision, vector<T>&, const Interval&) const {}
5639 virtual T genRandom (const FloatFormat&,const Precision, Random&, const Interval&) const { return T(); }
5640 virtual void removeNotInRange (vector<T>&, const Interval&, const Precision) const {}
5644 class DefaultSampling<Void> : public Sampling<Void>
5647 void genFixeds (const FloatFormat&, const Precision, vector<Void>& dst, const Interval&) const { dst.push_back(Void()); }
5651 class DefaultSampling<bool> : public Sampling<bool>
5654 void genFixeds (const FloatFormat&, const Precision, vector<bool>& dst, const Interval&) const
5656 dst.push_back(true);
5657 dst.push_back(false);
5662 class DefaultSampling<int> : public Sampling<int>
5665 int genRandom (const FloatFormat&, const Precision prec, Random& rnd, const Interval&) const
5667 const int exp = rnd.getInt(0, getNumBits(prec)-2);
5668 const int sign = rnd.getBool() ? -1 : 1;
5670 return sign * rnd.getInt(0, (deInt32)1 << exp);
5673 void genFixeds (const FloatFormat&, const Precision, vector<int>& dst, const Interval&) const
5681 static inline int getNumBits (Precision prec)
5685 case glu::PRECISION_LAST:
5686 case glu::PRECISION_MEDIUMP: return 16;
5687 case glu::PRECISION_HIGHP: return 32;
5696 class DefaultSampling<float> : public Sampling<float>
5699 float genRandom (const FloatFormat& format, const Precision prec, Random& rnd, const Interval& inputRange) const;
5700 void genFixeds (const FloatFormat& format, const Precision prec, vector<float>& dst, const Interval& inputRange) const;
5701 void removeNotInRange (vector<float>& dst, const Interval& inputRange, const Precision prec) const;
5705 class DefaultSampling<double> : public Sampling<double>
5708 double genRandom (const FloatFormat& format, const Precision prec, Random& rnd, const Interval& inputRange) const;
5709 void genFixeds (const FloatFormat& format, const Precision prec, vector<double>& dst, const Interval& inputRange) const;
5710 void removeNotInRange (vector<double>& dst, const Interval& inputRange, const Precision prec) const;
5713 static bool isDenorm16(deFloat16 v)
5715 const deUint16 mantissa = 0x03FF;
5716 const deUint16 exponent = 0x7C00;
5717 return ((exponent & v) == 0 && (mantissa & v) != 0);
5720 //! Generate a random double from a reasonable general-purpose distribution.
5721 double randomDouble(const FloatFormat& format, Random& rnd, const Interval& inputRange)
5723 // No testing of subnormals. TODO: Could integrate float controls for some operations.
5724 const int minExp = format.getMinExp();
5725 const int maxExp = format.getMaxExp();
5726 const bool haveSubnormal = false;
5727 const double midpoint = inputRange.midpoint();
5729 // Choose exponent so that the cumulative distribution is cubic.
5730 // This makes the probability distribution quadratic, with the peak centered on zero.
5731 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
5732 const double maxRoot = deCbrt(maxExp + 0.5);
5733 const int fractionBits = format.getFractionBits();
5734 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot), 3.0)));
5736 // Generate some occasional special numbers
5737 switch (rnd.getInt(0, 64))
5739 case 0: return inputRange.contains(0) ? 0 : midpoint;
5740 case 1: return inputRange.contains(TCU_INFINITY) ? TCU_INFINITY : midpoint;
5741 case 2: return inputRange.contains(-TCU_INFINITY) ? -TCU_INFINITY : midpoint;
5742 case 3: return inputRange.contains(TCU_NAN) ? TCU_NAN : midpoint;
5746 DE_ASSERT(fractionBits < std::numeric_limits<double>::digits);
5749 double base = deLdExp(1.0, exp);
5750 double quantum = deLdExp(1.0, exp - fractionBits); // smallest representable difference in the binade
5751 double significand = 0.0;
5752 switch (rnd.getInt(0, 16))
5754 case 0: // The highest number in this binade, significand is all bits one.
5755 significand = base - quantum;
5757 case 1: // Significand is one.
5758 significand = quantum;
5760 case 2: // Significand is zero.
5763 default: // Random (evenly distributed) significand.
5765 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
5766 significand = double(intFraction) * quantum;
5770 // Produce positive numbers more often than negative.
5771 double value = (rnd.getInt(0, 3) == 0 ? -1.0 : 1.0) * (base + significand);
5772 return inputRange.contains(value) ? value : midpoint;
5775 //! Generate a random float from a reasonable general-purpose distribution.
5776 float DefaultSampling<float>::genRandom (const FloatFormat& format,
5779 const Interval& inputRange) const
5782 return (float)randomDouble(format, rnd, inputRange);
5785 //! Generate a standard set of floats that should always be tested.
5786 void DefaultSampling<float>::genFixeds (const FloatFormat& format, const Precision prec, vector<float>& dst, const Interval& inputRange) const
5788 const int minExp = format.getMinExp();
5789 const int maxExp = format.getMaxExp();
5790 const int fractionBits = format.getFractionBits();
5791 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
5792 const float minNormalized = deFloatLdExp(1.0f, minExp);
5793 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
5796 dst.push_back(TCU_NAN);
5798 dst.push_back(0.0f);
5800 for (int sign = -1; sign <= 1; sign += 2)
5802 // Smallest normalized
5803 dst.push_back((float)sign * minNormalized);
5805 // Next smallest normalized
5806 dst.push_back((float)sign * (minNormalized + minQuantum));
5808 dst.push_back((float)sign * 0.5f);
5809 dst.push_back((float)sign * 1.0f);
5810 dst.push_back((float)sign * 2.0f);
5813 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
5814 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
5816 dst.push_back((float)sign * TCU_INFINITY);
5818 removeNotInRange(dst, inputRange, prec);
5821 void DefaultSampling<float>::removeNotInRange (vector<float>& dst, const Interval& inputRange, const Precision prec) const
5823 for (vector<float>::iterator it = dst.begin(); it < dst.end();)
5825 // Remove out of range values. PRECISION_LAST means this is an FP16 test so remove any values that
5826 // will be denorms when converted to FP16. (This is used in the precision_fp16_storage32b test group).
5827 if ( !inputRange.contains(static_cast<double>(*it)) || (prec == glu::PRECISION_LAST && isDenorm16(deFloat32To16Round(*it, DE_ROUNDINGMODE_TO_ZERO))))
5834 //! Generate a random double from a reasonable general-purpose distribution.
5835 double DefaultSampling<double>::genRandom (const FloatFormat& format,
5838 const Interval& inputRange) const
5841 return randomDouble(format, rnd, inputRange);
5844 //! Generate a standard set of floats that should always be tested.
5845 void DefaultSampling<double>::genFixeds (const FloatFormat& format, const Precision prec, vector<double>& dst, const Interval& inputRange) const
5847 const int minExp = format.getMinExp();
5848 const int maxExp = format.getMaxExp();
5849 const int fractionBits = format.getFractionBits();
5850 const double minQuantum = deLdExp(1.0, minExp - fractionBits);
5851 const double minNormalized = deLdExp(1.0, minExp);
5852 const double maxQuantum = deLdExp(1.0, maxExp - fractionBits);
5855 dst.push_back(TCU_NAN);
5859 for (int sign = -1; sign <= 1; sign += 2)
5861 // Smallest normalized
5862 dst.push_back((double)sign * minNormalized);
5864 // Next smallest normalized
5865 dst.push_back((double)sign * (minNormalized + minQuantum));
5867 dst.push_back((double)sign * 0.5);
5868 dst.push_back((double)sign * 1.0);
5869 dst.push_back((double)sign * 2.0);
5872 dst.push_back((double)sign * (deLdExp(1.0, maxExp) + (deLdExp(1.0, maxExp) - maxQuantum)));
5874 dst.push_back((double)sign * TCU_INFINITY);
5876 removeNotInRange(dst, inputRange, prec);
5879 void DefaultSampling<double>::removeNotInRange (vector<double>& dst, const Interval& inputRange, const Precision) const
5881 for (vector<double>::iterator it = dst.begin(); it < dst.end();)
5883 if ( !inputRange.contains(*it) )
5891 class DefaultSampling<deFloat16> : public Sampling<deFloat16>
5894 deFloat16 genRandom (const FloatFormat& format, const Precision prec, Random& rnd, const Interval& inputRange) const;
5895 void genFixeds (const FloatFormat& format, const Precision prec, vector<deFloat16>& dst, const Interval& inputRange) const;
5897 void removeNotInRange(vector<deFloat16>& dst, const Interval& inputRange, const Precision prec) const;
5900 //! Generate a random float from a reasonable general-purpose distribution.
5901 deFloat16 DefaultSampling<deFloat16>::genRandom (const FloatFormat& format, const Precision prec,
5902 Random& rnd, const Interval& inputRange) const
5905 return deFloat64To16Round(randomDouble(format, rnd, inputRange), DE_ROUNDINGMODE_TO_NEAREST_EVEN);
5908 //! Generate a standard set of floats that should always be tested.
5909 void DefaultSampling<deFloat16>::genFixeds (const FloatFormat& format, const Precision prec, vector<deFloat16>& dst, const Interval& inputRange) const
5911 dst.push_back(deUint16(0x3E00)); //1.5
5912 dst.push_back(deUint16(0x3D00)); //1.25
5913 dst.push_back(deUint16(0x3F00)); //1.75
5915 dst.push_back(deUint16(0x0000));
5916 dst.push_back(deUint16(0x8000));
5918 dst.push_back(deUint16(0x7c00));
5919 dst.push_back(deUint16(0xfc00));
5921 dst.push_back(deUint16(0x7c0f));
5922 dst.push_back(deUint16(0xfc0f));
5924 dst.push_back(deUint16(0x7cf0));
5925 dst.push_back(deUint16(0xfcf0));
5927 dst.push_back(deUint16(0x0401));
5928 dst.push_back(deUint16(0x8401));
5929 // Some normal number
5930 dst.push_back(deUint16(0x14cb));
5931 dst.push_back(deUint16(0x94cb));
5933 const int minExp = format.getMinExp();
5934 const int maxExp = format.getMaxExp();
5935 const int fractionBits = format.getFractionBits();
5936 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
5937 const float minNormalized = deFloatLdExp(1.0f, minExp);
5938 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
5940 for (float sign = -1.0; sign <= 1.0f; sign += 2.0f)
5942 // Smallest normalized
5943 dst.push_back(deFloat32To16Round(sign * minNormalized, DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5945 // Next smallest normalized
5946 dst.push_back(deFloat32To16Round(sign * (minNormalized + minQuantum), DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5948 dst.push_back(deFloat32To16Round(sign * 0.5f, DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5949 dst.push_back(deFloat32To16Round(sign * 1.0f, DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5950 dst.push_back(deFloat32To16Round(sign * 2.0f, DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5953 dst.push_back(deFloat32To16Round(sign * (deFloatLdExp(1.0f, maxExp) +
5954 (deFloatLdExp(1.0f, maxExp) - maxQuantum)), DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5956 dst.push_back(deFloat32To16Round(sign * TCU_INFINITY, DE_ROUNDINGMODE_TO_NEAREST_EVEN));
5958 removeNotInRange(dst, inputRange, prec);
5961 void DefaultSampling<deFloat16>::removeNotInRange(vector<deFloat16>& dst, const Interval& inputRange, const Precision) const
5963 for (vector<deFloat16>::iterator it = dst.begin(); it < dst.end();)
5965 if (inputRange.contains(static_cast<double>(*it)))
5972 template <typename T, int Size>
5973 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
5976 typedef Vector<T, Size> Value;
5978 Value genRandom (const FloatFormat& fmt, const Precision prec, Random& rnd, const Interval& inputRange) const
5982 for (int ndx = 0; ndx < Size; ++ndx)
5983 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd, inputRange);
5988 void genFixeds (const FloatFormat& fmt, const Precision prec, vector<Value>& dst, const Interval& inputRange) const
5992 instance<DefaultSampling<T> >().genFixeds(fmt, prec, scalars, inputRange);
5994 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
5995 dst.push_back(Value(scalars[scalarNdx]));
5999 template <typename T, int Rows, int Columns>
6000 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
6003 typedef Matrix<T, Rows, Columns> Value;
6005 Value genRandom (const FloatFormat& fmt, const Precision prec, Random& rnd, const Interval& inputRange) const
6009 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
6010 for (int colNdx = 0; colNdx < Columns; ++colNdx)
6011 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd, inputRange);
6016 void genFixeds (const FloatFormat& fmt, const Precision prec, vector<Value>& dst, const Interval& inputRange) const
6020 instance<DefaultSampling<T> >().genFixeds(fmt, prec, scalars, inputRange);
6022 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
6023 dst.push_back(Value(scalars[scalarNdx]));
6025 if (Columns == Rows)
6030 for (int ndx = 0; ndx < Columns; ++ndx)
6032 mat[Columns-1-ndx][ndx] = x;
6033 x = static_cast<T>(x * static_cast<T>(2.0f));
6042 CaseContext (const string& name_,
6043 TestContext& testContext_,
6044 const FloatFormat& floatFormat_,
6045 const FloatFormat& highpFormat_,
6046 const Precision precision_,
6047 const ShaderType shaderType_,
6048 const size_t numRandoms_,
6049 const PrecisionTestFeatures precisionTestFeatures_ = PRECISION_TEST_FEATURES_NONE,
6050 const bool isPackFloat16b_ = false,
6051 const bool isFloat64b_ = false)
6053 , testContext (testContext_)
6054 , floatFormat (floatFormat_)
6055 , highpFormat (highpFormat_)
6056 , precision (precision_)
6057 , shaderType (shaderType_)
6058 , numRandoms (numRandoms_)
6059 , inputRange (-TCU_INFINITY, TCU_INFINITY)
6060 , precisionTestFeatures (precisionTestFeatures_)
6061 , isPackFloat16b (isPackFloat16b_)
6062 , isFloat64b (isFloat64b_)
6066 TestContext& testContext;
6067 FloatFormat floatFormat;
6068 FloatFormat highpFormat;
6069 Precision precision;
6070 ShaderType shaderType;
6072 Interval inputRange;
6073 PrecisionTestFeatures precisionTestFeatures;
6074 bool isPackFloat16b;
6078 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
6087 template <typename In>
6088 int numInputs (void)
6090 return (!isTypeValid<typename In::In0>() ? 0 :
6091 !isTypeValid<typename In::In1>() ? 1 :
6092 !isTypeValid<typename In::In2>() ? 2 :
6093 !isTypeValid<typename In::In3>() ? 3 :
6097 template<typename Out0_, typename Out1_ = Void>
6104 template <typename Out>
6105 int numOutputs (void)
6107 return (!isTypeValid<typename Out::Out0>() ? 0 :
6108 !isTypeValid<typename Out::Out1>() ? 1 :
6112 template<typename In>
6115 vector<typename In::In0> in0;
6116 vector<typename In::In1> in1;
6117 vector<typename In::In2> in2;
6118 vector<typename In::In3> in3;
6121 template<typename Out>
6124 Outputs (size_t size) : out0(size), out1(size) {}
6126 vector<typename Out::Out0> out0;
6127 vector<typename Out::Out1> out1;
6130 template<typename In, typename Out>
6133 VariableP<typename In::In0> in0;
6134 VariableP<typename In::In1> in1;
6135 VariableP<typename In::In2> in2;
6136 VariableP<typename In::In3> in3;
6137 VariableP<typename Out::Out0> out0;
6138 VariableP<typename Out::Out1> out1;
6141 template<typename In>
6144 Samplings (const Sampling<typename In::In0>& in0_,
6145 const Sampling<typename In::In1>& in1_,
6146 const Sampling<typename In::In2>& in2_,
6147 const Sampling<typename In::In3>& in3_)
6148 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
6150 const Sampling<typename In::In0>& in0;
6151 const Sampling<typename In::In1>& in1;
6152 const Sampling<typename In::In2>& in2;
6153 const Sampling<typename In::In3>& in3;
6156 template<typename In>
6157 struct DefaultSamplings : Samplings<In>
6159 DefaultSamplings (void)
6160 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
6161 instance<DefaultSampling<typename In::In1> >(),
6162 instance<DefaultSampling<typename In::In2> >(),
6163 instance<DefaultSampling<typename In::In3> >()) {}
6166 template <typename In, typename Out>
6167 class BuiltinPrecisionCaseTestInstance : public TestInstance
6170 BuiltinPrecisionCaseTestInstance (Context& context,
6171 const CaseContext caseCtx,
6172 const ShaderSpec& shaderSpec,
6173 const Variables<In, Out> variables,
6174 const Samplings<In>& samplings,
6175 const StatementP stmt,
6176 bool modularOp = false)
6177 : TestInstance (context)
6178 , m_caseCtx (caseCtx)
6179 , m_variables (variables)
6180 , m_samplings (samplings)
6182 , m_executor (createExecutor(context, caseCtx.shaderType, shaderSpec))
6183 , m_modularOp (modularOp)
6186 virtual tcu::TestStatus iterate (void);
6189 CaseContext m_caseCtx;
6190 Variables<In, Out> m_variables;
6191 const Samplings<In>& m_samplings;
6193 de::UniquePtr<ShaderExecutor> m_executor;
6197 template<class In, class Out>
6198 tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
6200 typedef typename In::In0 In0;
6201 typedef typename In::In1 In1;
6202 typedef typename In::In2 In2;
6203 typedef typename In::In3 In3;
6204 typedef typename Out::Out0 Out0;
6205 typedef typename Out::Out1 Out1;
6207 areFeaturesSupported(m_context, m_caseCtx.precisionTestFeatures);
6208 Inputs<In> inputs = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed(), m_caseCtx.inputRange);
6209 const FloatFormat& fmt = m_caseCtx.floatFormat;
6210 const int inCount = numInputs<In>();
6211 const int outCount = numOutputs<Out>();
6212 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
6213 Outputs<Out> outputs (numValues);
6214 const FloatFormat highpFmt = m_caseCtx.highpFormat;
6215 const int maxMsgs = 100;
6217 Environment env; // Hoisted out of the inner loop for optimization.
6218 ResultCollector status;
6219 TestLog& testLog = m_context.getTestContext().getLog();
6221 // Module operations need exactly two inputs and have exactly one output.
6224 DE_ASSERT(inCount == 2);
6225 DE_ASSERT(outCount == 1);
6228 const void* inputArr[] =
6230 inputs.in0.data(), inputs.in1.data(), inputs.in2.data(), inputs.in3.data(),
6234 outputs.out0.data(), outputs.out1.data(),
6237 // Print out the statement and its definitions
6238 testLog << TestLog::Message << "Statement: " << m_stmt << TestLog::EndMessage;
6243 m_stmt->getUsedFuncs(funcs);
6244 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
6246 (*it)->printDefinition(oss);
6249 testLog << TestLog::Message << "Reference definitions:\n" << oss.str()
6250 << TestLog::EndMessage;
6255 DE_ASSERT(inputs.in3.size() == numValues);
6258 DE_ASSERT(inputs.in2.size() == numValues);
6261 DE_ASSERT(inputs.in1.size() == numValues);
6264 DE_ASSERT(inputs.in0.size() == numValues);
6270 m_executor->execute(int(numValues), inputArr, outputArr);
6272 // Initialize environment with unused values so we don't need to bind in inner loop.
6274 const typename Traits<In0>::IVal in0;
6275 const typename Traits<In1>::IVal in1;
6276 const typename Traits<In2>::IVal in2;
6277 const typename Traits<In3>::IVal in3;
6278 const typename Traits<Out0>::IVal reference0;
6279 const typename Traits<Out1>::IVal reference1;
6281 env.bind(*m_variables.in0, in0);
6282 env.bind(*m_variables.in1, in1);
6283 env.bind(*m_variables.in2, in2);
6284 env.bind(*m_variables.in3, in3);
6285 env.bind(*m_variables.out0, reference0);
6286 env.bind(*m_variables.out1, reference1);
6289 // For each input tuple, compute output reference interval and compare
6290 // shader output to the reference.
6291 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
6294 const bool isInput16Bit = m_executor->areInputs16Bit();
6295 const bool isInput64Bit = m_executor->areInputs64Bit();
6297 DE_ASSERT(!(isInput16Bit && isInput64Bit));
6299 typename Traits<Out0>::IVal reference0;
6300 typename Traits<Out1>::IVal reference1;
6302 if (valueNdx % (size_t)TOUCH_WATCHDOG_VALUE_FREQUENCY == 0)
6303 m_context.getTestContext().touchWatchdog();
6305 env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
6306 env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
6307 env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
6308 env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
6311 EvalContext ctx (fmt, m_caseCtx.precision, env, 0);
6312 m_stmt->execute(ctx);
6317 reference1 = convert<Out1>(highpFmt, env.lookup(*m_variables.out1));
6318 if (!status.check(contains(reference1, outputs.out1[valueNdx], m_caseCtx.isPackFloat16b), "Shader output 1 is outside acceptable range"))
6323 // Pass b from mod(a, b) if we are in the modulo operation.
6324 const tcu::Maybe<In1> modularDivisor = (m_modularOp ? tcu::just(inputs.in1[valueNdx]) : tcu::Nothing);
6326 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
6327 if (!status.check(contains(reference0, outputs.out0[valueNdx], m_caseCtx.isPackFloat16b, modularDivisor), "Shader output 0 is outside acceptable range"))
6329 m_stmt->failed(ctx);
6330 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
6331 if (!status.check(contains(reference0, outputs.out0[valueNdx], m_caseCtx.isPackFloat16b, modularDivisor), "Shader output 0 is outside acceptable range"))
6343 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
6345 MessageBuilder builder = testLog.message();
6347 builder << (result ? "Passed" : "Failed") << " sample:\n";
6351 builder << "\t" << m_variables.in0->getName() << " = "
6352 << (isInput64Bit ? value64ToString(highpFmt, inputs.in0[valueNdx]) : (isInput16Bit ? value16ToString(highpFmt, inputs.in0[valueNdx]) : value32ToString(highpFmt, inputs.in0[valueNdx]))) << "\n";
6357 builder << "\t" << m_variables.in1->getName() << " = "
6358 << (isInput64Bit ? value64ToString(highpFmt, inputs.in1[valueNdx]) : (isInput16Bit ? value16ToString(highpFmt, inputs.in1[valueNdx]) : value32ToString(highpFmt, inputs.in1[valueNdx]))) << "\n";
6363 builder << "\t" << m_variables.in2->getName() << " = "
6364 << (isInput64Bit ? value64ToString(highpFmt, inputs.in2[valueNdx]) : (isInput16Bit ? value16ToString(highpFmt, inputs.in2[valueNdx]) : value32ToString(highpFmt, inputs.in2[valueNdx]))) << "\n";
6369 builder << "\t" << m_variables.in3->getName() << " = "
6370 << (isInput64Bit ? value64ToString(highpFmt, inputs.in3[valueNdx]) : (isInput16Bit ? value16ToString(highpFmt, inputs.in3[valueNdx]) : value32ToString(highpFmt, inputs.in3[valueNdx]))) << "\n";
6375 if (m_executor->spirvCase() == SPIRV_CASETYPE_COMPARE)
6377 builder << "Output:\n"
6378 << comparisonMessage(outputs.out0[valueNdx])
6379 << "Expected result:\n"
6380 << comparisonMessageInterval<typename Out::Out0>(reference0) << "\n";
6384 builder << "\t" << m_variables.out0->getName() << " = "
6385 << (m_executor->isOutput64Bit(0u) ? value64ToString(highpFmt, outputs.out0[valueNdx]) : (m_executor->isOutput16Bit(0u) || m_caseCtx.isPackFloat16b ? value16ToString(highpFmt, outputs.out0[valueNdx]) : value32ToString(highpFmt, outputs.out0[valueNdx]))) << "\n"
6386 << "\tExpected range: "
6387 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
6393 builder << "\t" << m_variables.out1->getName() << " = "
6394 << (m_executor->isOutput64Bit(1u) ? value64ToString(highpFmt, outputs.out1[valueNdx]) : (m_executor->isOutput16Bit(1u) || m_caseCtx.isPackFloat16b ? value16ToString(highpFmt, outputs.out1[valueNdx]) : value32ToString(highpFmt, outputs.out1[valueNdx]))) << "\n"
6395 << "\tExpected range: "
6396 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
6399 builder << TestLog::EndMessage;
6403 if (numErrors > maxMsgs)
6405 testLog << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
6406 << TestLog::EndMessage;
6411 testLog << TestLog::Message << "All " << numValues << " inputs passed."
6412 << TestLog::EndMessage;
6416 testLog << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
6417 << TestLog::EndMessage;
6421 return tcu::TestStatus::fail(de::toString(numErrors) + string(" test failed. Check log for the details"));
6423 return tcu::TestStatus::pass("Pass");
6427 class PrecisionCase : public TestCase
6430 PrecisionCase (const CaseContext& context, const string& name, const Interval& inputRange, const string& extension = "")
6431 : TestCase (context.testContext, name.c_str(), name.c_str())
6433 , m_extension (extension)
6435 m_ctx.inputRange = inputRange;
6436 m_spec.packFloat16Bit = context.isPackFloat16b;
6439 virtual void initPrograms (vk::SourceCollections& programCollection) const
6441 generateSources(m_ctx.shaderType, m_spec, programCollection);
6444 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
6446 template <typename In, typename Out>
6447 void testStatement (const Variables<In, Out>& variables, const Statement& stmt, SpirVCaseT spirvCase);
6449 template<typename T>
6450 Symbol makeSymbol (const Variable<T>& variable)
6452 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
6456 const string m_extension;
6460 template <typename In, typename Out>
6461 void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt, SpirVCaseT spirvCase)
6463 const int inCount = numInputs<In>();
6464 const int outCount = numOutputs<Out>();
6465 Environment env; // Hoisted out of the inner loop for optimization.
6467 // Initialize ShaderSpec from precision, variables and statement.
6468 if (m_ctx.precision != glu::PRECISION_LAST)
6471 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
6472 m_spec.globalDeclarations = os.str();
6475 if (!m_extension.empty())
6476 m_spec.globalDeclarations = "#extension " + m_extension + " : require\n";
6478 m_spec.inputs.resize(inCount);
6483 m_spec.inputs[3] = makeSymbol(*variables.in3);
6486 m_spec.inputs[2] = makeSymbol(*variables.in2);
6489 m_spec.inputs[1] = makeSymbol(*variables.in1);
6492 m_spec.inputs[0] = makeSymbol(*variables.in0);
6498 bool inputs16Bit = false;
6499 for (vector<Symbol>::const_iterator symIter = m_spec.inputs.begin(); symIter != m_spec.inputs.end(); ++symIter)
6500 inputs16Bit = inputs16Bit || glu::isDataTypeFloat16OrVec(symIter->varType.getBasicType());
6502 if (inputs16Bit || m_spec.packFloat16Bit)
6503 m_spec.globalDeclarations += "#extension GL_EXT_shader_explicit_arithmetic_types: require\n";
6505 m_spec.outputs.resize(outCount);
6510 m_spec.outputs[1] = makeSymbol(*variables.out1);
6513 m_spec.outputs[0] = makeSymbol(*variables.out0);
6519 m_spec.source = de::toString(stmt);
6520 m_spec.spirvCase = spirvCase;
6523 template <typename T>
6526 bool operator() (const T& val1, const T& val2) const
6532 template <typename T>
6533 bool inputLess (const T& val1, const T& val2)
6535 return InputLess<T>()(val1, val2);
6539 struct InputLess<float>
6541 bool operator() (const float& val1, const float& val2) const
6551 template <typename T, int Size>
6552 struct InputLess<Vector<T, Size> >
6554 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
6556 for (int ndx = 0; ndx < Size; ++ndx)
6558 if (inputLess(vec1[ndx], vec2[ndx]))
6560 if (inputLess(vec2[ndx], vec1[ndx]))
6568 template <typename T, int Rows, int Cols>
6569 struct InputLess<Matrix<T, Rows, Cols> >
6571 bool operator() (const Matrix<T, Rows, Cols>& mat1,
6572 const Matrix<T, Rows, Cols>& mat2) const
6574 for (int col = 0; col < Cols; ++col)
6576 if (inputLess(mat1[col], mat2[col]))
6578 if (inputLess(mat2[col], mat1[col]))
6586 template <typename In>
6588 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
6590 InTuple (const typename In::In0& in0,
6591 const typename In::In1& in1,
6592 const typename In::In2& in2,
6593 const typename In::In3& in3)
6594 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
6595 (in0, in1, in2, in3) {}
6598 template <typename In>
6599 struct InputLess<InTuple<In> >
6601 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
6603 if (inputLess(in1.a, in2.a))
6605 if (inputLess(in2.a, in1.a))
6607 if (inputLess(in1.b, in2.b))
6609 if (inputLess(in2.b, in1.b))
6611 if (inputLess(in1.c, in2.c))
6613 if (inputLess(in2.c, in1.c))
6615 if (inputLess(in1.d, in2.d))
6621 template<typename In>
6622 Inputs<In> generateInputs (const Samplings<In>& samplings,
6623 const FloatFormat& floatFormat,
6624 Precision intPrecision,
6627 const Interval& inputRange)
6631 Inputs<In> fixedInputs;
6632 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
6634 samplings.in0.genFixeds(floatFormat, intPrecision, fixedInputs.in0, inputRange);
6635 samplings.in1.genFixeds(floatFormat, intPrecision, fixedInputs.in1, inputRange);
6636 samplings.in2.genFixeds(floatFormat, intPrecision, fixedInputs.in2, inputRange);
6637 samplings.in3.genFixeds(floatFormat, intPrecision, fixedInputs.in3, inputRange);
6639 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
6641 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
6643 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
6645 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
6647 const InTuple<In> tuple (fixedInputs.in0[ndx0],
6648 fixedInputs.in1[ndx1],
6649 fixedInputs.in2[ndx2],
6650 fixedInputs.in3[ndx3]);
6652 seenInputs.insert(tuple);
6653 ret.in0.push_back(tuple.a);
6654 ret.in1.push_back(tuple.b);
6655 ret.in2.push_back(tuple.c);
6656 ret.in3.push_back(tuple.d);
6662 for (size_t ndx = 0; ndx < numSamples; ++ndx)
6664 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd, inputRange);
6665 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd, inputRange);
6666 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd, inputRange);
6667 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd, inputRange);
6668 const InTuple<In> tuple (in0, in1, in2, in3);
6670 if (de::contains(seenInputs, tuple))
6673 seenInputs.insert(tuple);
6674 ret.in0.push_back(in0);
6675 ret.in1.push_back(in1);
6676 ret.in2.push_back(in2);
6677 ret.in3.push_back(in3);
6683 class FuncCaseBase : public PrecisionCase
6686 FuncCaseBase (const CaseContext& context, const string& name, const FuncBase& func)
6687 : PrecisionCase (context, name, func.getInputRange(!context.isFloat64b && (context.precision == glu::PRECISION_LAST || context.isPackFloat16b)), func.getRequiredExtension())
6694 template <typename Sig>
6695 class FuncCase : public FuncCaseBase
6698 typedef Func<Sig> CaseFunc;
6699 typedef typename Sig::Ret Ret;
6700 typedef typename Sig::Arg0 Arg0;
6701 typedef typename Sig::Arg1 Arg1;
6702 typedef typename Sig::Arg2 Arg2;
6703 typedef typename Sig::Arg3 Arg3;
6704 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
6705 typedef OutTypes<Ret> Out;
6707 FuncCase (const CaseContext& context, const string& name, const CaseFunc& func, bool modularOp = false)
6708 : FuncCaseBase (context, name, func)
6710 , m_modularOp (modularOp)
6715 virtual TestInstance* createInstance (Context& context) const
6717 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, m_spec, m_variables, getSamplings(), m_stmt, m_modularOp);
6721 void buildTest (void);
6722 virtual const Samplings<In>& getSamplings (void) const
6724 return instance<DefaultSamplings<In> >();
6728 const CaseFunc& m_func;
6729 Variables<In, Out> m_variables;
6733 template <typename Sig>
6734 void FuncCase<Sig>::buildTest (void)
6736 m_variables.out0 = variable<Ret>("out0");
6737 m_variables.out1 = variable<Void>("out1");
6738 m_variables.in0 = variable<Arg0>("in0");
6739 m_variables.in1 = variable<Arg1>("in1");
6740 m_variables.in2 = variable<Arg2>("in2");
6741 m_variables.in3 = variable<Arg3>("in3");
6744 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
6745 m_stmt = variableAssignment(m_variables.out0, expr);
6747 this->testStatement(m_variables, *m_stmt, m_func.getSpirvCase());
6751 template <typename Sig>
6752 class InOutFuncCase : public FuncCaseBase
6755 typedef Func<Sig> CaseFunc;
6756 typedef typename Sig::Ret Ret;
6757 typedef typename Sig::Arg0 Arg0;
6758 typedef typename Sig::Arg1 Arg1;
6759 typedef typename Sig::Arg2 Arg2;
6760 typedef typename Sig::Arg3 Arg3;
6761 typedef InTypes<Arg0, Arg2, Arg3> In;
6762 typedef OutTypes<Ret, Arg1> Out;
6764 InOutFuncCase (const CaseContext& context, const string& name, const CaseFunc& func, bool modularOp = false)
6765 : FuncCaseBase (context, name, func)
6767 , m_modularOp (modularOp)
6771 virtual TestInstance* createInstance (Context& context) const
6773 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, m_spec, m_variables, getSamplings(), m_stmt, m_modularOp);
6777 void buildTest (void);
6778 virtual const Samplings<In>& getSamplings (void) const
6780 return instance<DefaultSamplings<In> >();
6784 const CaseFunc& m_func;
6785 Variables<In, Out> m_variables;
6789 template <typename Sig>
6790 void InOutFuncCase<Sig>::buildTest (void)
6792 m_variables.out0 = variable<Ret>("out0");
6793 m_variables.out1 = variable<Arg1>("out1");
6794 m_variables.in0 = variable<Arg0>("in0");
6795 m_variables.in1 = variable<Arg2>("in1");
6796 m_variables.in2 = variable<Arg3>("in2");
6797 m_variables.in3 = variable<Void>("in3");
6800 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
6801 m_stmt = variableAssignment(m_variables.out0, expr);
6803 this->testStatement(m_variables, *m_stmt, m_func.getSpirvCase());
6807 template <typename Sig>
6808 PrecisionCase* createFuncCase (const CaseContext& context, const string& name, const Func<Sig>& func, bool modularOp = false)
6810 switch (func.getOutParamIndex())
6813 return new FuncCase<Sig>(context, name, func, modularOp);
6815 return new InOutFuncCase<Sig>(context, name, func, modularOp);
6817 DE_FATAL("Impossible");
6825 virtual ~CaseFactory (void) {}
6826 virtual MovePtr<TestNode> createCase (const CaseContext& ctx) const = 0;
6827 virtual string getName (void) const = 0;
6828 virtual string getDesc (void) const = 0;
6831 class FuncCaseFactory : public CaseFactory
6834 virtual const FuncBase& getFunc (void) const = 0;
6835 string getName (void) const { return de::toLower(getFunc().getName()); }
6836 string getDesc (void) const { return "Function '" + getFunc().getName() + "'"; }
6839 template <typename Sig>
6840 class GenFuncCaseFactory : public CaseFactory
6843 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, const string& name, bool modularOp = false)
6845 , m_name (de::toLower(name))
6846 , m_modularOp (modularOp)
6850 MovePtr<TestNode> createCase (const CaseContext& ctx) const
6852 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
6854 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func, m_modularOp));
6855 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2, m_modularOp));
6856 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3, m_modularOp));
6857 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4, m_modularOp));
6858 return MovePtr<TestNode>(group);
6861 string getName (void) const { return m_name; }
6862 string getDesc (void) const { return "Function '" + m_funcs.func.getName() + "'"; }
6865 const GenFuncs<Sig> m_funcs;
6870 template <template <int, class> class GenF, typename T>
6871 class TemplateFuncCaseFactory : public FuncCaseFactory
6874 MovePtr<TestNode> createCase (const CaseContext& ctx) const
6876 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
6878 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1, T> >()));
6879 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2, T> >()));
6880 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3, T> >()));
6881 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4, T> >()));
6883 return MovePtr<TestNode>(group);
6886 const FuncBase& getFunc (void) const { return instance<GenF<1, T> >(); }
6889 #ifndef CTS_USES_VULKANSC
6890 template <template <int> class GenF>
6891 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
6894 MovePtr<TestNode> createCase (const CaseContext& ctx) const
6896 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
6898 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
6900 // There is no defined precision for mediump/RelaxedPrecision in Vulkan
6901 if (ctx.name != "mediump")
6903 static const char dataDir[] = "builtin/precision/square_matrix";
6904 std::string fileName = getFunc().getName() + "_" + ctx.name;
6905 std::vector<std::string> requirements;
6907 if (ctx.name == "compute")
6911 requirements.push_back("Features.shaderFloat64");
6912 fileName += "_fp64";
6916 requirements.push_back("Float16Int8Features.shaderFloat16");
6917 requirements.push_back("VK_KHR_16bit_storage");
6918 requirements.push_back("VK_KHR_storage_buffer_storage_class");
6919 fileName += "_fp16";
6921 if (ctx.isPackFloat16b == true)
6923 fileName += "_32bit";
6927 requirements.push_back("Storage16BitFeatures.storageBuffer16BitAccess");
6932 group->addChild(cts_amber::createAmberTestCase(ctx.testContext, "mat3", "Square matrix 3x3 precision tests", dataDir, fileName + "_mat_3x3.amber", requirements));
6933 group->addChild(cts_amber::createAmberTestCase(ctx.testContext, "mat4", "Square matrix 4x4 precision tests", dataDir, fileName + "_mat_4x4.amber", requirements));
6936 return MovePtr<TestNode>(group);
6939 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
6941 #endif // CTS_USES_VULKANSC
6943 template <template <int, int, class> class GenF, typename T>
6944 class MatrixFuncCaseFactory : public FuncCaseFactory
6947 MovePtr<TestNode> createCase (const CaseContext& ctx) const
6949 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
6951 this->addCase<2, 2>(ctx, group);
6952 this->addCase<3, 2>(ctx, group);
6953 this->addCase<4, 2>(ctx, group);
6954 this->addCase<2, 3>(ctx, group);
6955 this->addCase<3, 3>(ctx, group);
6956 this->addCase<4, 3>(ctx, group);
6957 this->addCase<2, 4>(ctx, group);
6958 this->addCase<3, 4>(ctx, group);
6959 this->addCase<4, 4>(ctx, group);
6961 return MovePtr<TestNode>(group);
6964 const FuncBase& getFunc (void) const { return instance<GenF<2,2, T> >(); }
6967 template <int Rows, int Cols>
6968 void addCase (const CaseContext& ctx, TestCaseGroup* group) const
6970 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
6971 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols, T> >()));
6975 template <typename Sig>
6976 class SimpleFuncCaseFactory : public CaseFactory
6979 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
6981 MovePtr<TestNode> createCase (const CaseContext& ctx) const { return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); }
6982 string getName (void) const { return de::toLower(m_func.getName()); }
6983 string getDesc (void) const { return "Function '" + getName() + "'"; }
6986 const Func<Sig>& m_func;
6989 template <typename F>
6990 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
6992 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
6998 virtual ~CaseFactories (void) {}
6999 virtual const std::vector<const CaseFactory*> getFactories (void) const = 0;
7002 class BuiltinFuncs : public CaseFactories
7005 const vector<const CaseFactory*> getFactories (void) const
7007 vector<const CaseFactory*> ret;
7009 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
7010 ret.push_back(m_factories[ndx].get());
7015 void addFactory (SharedPtr<const CaseFactory> fact) { m_factories.push_back(fact); }
7018 vector<SharedPtr<const CaseFactory> > m_factories;
7021 template <typename F>
7022 void addScalarFactory (BuiltinFuncs& funcs, string name = "", bool modularOp = false)
7025 name = instance<F>().getName();
7027 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name, modularOp)));
7030 MovePtr<const CaseFactories> createBuiltinCases ()
7032 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
7034 // Tests for ES3 builtins
7035 addScalarFactory<Comparison< Signature<int, float, float> > >(*funcs);
7036 addScalarFactory<Add< Signature<float, float, float> > >(*funcs);
7037 addScalarFactory<Sub< Signature<float, float, float> > >(*funcs);
7038 addScalarFactory<Mul< Signature<float, float, float> > >(*funcs);
7039 addScalarFactory<Div< Signature<float, float, float> > >(*funcs);
7041 addScalarFactory<Radians>(*funcs);
7042 addScalarFactory<Degrees>(*funcs);
7043 addScalarFactory<Sin<Signature<float, float> > >(*funcs);
7044 addScalarFactory<Cos<Signature<float, float> > >(*funcs);
7045 addScalarFactory<Tan>(*funcs);
7047 addScalarFactory<ASin>(*funcs);
7048 addScalarFactory<ACos>(*funcs);
7049 addScalarFactory<ATan2< Signature<float, float, float> > >(*funcs, "atan2");
7050 addScalarFactory<ATan<Signature<float, float> > >(*funcs);
7051 addScalarFactory<Sinh>(*funcs);
7052 addScalarFactory<Cosh>(*funcs);
7053 addScalarFactory<Tanh>(*funcs);
7054 addScalarFactory<ASinh>(*funcs);
7055 addScalarFactory<ACosh>(*funcs);
7056 addScalarFactory<ATanh>(*funcs);
7058 addScalarFactory<Pow>(*funcs);
7059 addScalarFactory<Exp<Signature<float, float> > >(*funcs);
7060 addScalarFactory<Log< Signature<float, float> > >(*funcs);
7061 addScalarFactory<Exp2<Signature<float, float> > >(*funcs);
7062 addScalarFactory<Log2< Signature<float, float> > >(*funcs);
7063 addScalarFactory<Sqrt32Bit>(*funcs);
7064 addScalarFactory<InverseSqrt< Signature<float, float> > >(*funcs);
7066 addScalarFactory<Abs< Signature<float, float> > >(*funcs);
7067 addScalarFactory<Sign< Signature<float, float> > >(*funcs);
7068 addScalarFactory<Floor32Bit>(*funcs);
7069 addScalarFactory<Trunc32Bit>(*funcs);
7070 addScalarFactory<Round< Signature<float, float> > >(*funcs);
7071 addScalarFactory<RoundEven< Signature<float, float> > >(*funcs);
7072 addScalarFactory<Ceil< Signature<float, float> > >(*funcs);
7073 addScalarFactory<Fract>(*funcs);
7075 addScalarFactory<Mod32Bit>(*funcs, "mod", true);
7076 addScalarFactory<FRem32Bit>(*funcs);
7078 addScalarFactory<Modf32Bit>(*funcs);
7079 addScalarFactory<ModfStruct32Bit>(*funcs);
7080 addScalarFactory<Min< Signature<float, float, float> > >(*funcs);
7081 addScalarFactory<Max< Signature<float, float, float> > >(*funcs);
7082 addScalarFactory<Clamp< Signature<float, float, float, float> > >(*funcs);
7083 addScalarFactory<Mix>(*funcs);
7084 addScalarFactory<Step< Signature<float, float, float> > >(*funcs);
7085 addScalarFactory<SmoothStep< Signature<float, float, float, float> > >(*funcs);
7087 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length, float>()));
7088 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance, float>()));
7089 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot, float>()));
7090 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
7091 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize, float>()));
7092 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward, float>()));
7093 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect, float>()));
7094 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract, float>()));
7096 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult, float>()));
7097 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct, float>()));
7098 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose, float>()));
7099 #ifndef CTS_USES_VULKANSC
7100 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
7101 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
7102 #endif // CTS_USES_VULKANSC
7104 addScalarFactory<Frexp32Bit>(*funcs);
7105 addScalarFactory<FrexpStruct32Bit>(*funcs);
7106 addScalarFactory<LdExp <Signature<float, float, int> > >(*funcs);
7107 addScalarFactory<Fma <Signature<float, float, float, float> > >(*funcs);
7109 return MovePtr<const CaseFactories>(funcs.release());
7112 MovePtr<const CaseFactories> createBuiltinDoubleCases ()
7114 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
7116 // Tests for ES3 builtins
7117 addScalarFactory<Comparison<Signature<int, double, double>>>(*funcs);
7118 addScalarFactory<Add<Signature<double, double, double>>>(*funcs);
7119 addScalarFactory<Sub<Signature<double, double, double>>>(*funcs);
7120 addScalarFactory<Mul<Signature<double, double, double>>>(*funcs);
7121 addScalarFactory<Div<Signature<double, double, double>>>(*funcs);
7123 // Radians, degrees, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, atan2, pow, exp, log, exp2 and log2
7124 // only work with 16-bit and 32-bit floating point types according to the spec.
7126 addScalarFactory<Radians64>(*funcs);
7127 addScalarFactory<Degrees64>(*funcs);
7128 addScalarFactory<Sin<Signature<double, double>>>(*funcs);
7129 addScalarFactory<Cos<Signature<double, double>>>(*funcs);
7130 addScalarFactory<Tan64Bit>(*funcs);
7131 addScalarFactory<ASin64Bit>(*funcs);
7132 addScalarFactory<ACos64Bit>(*funcs);
7133 addScalarFactory<ATan2<Signature<double, double, double>>>(*funcs, "atan2");
7134 addScalarFactory<ATan<Signature<double, double>>>(*funcs);
7135 addScalarFactory<Sinh64Bit>(*funcs);
7136 addScalarFactory<Cosh64Bit>(*funcs);
7137 addScalarFactory<Tanh64Bit>(*funcs);
7138 addScalarFactory<ASinh64Bit>(*funcs);
7139 addScalarFactory<ACosh64Bit>(*funcs);
7140 addScalarFactory<ATanh64Bit>(*funcs);
7142 addScalarFactory<Pow64>(*funcs);
7143 addScalarFactory<Exp<Signature<double, double>>>(*funcs);
7144 addScalarFactory<Log<Signature<double, double>>>(*funcs);
7145 addScalarFactory<Exp2<Signature<double, double>>>(*funcs);
7146 addScalarFactory<Log2<Signature<double, double>>>(*funcs);
7148 addScalarFactory<Sqrt64Bit>(*funcs);
7149 addScalarFactory<InverseSqrt<Signature<double, double>>>(*funcs);
7151 addScalarFactory<Abs<Signature<double, double>>>(*funcs);
7152 addScalarFactory<Sign<Signature<double, double>>>(*funcs);
7153 addScalarFactory<Floor64Bit>(*funcs);
7154 addScalarFactory<Trunc64Bit>(*funcs);
7155 addScalarFactory<Round<Signature<double, double>>>(*funcs);
7156 addScalarFactory<RoundEven<Signature<double, double>>>(*funcs);
7157 addScalarFactory<Ceil<Signature<double, double>>>(*funcs);
7158 addScalarFactory<Fract64Bit>(*funcs);
7160 addScalarFactory<Mod64Bit>(*funcs, "mod", true);
7161 addScalarFactory<FRem64Bit>(*funcs);
7163 addScalarFactory<Modf64Bit>(*funcs);
7164 addScalarFactory<ModfStruct64Bit>(*funcs);
7165 addScalarFactory<Min<Signature<double, double, double>>>(*funcs);
7166 addScalarFactory<Max<Signature<double, double, double>>>(*funcs);
7167 addScalarFactory<Clamp<Signature<double, double, double, double>>>(*funcs);
7168 addScalarFactory<Mix64Bit>(*funcs);
7169 addScalarFactory<Step<Signature<double, double, double>>>(*funcs);
7170 addScalarFactory<SmoothStep<Signature<double, double, double, double>>>(*funcs);
7172 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length, double>()));
7173 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance, double>()));
7174 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot, double>()));
7175 funcs->addFactory(createSimpleFuncCaseFactory<Cross64Bit>());
7176 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize, double>()));
7177 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward, double>()));
7178 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect, double>()));
7179 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract, double>()));
7181 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult, double>()));
7182 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct, double>()));
7183 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose, double>()));
7184 #ifndef CTS_USES_VULKANSC
7185 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant64bit>()));
7186 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse64bit>()));
7187 #endif // CTS_USES_VULKANSC
7189 addScalarFactory<Frexp64Bit>(*funcs);
7190 addScalarFactory<FrexpStruct64Bit>(*funcs);
7191 addScalarFactory<LdExp<Signature<double, double, int>>>(*funcs);
7192 addScalarFactory<Fma<Signature<double, double, double, double>>>(*funcs);
7194 return MovePtr<const CaseFactories>(funcs.release());
7197 MovePtr<const CaseFactories> createBuiltinCases16Bit(void)
7199 MovePtr<BuiltinFuncs> funcs(new BuiltinFuncs());
7201 addScalarFactory<Comparison< Signature<int, deFloat16, deFloat16> > >(*funcs);
7202 addScalarFactory<Add< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7203 addScalarFactory<Sub< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7204 addScalarFactory<Mul< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7205 addScalarFactory<Div< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7207 addScalarFactory<Radians16>(*funcs);
7208 addScalarFactory<Degrees16>(*funcs);
7210 addScalarFactory<Sin<Signature<deFloat16, deFloat16> > >(*funcs);
7211 addScalarFactory<Cos<Signature<deFloat16, deFloat16> > >(*funcs);
7212 addScalarFactory<Tan16Bit>(*funcs);
7213 addScalarFactory<ASin16Bit>(*funcs);
7214 addScalarFactory<ACos16Bit>(*funcs);
7215 addScalarFactory<ATan2< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs, "atan2");
7216 addScalarFactory<ATan<Signature<deFloat16, deFloat16> > >(*funcs);
7218 addScalarFactory<Sinh16Bit>(*funcs);
7219 addScalarFactory<Cosh16Bit>(*funcs);
7220 addScalarFactory<Tanh16Bit>(*funcs);
7221 addScalarFactory<ASinh16Bit>(*funcs);
7222 addScalarFactory<ACosh16Bit>(*funcs);
7223 addScalarFactory<ATanh16Bit>(*funcs);
7225 addScalarFactory<Pow16>(*funcs);
7226 addScalarFactory<Exp< Signature<deFloat16, deFloat16> > >(*funcs);
7227 addScalarFactory<Log< Signature<deFloat16, deFloat16> > >(*funcs);
7228 addScalarFactory<Exp2< Signature<deFloat16, deFloat16> > >(*funcs);
7229 addScalarFactory<Log2< Signature<deFloat16, deFloat16> > >(*funcs);
7230 addScalarFactory<Sqrt16Bit>(*funcs);
7231 addScalarFactory<InverseSqrt16Bit>(*funcs);
7233 addScalarFactory<Abs< Signature<deFloat16, deFloat16> > >(*funcs);
7234 addScalarFactory<Sign< Signature<deFloat16, deFloat16> > >(*funcs);
7235 addScalarFactory<Floor16Bit>(*funcs);
7236 addScalarFactory<Trunc16Bit>(*funcs);
7237 addScalarFactory<Round< Signature<deFloat16, deFloat16> > >(*funcs);
7238 addScalarFactory<RoundEven< Signature<deFloat16, deFloat16> > >(*funcs);
7239 addScalarFactory<Ceil< Signature<deFloat16, deFloat16> > >(*funcs);
7240 addScalarFactory<Fract16Bit>(*funcs);
7242 addScalarFactory<Mod16Bit>(*funcs, "mod", true);
7243 addScalarFactory<FRem16Bit>(*funcs);
7245 addScalarFactory<Modf16Bit>(*funcs);
7246 addScalarFactory<ModfStruct16Bit>(*funcs);
7247 addScalarFactory<Min< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7248 addScalarFactory<Max< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7249 addScalarFactory<Clamp< Signature<deFloat16, deFloat16, deFloat16, deFloat16> > >(*funcs);
7250 addScalarFactory<Mix16Bit>(*funcs);
7251 addScalarFactory<Step< Signature<deFloat16, deFloat16, deFloat16> > >(*funcs);
7252 addScalarFactory<SmoothStep< Signature<deFloat16, deFloat16, deFloat16, deFloat16> > >(*funcs);
7254 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length, deFloat16>()));
7255 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance, deFloat16>()));
7256 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot, deFloat16>()));
7257 funcs->addFactory(createSimpleFuncCaseFactory<Cross16Bit>());
7258 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize, deFloat16>()));
7259 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward, deFloat16>()));
7260 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect, deFloat16>()));
7261 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract, deFloat16>()));
7263 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct, deFloat16>()));
7264 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose, deFloat16>()));
7265 #ifndef CTS_USES_VULKANSC
7266 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant16bit>()));
7267 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse16bit>()));
7268 #endif // CTS_USES_VULKANSC
7270 addScalarFactory<Frexp16Bit>(*funcs);
7271 addScalarFactory<FrexpStruct16Bit>(*funcs);
7272 addScalarFactory<LdExp <Signature<deFloat16, deFloat16, int> > >(*funcs);
7273 addScalarFactory<Fma <Signature<deFloat16, deFloat16, deFloat16, deFloat16> > >(*funcs);
7275 return MovePtr<const CaseFactories>(funcs.release());
7278 TestCaseGroup* createFuncGroup (TestContext& ctx, const CaseFactory& factory, int numRandoms)
7280 TestCaseGroup* const group = new TestCaseGroup(ctx, factory.getName().c_str(), factory.getDesc().c_str());
7281 const FloatFormat highp (-126, 127, 23, true,
7282 tcu::MAYBE, // subnormals
7283 tcu::YES, // infinities
7285 const FloatFormat mediump (-14, 13, 10, false, tcu::MAYBE);
7287 for (int precNdx = glu::PRECISION_MEDIUMP; precNdx < glu::PRECISION_LAST; ++precNdx)
7289 const Precision precision = Precision(precNdx);
7290 const string precName (glu::getPrecisionName(precision));
7291 const FloatFormat& fmt = precNdx == glu::PRECISION_MEDIUMP ? mediump : highp;
7293 const CaseContext caseCtx (precName, ctx, fmt, highp, precision, glu::SHADERTYPE_COMPUTE, numRandoms);
7295 group->addChild(factory.createCase(caseCtx).release());
7301 TestCaseGroup* createFuncGroupDouble (TestContext& ctx, const CaseFactory& factory, int numRandoms)
7303 TestCaseGroup* const group = new TestCaseGroup(ctx, factory.getName().c_str(), factory.getDesc().c_str());
7304 const Precision precision = Precision(glu::PRECISION_LAST);
7305 const FloatFormat highp (-1022, 1023, 52, true,
7306 tcu::MAYBE, // subnormals
7307 tcu::YES, // infinities
7310 PrecisionTestFeatures precisionTestFeatures = PRECISION_TEST_FEATURES_64BIT_SHADER_FLOAT;
7312 const CaseContext caseCtx("compute", ctx, highp, highp, precision, glu::SHADERTYPE_COMPUTE, numRandoms, precisionTestFeatures, false, true);
7313 group->addChild(factory.createCase(caseCtx).release());
7318 TestCaseGroup* createFuncGroup16Bit(TestContext& ctx, const CaseFactory& factory, int numRandoms, bool storage32)
7320 TestCaseGroup* const group = new TestCaseGroup(ctx, factory.getName().c_str(), factory.getDesc().c_str());
7321 const Precision precision = Precision(glu::PRECISION_LAST);
7322 const FloatFormat float16 (-14, 15, 10, true, tcu::MAYBE);
7324 PrecisionTestFeatures precisionTestFeatures = PRECISION_TEST_FEATURES_16BIT_SHADER_FLOAT;
7326 precisionTestFeatures |= PRECISION_TEST_FEATURES_16BIT_UNIFORM_AND_STORAGE_BUFFER_ACCESS;
7328 const CaseContext caseCtx("compute", ctx, float16, float16, precision, glu::SHADERTYPE_COMPUTE, numRandoms, precisionTestFeatures, storage32);
7329 group->addChild(factory.createCase(caseCtx).release());
7334 const int defRandoms = 16384;
7336 void addBuiltinPrecisionTests (TestContext& ctx,
7337 TestCaseGroup& dstGroup,
7338 const bool test16Bit = false,
7339 const bool storage32Bit = false)
7341 const int userRandoms = ctx.getCommandLine().getTestIterationCount();
7342 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
7344 MovePtr<const CaseFactories> cases = (test16Bit && !storage32Bit) ? createBuiltinCases16Bit()
7345 : createBuiltinCases();
7346 for (size_t ndx = 0; ndx < cases->getFactories().size(); ++ndx)
7349 dstGroup.addChild(createFuncGroup(ctx, *cases->getFactories()[ndx], numRandoms));
7351 dstGroup.addChild(createFuncGroup16Bit(ctx, *cases->getFactories()[ndx], numRandoms, storage32Bit));
7355 void addBuiltinPrecisionDoubleTests (TestContext& ctx,
7356 TestCaseGroup& dstGroup)
7358 const int userRandoms = ctx.getCommandLine().getTestIterationCount();
7359 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
7361 MovePtr<const CaseFactories> cases = createBuiltinDoubleCases();
7362 for (size_t ndx = 0; ndx < cases->getFactories().size(); ++ndx)
7364 dstGroup.addChild(createFuncGroupDouble(ctx, *cases->getFactories()[ndx], numRandoms));
7368 BuiltinPrecisionTests::BuiltinPrecisionTests (tcu::TestContext& testCtx)
7369 : tcu::TestCaseGroup(testCtx, "precision", "Builtin precision tests")
7373 BuiltinPrecisionTests::~BuiltinPrecisionTests (void)
7377 void BuiltinPrecisionTests::init (void)
7379 addBuiltinPrecisionTests(m_testCtx, *this);
7382 BuiltinPrecisionDoubleTests::BuiltinPrecisionDoubleTests (tcu::TestContext& testCtx)
7383 : tcu::TestCaseGroup(testCtx, "precision_double", "Builtin precision tests")
7387 BuiltinPrecisionDoubleTests::~BuiltinPrecisionDoubleTests (void)
7391 void BuiltinPrecisionDoubleTests::init (void)
7393 addBuiltinPrecisionDoubleTests(m_testCtx, *this);
7396 BuiltinPrecision16BitTests::BuiltinPrecision16BitTests (tcu::TestContext& testCtx)
7397 : tcu::TestCaseGroup(testCtx, "precision_fp16_storage16b", "Builtin precision tests")
7401 BuiltinPrecision16BitTests::~BuiltinPrecision16BitTests (void)
7405 void BuiltinPrecision16BitTests::init (void)
7407 addBuiltinPrecisionTests(m_testCtx, *this, true);
7410 BuiltinPrecision16Storage32BitTests::BuiltinPrecision16Storage32BitTests(tcu::TestContext& testCtx)
7411 : tcu::TestCaseGroup(testCtx, "precision_fp16_storage32b", "Builtin precision tests")
7415 BuiltinPrecision16Storage32BitTests::~BuiltinPrecision16Storage32BitTests(void)
7419 void BuiltinPrecision16Storage32BitTests::init(void)
7421 addBuiltinPrecisionTests(m_testCtx, *this, true, true);