xref: /aosp_15_r20/external/deqp/modules/glshared/glsBuiltinPrecisionTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) Module
3  * -----------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Precision and range tests for GLSL builtins and types.
22  *
23  *//*--------------------------------------------------------------------*/
24 
25 #include "glsBuiltinPrecisionTests.hpp"
26 
27 #include "deMath.h"
28 #include "deMemory.h"
29 #include "deDefs.hpp"
30 #include "deRandom.hpp"
31 #include "deSTLUtil.hpp"
32 #include "deStringUtil.hpp"
33 #include "deUniquePtr.hpp"
34 #include "deSharedPtr.hpp"
35 #include "deArrayUtil.hpp"
36 
37 #include "tcuCommandLine.hpp"
38 #include "tcuFloatFormat.hpp"
39 #include "tcuInterval.hpp"
40 #include "tcuTestCase.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuMatrix.hpp"
44 #include "tcuResultCollector.hpp"
45 
46 #include "gluContextInfo.hpp"
47 #include "gluVarType.hpp"
48 #include "gluRenderContext.hpp"
49 #include "glwDefs.hpp"
50 
51 #include "glsShaderExecUtil.hpp"
52 
53 #include <cmath>
54 #include <string>
55 #include <sstream>
56 #include <iostream>
57 #include <map>
58 #include <utility>
59 #include <limits>
60 
61 // Uncomment this to get evaluation trace dumps to std::cerr
62 // #define GLS_ENABLE_TRACE
63 
64 // set this to true to dump even passing results
65 #define GLS_LOG_ALL_RESULTS false
66 
67 enum
68 {
69     // Computing reference intervals can take a non-trivial amount of time, especially on
70     // platforms where toggling floating-point rounding mode is slow (emulated arm on x86).
71     // As a workaround watchdog is kept happy by touching it periodically during reference
72     // interval computation.
73     TOUCH_WATCHDOG_VALUE_FREQUENCY = 4096
74 };
75 
76 namespace deqp
77 {
78 namespace gls
79 {
80 namespace BuiltinPrecisionTests
81 {
82 
83 using std::map;
84 using std::ostream;
85 using std::ostringstream;
86 using std::pair;
87 using std::set;
88 using std::string;
89 using std::vector;
90 
91 using de::MovePtr;
92 using de::Random;
93 using de::SharedPtr;
94 using de::UniquePtr;
95 using tcu::FloatFormat;
96 using tcu::Interval;
97 using tcu::Matrix;
98 using tcu::MessageBuilder;
99 using tcu::TestCase;
100 using tcu::TestLog;
101 using tcu::Vector;
102 namespace matrix = tcu::matrix;
103 using gls::ShaderExecUtil::Symbol;
104 using glu::ContextInfo;
105 using glu::DataType;
106 using glu::Precision;
107 using glu::RenderContext;
108 using glu::ShaderType;
109 using glu::VarType;
110 
111 typedef TestCase::IterateResult IterateResult;
112 
113 using namespace glw;
114 using namespace tcu;
115 
116 /*--------------------------------------------------------------------*//*!
117  * \brief Generic singleton creator.
118  *
119  * instance<T>() returns a reference to a unique default-constructed instance
120  * of T. This is mainly used for our GLSL function implementations: each
121  * function is implemented by an object, and each of the objects has a
122  * distinct class. It would be extremely toilsome to maintain a separate
123  * context object that contained individual instances of the function classes,
124  * so we have to resort to global singleton instances.
125  *
126  *//*--------------------------------------------------------------------*/
127 template <typename T>
instance(void)128 const T &instance(void)
129 {
130     static const T s_instance = T();
131     return s_instance;
132 }
133 
134 /*--------------------------------------------------------------------*//*!
135  * \brief A placeholder type for unused template parameters.
136  *
137  * In the precision tests we are dealing with functions of different arities.
138  * To minimize code duplication, we only define templates with the maximum
139  * number of arguments, currently four. If a function's arity is less than the
140  * maximum, Void us used as the type for unused arguments.
141  *
142  * Although Voids are not used at run-time, they still must be compilable, so
143  * they must support all operations that other types do.
144  *
145  *//*--------------------------------------------------------------------*/
146 struct Void
147 {
148     typedef Void Element;
149     enum
150     {
151         SIZE = 0,
152     };
153 
154     template <typename T>
Voiddeqp::gls::BuiltinPrecisionTests::Void155     explicit Void(const T &)
156     {
157     }
Voiddeqp::gls::BuiltinPrecisionTests::Void158     Void(void)
159     {
160     }
operator doubledeqp::gls::BuiltinPrecisionTests::Void161     operator double(void) const
162     {
163         return TCU_NAN;
164     }
165 
166     // These are used to make Voids usable as containers in container-generic code.
operator []deqp::gls::BuiltinPrecisionTests::Void167     Void &operator[](int)
168     {
169         return *this;
170     }
operator []deqp::gls::BuiltinPrecisionTests::Void171     const Void &operator[](int) const
172     {
173         return *this;
174     }
175 };
176 
operator <<(ostream & os,Void)177 ostream &operator<<(ostream &os, Void)
178 {
179     return os << "()";
180 }
181 
182 //! Returns true for all other types except Void
183 template <typename T>
isTypeValid(void)184 bool isTypeValid(void)
185 {
186     return true;
187 }
188 template <>
isTypeValid(void)189 bool isTypeValid<Void>(void)
190 {
191     return false;
192 }
193 
194 //! Utility function for getting the name of a data type.
195 //! This is used in vector and matrix constructors.
196 template <typename T>
dataTypeNameOf(void)197 const char *dataTypeNameOf(void)
198 {
199     return glu::getDataTypeName(glu::dataTypeOf<T>());
200 }
201 
202 template <>
dataTypeNameOf(void)203 const char *dataTypeNameOf<Void>(void)
204 {
205     DE_FATAL("Impossible");
206     return DE_NULL;
207 }
208 
209 //! A hack to get Void support for VarType.
210 template <typename T>
getVarTypeOf(Precision prec=glu::PRECISION_LAST)211 VarType getVarTypeOf(Precision prec = glu::PRECISION_LAST)
212 {
213     return glu::varTypeOf<T>(prec);
214 }
215 
216 template <>
getVarTypeOf(Precision)217 VarType getVarTypeOf<Void>(Precision)
218 {
219     DE_FATAL("Impossible");
220     return VarType();
221 }
222 
223 /*--------------------------------------------------------------------*//*!
224  * \brief Type traits for generalized interval types.
225  *
226  * We are trying to compute sets of acceptable values not only for
227  * float-valued expressions but also for compound values: vectors and
228  * matrices. We approximate a set of vectors as a vector of intervals and
229  * likewise for matrices.
230  *
231  * We now need generalized operations for each type and its interval
232  * approximation. These are given in the type Traits<T>.
233  *
234  * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
235  * scalar types, and a vector or matrix of intervals for container types.
236  *
237  * To allow template inference to take place, there are function wrappers for
238  * the actual operations in Traits<T>. Hence we can just use:
239  *
240  * makeIVal(someFloat)
241  *
242  * instead of:
243  *
244  * Traits<float>::doMakeIVal(value)
245  *
246  *//*--------------------------------------------------------------------*/
247 
248 template <typename T>
249 struct Traits;
250 
251 //! Create container from elementwise singleton values.
252 template <typename T>
makeIVal(const T & value)253 typename Traits<T>::IVal makeIVal(const T &value)
254 {
255     return Traits<T>::doMakeIVal(value);
256 }
257 
258 //! Elementwise union of intervals.
259 template <typename T>
unionIVal(const typename Traits<T>::IVal & a,const typename Traits<T>::IVal & b)260 typename Traits<T>::IVal unionIVal(const typename Traits<T>::IVal &a, const typename Traits<T>::IVal &b)
261 {
262     return Traits<T>::doUnion(a, b);
263 }
264 
265 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
266 template <typename T>
contains(const typename Traits<T>::IVal & ival,const T & value)267 bool contains(const typename Traits<T>::IVal &ival, const T &value)
268 {
269     return Traits<T>::doContains(ival, value);
270 }
271 
272 //! Returns true iff every element of `ival` contains corresponding element of `value` within the warning interval
273 template <typename T>
containsWarning(const typename Traits<T>::IVal & ival,const T & value)274 bool containsWarning(const typename Traits<T>::IVal &ival, const T &value)
275 {
276     return Traits<T>::doContainsWarning(ival, value);
277 }
278 
279 //! Print out an interval with the precision of `fmt`.
280 template <typename T>
printIVal(const FloatFormat & fmt,const typename Traits<T>::IVal & ival,ostream & os)281 void printIVal(const FloatFormat &fmt, const typename Traits<T>::IVal &ival, ostream &os)
282 {
283     Traits<T>::doPrintIVal(fmt, ival, os);
284 }
285 
286 template <typename T>
intervalToString(const FloatFormat & fmt,const typename Traits<T>::IVal & ival)287 string intervalToString(const FloatFormat &fmt, const typename Traits<T>::IVal &ival)
288 {
289     ostringstream oss;
290     printIVal<T>(fmt, ival, oss);
291     return oss.str();
292 }
293 
294 //! Print out a value with the precision of `fmt`.
295 template <typename T>
printValue(const FloatFormat & fmt,const T & value,ostream & os)296 void printValue(const FloatFormat &fmt, const T &value, ostream &os)
297 {
298     Traits<T>::doPrintValue(fmt, value, os);
299 }
300 
301 template <typename T>
valueToString(const FloatFormat & fmt,const T & val)302 string valueToString(const FloatFormat &fmt, const T &val)
303 {
304     ostringstream oss;
305     printValue(fmt, val, oss);
306     return oss.str();
307 }
308 
309 //! Approximate `value` elementwise to the float precision defined in `fmt`.
310 //! The resulting interval might not be a singleton if rounding in both
311 //! directions is allowed.
312 template <typename T>
round(const FloatFormat & fmt,const T & value)313 typename Traits<T>::IVal round(const FloatFormat &fmt, const T &value)
314 {
315     return Traits<T>::doRound(fmt, value);
316 }
317 
318 template <typename T>
convert(const FloatFormat & fmt,const typename Traits<T>::IVal & value)319 typename Traits<T>::IVal convert(const FloatFormat &fmt, const typename Traits<T>::IVal &value)
320 {
321     return Traits<T>::doConvert(fmt, value);
322 }
323 
324 //! Common traits for scalar types.
325 template <typename T>
326 struct ScalarTraits
327 {
328     typedef Interval IVal;
329 
doMakeIValdeqp::gls::BuiltinPrecisionTests::ScalarTraits330     static Interval doMakeIVal(const T &value)
331     {
332         // Thankfully all scalar types have a well-defined conversion to `double`,
333         // hence Interval can represent their ranges without problems.
334         return Interval(double(value));
335     }
336 
doUniondeqp::gls::BuiltinPrecisionTests::ScalarTraits337     static Interval doUnion(const Interval &a, const Interval &b)
338     {
339         return a | b;
340     }
341 
doContainsdeqp::gls::BuiltinPrecisionTests::ScalarTraits342     static bool doContains(const Interval &a, T value)
343     {
344         return a.contains(double(value));
345     }
346 
doContainsWarningdeqp::gls::BuiltinPrecisionTests::ScalarTraits347     static bool doContainsWarning(const Interval &a, T value)
348     {
349         return a.containsWarning(double(value));
350     }
351 
doConvertdeqp::gls::BuiltinPrecisionTests::ScalarTraits352     static Interval doConvert(const FloatFormat &fmt, const IVal &ival)
353     {
354         return fmt.convert(ival);
355     }
356 
doRounddeqp::gls::BuiltinPrecisionTests::ScalarTraits357     static Interval doRound(const FloatFormat &fmt, T value)
358     {
359         return fmt.roundOut(double(value), false);
360     }
361 };
362 
363 template <>
364 struct Traits<float> : ScalarTraits<float>
365 {
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits366     static void doPrintIVal(const FloatFormat &fmt, const Interval &ival, ostream &os)
367     {
368         os << fmt.intervalToHex(ival);
369     }
370 
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits371     static void doPrintValue(const FloatFormat &fmt, const float &value, ostream &os)
372     {
373         os << fmt.floatToHex(value);
374     }
375 };
376 
377 template <>
378 struct Traits<bool> : ScalarTraits<bool>
379 {
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits380     static void doPrintValue(const FloatFormat &, const float &value, ostream &os)
381     {
382         os << (value != 0.0f ? "true" : "false");
383     }
384 
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits385     static void doPrintIVal(const FloatFormat &, const Interval &ival, ostream &os)
386     {
387         os << "{";
388         if (ival.contains(false))
389             os << "false";
390         if (ival.contains(false) && ival.contains(true))
391             os << ", ";
392         if (ival.contains(true))
393             os << "true";
394         os << "}";
395     }
396 };
397 
398 template <>
399 struct Traits<int> : ScalarTraits<int>
400 {
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits401     static void doPrintValue(const FloatFormat &, const int &value, ostream &os)
402     {
403         os << value;
404     }
405 
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits406     static void doPrintIVal(const FloatFormat &, const Interval &ival, ostream &os)
407     {
408         os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
409     }
410 };
411 
412 //! Common traits for containers, i.e. vectors and matrices.
413 //! T is the container type itself, I is the same type with interval elements.
414 template <typename T, typename I>
415 struct ContainerTraits
416 {
417     typedef typename T::Element Element;
418     typedef I IVal;
419 
doMakeIValdeqp::gls::BuiltinPrecisionTests::ContainerTraits420     static IVal doMakeIVal(const T &value)
421     {
422         IVal ret;
423 
424         for (int ndx = 0; ndx < T::SIZE; ++ndx)
425             ret[ndx] = makeIVal(value[ndx]);
426 
427         return ret;
428     }
429 
doUniondeqp::gls::BuiltinPrecisionTests::ContainerTraits430     static IVal doUnion(const IVal &a, const IVal &b)
431     {
432         IVal ret;
433 
434         for (int ndx = 0; ndx < T::SIZE; ++ndx)
435             ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
436 
437         return ret;
438     }
439 
doContainsdeqp::gls::BuiltinPrecisionTests::ContainerTraits440     static bool doContains(const IVal &ival, const T &value)
441     {
442         for (int ndx = 0; ndx < T::SIZE; ++ndx)
443             if (!contains(ival[ndx], value[ndx]))
444                 return false;
445 
446         return true;
447     }
448 
doContainsWarningdeqp::gls::BuiltinPrecisionTests::ContainerTraits449     static bool doContainsWarning(const IVal &ival, const T &value)
450     {
451         for (int ndx = 0; ndx < T::SIZE; ++ndx)
452             if (!containsWarning(ival[ndx], value[ndx]))
453                 return false;
454 
455         return true;
456     }
457 
doPrintIValdeqp::gls::BuiltinPrecisionTests::ContainerTraits458     static void doPrintIVal(const FloatFormat &fmt, const IVal ival, ostream &os)
459     {
460         os << "(";
461 
462         for (int ndx = 0; ndx < T::SIZE; ++ndx)
463         {
464             if (ndx > 0)
465                 os << ", ";
466 
467             printIVal<Element>(fmt, ival[ndx], os);
468         }
469 
470         os << ")";
471     }
472 
doPrintValuedeqp::gls::BuiltinPrecisionTests::ContainerTraits473     static void doPrintValue(const FloatFormat &fmt, const T &value, ostream &os)
474     {
475         os << dataTypeNameOf<T>() << "(";
476 
477         for (int ndx = 0; ndx < T::SIZE; ++ndx)
478         {
479             if (ndx > 0)
480                 os << ", ";
481 
482             printValue<Element>(fmt, value[ndx], os);
483         }
484 
485         os << ")";
486     }
487 
doConvertdeqp::gls::BuiltinPrecisionTests::ContainerTraits488     static IVal doConvert(const FloatFormat &fmt, const IVal &value)
489     {
490         IVal ret;
491 
492         for (int ndx = 0; ndx < T::SIZE; ++ndx)
493             ret[ndx] = convert<Element>(fmt, value[ndx]);
494 
495         return ret;
496     }
497 
doRounddeqp::gls::BuiltinPrecisionTests::ContainerTraits498     static IVal doRound(const FloatFormat &fmt, T value)
499     {
500         IVal ret;
501 
502         for (int ndx = 0; ndx < T::SIZE; ++ndx)
503             ret[ndx] = round(fmt, value[ndx]);
504 
505         return ret;
506     }
507 };
508 
509 template <typename T, int Size>
510 struct Traits<Vector<T, Size>> : ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size>>
511 {
512 };
513 
514 template <typename T, int Rows, int Cols>
515 struct Traits<Matrix<T, Rows, Cols>>
516     : ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols>>
517 {
518 };
519 
520 //! Void traits. These are just dummies, but technically valid: a Void is a
521 //! unit type with a single possible value.
522 template <>
523 struct Traits<Void>
524 {
525     typedef Void IVal;
526 
doMakeIValdeqp::gls::BuiltinPrecisionTests::Traits527     static Void doMakeIVal(const Void &value)
528     {
529         return value;
530     }
doUniondeqp::gls::BuiltinPrecisionTests::Traits531     static Void doUnion(const Void &, const Void &)
532     {
533         return Void();
534     }
doContainsdeqp::gls::BuiltinPrecisionTests::Traits535     static bool doContains(const Void &, Void)
536     {
537         return true;
538     }
doContainsWarningdeqp::gls::BuiltinPrecisionTests::Traits539     static bool doContainsWarning(const Void &, Void)
540     {
541         return true;
542     }
doRounddeqp::gls::BuiltinPrecisionTests::Traits543     static Void doRound(const FloatFormat &, const Void &value)
544     {
545         return value;
546     }
doConvertdeqp::gls::BuiltinPrecisionTests::Traits547     static Void doConvert(const FloatFormat &, const Void &value)
548     {
549         return value;
550     }
551 
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits552     static void doPrintValue(const FloatFormat &, const Void &, ostream &os)
553     {
554         os << "()";
555     }
556 
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits557     static void doPrintIVal(const FloatFormat &, const Void &, ostream &os)
558     {
559         os << "()";
560     }
561 };
562 
563 //! This is needed for container-generic operations.
564 //! We want a scalar type T to be its own "one-element vector".
565 template <typename T, int Size>
566 struct ContainerOf
567 {
568     typedef Vector<T, Size> Container;
569 };
570 
571 template <typename T>
572 struct ContainerOf<T, 1>
573 {
574     typedef T Container;
575 };
576 template <int Size>
577 struct ContainerOf<Void, Size>
578 {
579     typedef Void Container;
580 };
581 
582 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
583 template <typename T>
584 struct ElementOf
585 {
586     typedef typename T::Element Element;
587 };
588 template <>
589 struct ElementOf<float>
590 {
591     typedef void Element;
592 };
593 template <>
594 struct ElementOf<bool>
595 {
596     typedef void Element;
597 };
598 template <>
599 struct ElementOf<int>
600 {
601     typedef void Element;
602 };
603 
604 /*--------------------------------------------------------------------*//*!
605  *
606  * \name Abstract syntax for expressions and statements.
607  *
608  * We represent GLSL programs as syntax objects: an Expr<T> represents an
609  * expression whose GLSL type corresponds to the C++ type T, and a Statement
610  * represents a statement.
611  *
612  * To ease memory management, we use shared pointers to refer to expressions
613  * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
614  * is a shared pointer to a Statement.
615  *
616  * \{
617  *
618  *//*--------------------------------------------------------------------*/
619 
620 class ExprBase;
621 class ExpandContext;
622 class Statement;
623 class StatementP;
624 class FuncBase;
625 template <typename T>
626 class ExprP;
627 template <typename T>
628 class Variable;
629 template <typename T>
630 class VariableP;
631 template <typename T>
632 class DefaultSampling;
633 
634 typedef set<const FuncBase *> FuncSet;
635 
636 template <typename T>
637 VariableP<T> variable(const string &name);
638 StatementP compoundStatement(const vector<StatementP> &statements);
639 
640 /*--------------------------------------------------------------------*//*!
641  * \brief A variable environment.
642  *
643  * An Environment object maintains the mapping between variables of the
644  * abstract syntax tree and their values.
645  *
646  * \todo [2014-03-28 lauri] At least run-time type safety.
647  *
648  *//*--------------------------------------------------------------------*/
649 class Environment
650 {
651 public:
652     template <typename T>
bind(const Variable<T> & variable,const typename Traits<T>::IVal & value)653     void bind(const Variable<T> &variable, const typename Traits<T>::IVal &value)
654     {
655         uint8_t *const data = new uint8_t[sizeof(value)];
656 
657         deMemcpy(data, &value, sizeof(value));
658         de::insert(m_map, variable.getName(), SharedPtr<uint8_t>(data, de::ArrayDeleter<uint8_t>()));
659     }
660 
661     template <typename T>
lookup(const Variable<T> & variable) const662     typename Traits<T>::IVal &lookup(const Variable<T> &variable) const
663     {
664         uint8_t *const data = de::lookup(m_map, variable.getName()).get();
665 
666         return *reinterpret_cast<typename Traits<T>::IVal *>(data);
667     }
668 
669 private:
670     map<string, SharedPtr<uint8_t>> m_map;
671 };
672 
673 /*--------------------------------------------------------------------*//*!
674  * \brief Evaluation context.
675  *
676  * The evaluation context contains everything that separates one execution of
677  * an expression from the next. Currently this means the desired floating
678  * point precision and the current variable environment.
679  *
680  *//*--------------------------------------------------------------------*/
681 struct EvalContext
682 {
EvalContextdeqp::gls::BuiltinPrecisionTests::EvalContext683     EvalContext(const FloatFormat &format_, Precision floatPrecision_, Environment &env_, int callDepth_ = 0)
684         : format(format_)
685         , floatPrecision(floatPrecision_)
686         , env(env_)
687         , callDepth(callDepth_)
688     {
689     }
690 
691     FloatFormat format;
692     Precision floatPrecision;
693     Environment &env;
694     int callDepth;
695 };
696 
697 /*--------------------------------------------------------------------*//*!
698  * \brief Simple incremental counter.
699  *
700  * This is used to make sure that different ExpandContexts will not produce
701  * overlapping temporary names.
702  *
703  *//*--------------------------------------------------------------------*/
704 class Counter
705 {
706 public:
Counter(int count=0)707     Counter(int count = 0) : m_count(count)
708     {
709     }
operator ()(void)710     int operator()(void)
711     {
712         return m_count++;
713     }
714 
715 private:
716     int m_count;
717 };
718 
719 /*--------------------------------------------------------------------*//*!
720  * \brief A statement or declaration.
721  *
722  * Statements have no values. Instead, they are executed for their side
723  * effects only: the execute() method should modify at least one variable in
724  * the environment.
725  *
726  * As a bit of a kludge, a Statement object can also represent a declaration:
727  * when it is evaluated, it can add a variable binding to the environment
728  * instead of modifying a current one.
729  *
730  *//*--------------------------------------------------------------------*/
731 class Statement
732 {
733 public:
~Statement(void)734     virtual ~Statement(void)
735     {
736     }
737     //! Execute the statement, modifying the environment of `ctx`
execute(EvalContext & ctx) const738     void execute(EvalContext &ctx) const
739     {
740         this->doExecute(ctx);
741     }
print(ostream & os) const742     void print(ostream &os) const
743     {
744         this->doPrint(os);
745     }
746     //! Add the functions used in this statement to `dst`.
getUsedFuncs(FuncSet & dst) const747     void getUsedFuncs(FuncSet &dst) const
748     {
749         this->doGetUsedFuncs(dst);
750     }
751 
752 protected:
753     virtual void doPrint(ostream &os) const         = 0;
754     virtual void doExecute(EvalContext &ctx) const  = 0;
755     virtual void doGetUsedFuncs(FuncSet &dst) const = 0;
756 };
757 
operator <<(ostream & os,const Statement & stmt)758 ostream &operator<<(ostream &os, const Statement &stmt)
759 {
760     stmt.print(os);
761     return os;
762 }
763 
764 /*--------------------------------------------------------------------*//*!
765  * \brief Smart pointer for statements (and declarations)
766  *
767  *//*--------------------------------------------------------------------*/
768 class StatementP : public SharedPtr<const Statement>
769 {
770 public:
771     typedef SharedPtr<const Statement> Super;
772 
StatementP(void)773     StatementP(void)
774     {
775     }
StatementP(const Statement * ptr)776     explicit StatementP(const Statement *ptr) : Super(ptr)
777     {
778     }
StatementP(const Super & ptr)779     StatementP(const Super &ptr) : Super(ptr)
780     {
781     }
782 };
783 
784 class ExpandContext
785 {
786 public:
ExpandContext(Counter & symCounter)787     ExpandContext(Counter &symCounter) : m_symCounter(symCounter)
788     {
789     }
ExpandContext(const ExpandContext & parent)790     ExpandContext(const ExpandContext &parent) : m_symCounter(parent.m_symCounter)
791     {
792     }
793 
794     template <typename T>
genSym(const string & baseName)795     VariableP<T> genSym(const string &baseName)
796     {
797         return variable<T>(baseName + de::toString(m_symCounter()));
798     }
799 
addStatement(const StatementP & stmt)800     void addStatement(const StatementP &stmt)
801     {
802         m_statements.push_back(stmt);
803     }
804 
getStatements(void) const805     vector<StatementP> getStatements(void) const
806     {
807         return m_statements;
808     }
809 
810 private:
811     Counter &m_symCounter;
812     vector<StatementP> m_statements;
813 };
814 
815 /*--------------------------------------------------------------------*//*!
816  * \brief
817  *
818  * A statement that modifies a variable or a declaration that binds a variable.
819  *
820  *//*--------------------------------------------------------------------*/
821 template <typename T>
822 class VariableStatement : public Statement
823 {
824 public:
VariableStatement(const VariableP<T> & variable,const ExprP<T> & value,bool isDeclaration)825     VariableStatement(const VariableP<T> &variable, const ExprP<T> &value, bool isDeclaration)
826         : m_variable(variable)
827         , m_value(value)
828         , m_isDeclaration(isDeclaration)
829     {
830     }
831 
832 protected:
doPrint(ostream & os) const833     void doPrint(ostream &os) const
834     {
835         if (m_isDeclaration)
836             os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
837         else
838             os << m_variable->getName();
839 
840         os << " = " << *m_value << ";\n";
841     }
842 
doExecute(EvalContext & ctx) const843     void doExecute(EvalContext &ctx) const
844     {
845         if (m_isDeclaration)
846             ctx.env.bind(*m_variable, m_value->evaluate(ctx));
847         else
848             ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
849     }
850 
doGetUsedFuncs(FuncSet & dst) const851     void doGetUsedFuncs(FuncSet &dst) const
852     {
853         m_value->getUsedFuncs(dst);
854     }
855 
856     VariableP<T> m_variable;
857     ExprP<T> m_value;
858     bool m_isDeclaration;
859 };
860 
861 template <typename T>
variableStatement(const VariableP<T> & variable,const ExprP<T> & value,bool isDeclaration)862 StatementP variableStatement(const VariableP<T> &variable, const ExprP<T> &value, bool isDeclaration)
863 {
864     return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
865 }
866 
867 template <typename T>
variableDeclaration(const VariableP<T> & variable,const ExprP<T> & definiens)868 StatementP variableDeclaration(const VariableP<T> &variable, const ExprP<T> &definiens)
869 {
870     return variableStatement(variable, definiens, true);
871 }
872 
873 template <typename T>
variableAssignment(const VariableP<T> & variable,const ExprP<T> & value)874 StatementP variableAssignment(const VariableP<T> &variable, const ExprP<T> &value)
875 {
876     return variableStatement(variable, value, false);
877 }
878 
879 /*--------------------------------------------------------------------*//*!
880  * \brief A compound statement, i.e. a block.
881  *
882  * A compound statement is executed by executing its constituent statements in
883  * sequence.
884  *
885  *//*--------------------------------------------------------------------*/
886 class CompoundStatement : public Statement
887 {
888 public:
CompoundStatement(const vector<StatementP> & statements)889     CompoundStatement(const vector<StatementP> &statements) : m_statements(statements)
890     {
891     }
892 
893 protected:
doPrint(ostream & os) const894     void doPrint(ostream &os) const
895     {
896         os << "{\n";
897 
898         for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
899             os << *m_statements[ndx];
900 
901         os << "}\n";
902     }
903 
doExecute(EvalContext & ctx) const904     void doExecute(EvalContext &ctx) const
905     {
906         for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
907             m_statements[ndx]->execute(ctx);
908     }
909 
doGetUsedFuncs(FuncSet & dst) const910     void doGetUsedFuncs(FuncSet &dst) const
911     {
912         for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
913             m_statements[ndx]->getUsedFuncs(dst);
914     }
915 
916     vector<StatementP> m_statements;
917 };
918 
compoundStatement(const vector<StatementP> & statements)919 StatementP compoundStatement(const vector<StatementP> &statements)
920 {
921     return StatementP(new CompoundStatement(statements));
922 }
923 
924 //! Common base class for all expressions regardless of their type.
925 class ExprBase
926 {
927 public:
~ExprBase(void)928     virtual ~ExprBase(void)
929     {
930     }
printExpr(ostream & os) const931     void printExpr(ostream &os) const
932     {
933         this->doPrintExpr(os);
934     }
935 
936     //! Output the functions that this expression refers to
getUsedFuncs(FuncSet & dst) const937     void getUsedFuncs(FuncSet &dst) const
938     {
939         this->doGetUsedFuncs(dst);
940     }
941 
942 protected:
doPrintExpr(ostream &) const943     virtual void doPrintExpr(ostream &) const
944     {
945     }
doGetUsedFuncs(FuncSet &) const946     virtual void doGetUsedFuncs(FuncSet &) const
947     {
948     }
949 };
950 
951 //! Type-specific operations for an expression representing type T.
952 template <typename T>
953 class Expr : public ExprBase
954 {
955 public:
956     typedef T Val;
957     typedef typename Traits<T>::IVal IVal;
958 
959     IVal evaluate(const EvalContext &ctx) const;
960 
961 protected:
962     virtual IVal doEvaluate(const EvalContext &ctx) const = 0;
963 };
964 
965 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
966 template <typename T>
evaluate(const EvalContext & ctx) const967 typename Traits<T>::IVal Expr<T>::evaluate(const EvalContext &ctx) const
968 {
969 #ifdef GLS_ENABLE_TRACE
970     static const FloatFormat highpFmt(-126, 127, 23, true, tcu::MAYBE, tcu::YES, tcu::MAYBE);
971     EvalContext newCtx(ctx.format, ctx.floatPrecision, ctx.env, ctx.callDepth + 1);
972     const IVal ret = this->doEvaluate(newCtx);
973 
974     if (isTypeValid<T>())
975     {
976         std::cerr << string(ctx.callDepth, ' ');
977         this->printExpr(std::cerr);
978         std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
979     }
980     return ret;
981 #else
982     return this->doEvaluate(ctx);
983 #endif
984 }
985 
986 template <typename T>
987 class ExprPBase : public SharedPtr<const Expr<T>>
988 {
989 public:
990 };
991 
operator <<(ostream & os,const ExprBase & expr)992 ostream &operator<<(ostream &os, const ExprBase &expr)
993 {
994     expr.printExpr(os);
995     return os;
996 }
997 
998 /*--------------------------------------------------------------------*//*!
999  * \brief Shared pointer to an expression of a container type.
1000  *
1001  * Container types (i.e. vectors and matrices) support the subscription
1002  * operator. This class provides a bit of syntactic sugar to allow us to use
1003  * the C++ subscription operator to create a subscription expression.
1004  *//*--------------------------------------------------------------------*/
1005 template <typename T>
1006 class ContainerExprPBase : public ExprPBase<T>
1007 {
1008 public:
1009     ExprP<typename T::Element> operator[](int i) const;
1010 };
1011 
1012 template <typename T>
1013 class ExprP : public ExprPBase<T>
1014 {
1015 };
1016 
1017 // We treat Voids as containers since the unused parameters in generalized
1018 // vector functions are represented as Voids.
1019 template <>
1020 class ExprP<Void> : public ContainerExprPBase<Void>
1021 {
1022 };
1023 
1024 template <typename T, int Size>
1025 class ExprP<Vector<T, Size>> : public ContainerExprPBase<Vector<T, Size>>
1026 {
1027 };
1028 
1029 template <typename T, int Rows, int Cols>
1030 class ExprP<Matrix<T, Rows, Cols>> : public ContainerExprPBase<Matrix<T, Rows, Cols>>
1031 {
1032 };
1033 
1034 template <typename T>
exprP(void)1035 ExprP<T> exprP(void)
1036 {
1037     return ExprP<T>();
1038 }
1039 
1040 template <typename T>
exprP(const SharedPtr<const Expr<T>> & ptr)1041 ExprP<T> exprP(const SharedPtr<const Expr<T>> &ptr)
1042 {
1043     ExprP<T> ret;
1044     static_cast<SharedPtr<const Expr<T>> &>(ret) = ptr;
1045     return ret;
1046 }
1047 
1048 template <typename T>
exprP(const Expr<T> * ptr)1049 ExprP<T> exprP(const Expr<T> *ptr)
1050 {
1051     return exprP(SharedPtr<const Expr<T>>(ptr));
1052 }
1053 
1054 /*--------------------------------------------------------------------*//*!
1055  * \brief A shared pointer to a variable expression.
1056  *
1057  * This is just a narrowing of ExprP for the operations that require a variable
1058  * instead of an arbitrary expression.
1059  *
1060  *//*--------------------------------------------------------------------*/
1061 template <typename T>
1062 class VariableP : public SharedPtr<const Variable<T>>
1063 {
1064 public:
1065     typedef SharedPtr<const Variable<T>> Super;
VariableP(const Variable<T> * ptr)1066     explicit VariableP(const Variable<T> *ptr) : Super(ptr)
1067     {
1068     }
VariableP(void)1069     VariableP(void)
1070     {
1071     }
VariableP(const Super & ptr)1072     VariableP(const Super &ptr) : Super(ptr)
1073     {
1074     }
1075 
operator ExprP<T>(void) const1076     operator ExprP<T>(void) const
1077     {
1078         SharedPtr<const Expr<T>> ptr = *this;
1079         return exprP(ptr);
1080     }
1081 };
1082 
1083 /*--------------------------------------------------------------------*//*!
1084  * \name Syntactic sugar operators for expressions.
1085  *
1086  * @{
1087  *
1088  * These operators allow the use of C++ syntax to construct GLSL expressions
1089  * containing operators: e.g. "a+b" creates an addition expression with
1090  * operands a and b, and so on.
1091  *
1092  *//*--------------------------------------------------------------------*/
1093 ExprP<float> operator-(const ExprP<float> &arg0);
1094 ExprP<float> operator+(const ExprP<float> &arg0, const ExprP<float> &arg1);
1095 ExprP<float> operator-(const ExprP<float> &arg0, const ExprP<float> &arg1);
1096 ExprP<float> operator*(const ExprP<float> &arg0, const ExprP<float> &arg1);
1097 ExprP<float> operator/(const ExprP<float> &arg0, const ExprP<float> &arg1);
1098 template <int Size>
1099 ExprP<Vector<float, Size>> operator-(const ExprP<Vector<float, Size>> &arg0);
1100 template <int Size>
1101 ExprP<Vector<float, Size>> operator*(const ExprP<Vector<float, Size>> &arg0, const ExprP<float> &arg1);
1102 template <int Size>
1103 ExprP<Vector<float, Size>> operator*(const ExprP<Vector<float, Size>> &arg0, const ExprP<Vector<float, Size>> &arg1);
1104 template <int Size>
1105 ExprP<Vector<float, Size>> operator-(const ExprP<Vector<float, Size>> &arg0, const ExprP<Vector<float, Size>> &arg1);
1106 template <int Left, int Mid, int Right>
1107 ExprP<Matrix<float, Left, Right>> operator*(const ExprP<Matrix<float, Left, Mid>> &left,
1108                                             const ExprP<Matrix<float, Mid, Right>> &right);
1109 template <int Rows, int Cols>
1110 ExprP<Vector<float, Rows>> operator*(const ExprP<Vector<float, Cols>> &left,
1111                                      const ExprP<Matrix<float, Rows, Cols>> &right);
1112 template <int Rows, int Cols>
1113 ExprP<Vector<float, Cols>> operator*(const ExprP<Matrix<float, Rows, Cols>> &left,
1114                                      const ExprP<Vector<float, Rows>> &right);
1115 template <int Rows, int Cols>
1116 ExprP<Matrix<float, Rows, Cols>> operator*(const ExprP<Matrix<float, Rows, Cols>> &left, const ExprP<float> &right);
1117 template <int Rows, int Cols>
1118 ExprP<Matrix<float, Rows, Cols>> operator+(const ExprP<Matrix<float, Rows, Cols>> &left,
1119                                            const ExprP<Matrix<float, Rows, Cols>> &right);
1120 template <int Rows, int Cols>
1121 ExprP<Matrix<float, Rows, Cols>> operator-(const ExprP<Matrix<float, Rows, Cols>> &mat);
1122 
1123 //! @}
1124 
1125 /*--------------------------------------------------------------------*//*!
1126  * \brief Variable expression.
1127  *
1128  * A variable is evaluated by looking up its range of possible values from an
1129  * environment.
1130  *//*--------------------------------------------------------------------*/
1131 template <typename T>
1132 class Variable : public Expr<T>
1133 {
1134 public:
1135     typedef typename Expr<T>::IVal IVal;
1136 
Variable(const string & name)1137     Variable(const string &name) : m_name(name)
1138     {
1139     }
getName(void) const1140     string getName(void) const
1141     {
1142         return m_name;
1143     }
1144 
1145 protected:
doPrintExpr(ostream & os) const1146     void doPrintExpr(ostream &os) const
1147     {
1148         os << m_name;
1149     }
doEvaluate(const EvalContext & ctx) const1150     IVal doEvaluate(const EvalContext &ctx) const
1151     {
1152         return ctx.env.lookup<T>(*this);
1153     }
1154 
1155 private:
1156     string m_name;
1157 };
1158 
1159 template <typename T>
variable(const string & name)1160 VariableP<T> variable(const string &name)
1161 {
1162     return VariableP<T>(new Variable<T>(name));
1163 }
1164 
1165 template <typename T>
bindExpression(const string & name,ExpandContext & ctx,const ExprP<T> & expr)1166 VariableP<T> bindExpression(const string &name, ExpandContext &ctx, const ExprP<T> &expr)
1167 {
1168     VariableP<T> var = ctx.genSym<T>(name);
1169     ctx.addStatement(variableDeclaration(var, expr));
1170     return var;
1171 }
1172 
1173 /*--------------------------------------------------------------------*//*!
1174  * \brief Constant expression.
1175  *
1176  * A constant is evaluated by rounding it to a set of possible values allowed
1177  * by the current floating point precision.
1178  *//*--------------------------------------------------------------------*/
1179 template <typename T>
1180 class Constant : public Expr<T>
1181 {
1182 public:
1183     typedef typename Expr<T>::IVal IVal;
1184 
Constant(const T & value)1185     Constant(const T &value) : m_value(value)
1186     {
1187     }
1188 
1189 protected:
doPrintExpr(ostream & os) const1190     void doPrintExpr(ostream &os) const
1191     {
1192         os << m_value;
1193     }
doEvaluate(const EvalContext &) const1194     IVal doEvaluate(const EvalContext &) const
1195     {
1196         return makeIVal(m_value);
1197     }
1198 
1199 private:
1200     T m_value;
1201 };
1202 
1203 template <typename T>
constant(const T & value)1204 ExprP<T> constant(const T &value)
1205 {
1206     return exprP(new Constant<T>(value));
1207 }
1208 
1209 //! Return a reference to a singleton void constant.
voidP(void)1210 const ExprP<Void> &voidP(void)
1211 {
1212     static const ExprP<Void> singleton = constant(Void());
1213 
1214     return singleton;
1215 }
1216 
1217 /*--------------------------------------------------------------------*//*!
1218  * \brief Four-element tuple.
1219  *
1220  * This is used for various things where we need one thing for each possible
1221  * function parameter. Currently the maximum supported number of parameters is
1222  * four.
1223  *//*--------------------------------------------------------------------*/
1224 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1225 struct Tuple4
1226 {
Tuple4deqp::gls::BuiltinPrecisionTests::Tuple41227     explicit Tuple4(const T0 e0 = T0(), const T1 e1 = T1(), const T2 e2 = T2(), const T3 e3 = T3())
1228         : a(e0)
1229         , b(e1)
1230         , c(e2)
1231         , d(e3)
1232     {
1233     }
1234 
1235     T0 a;
1236     T1 b;
1237     T2 c;
1238     T3 d;
1239 };
1240 
1241 /*--------------------------------------------------------------------*//*!
1242  * \brief Function signature.
1243  *
1244  * This is a purely compile-time structure used to bundle all types in a
1245  * function signature together. This makes passing the signature around in
1246  * templates easier, since we only need to take and pass a single Sig instead
1247  * of a bunch of parameter types and a return type.
1248  *
1249  *//*--------------------------------------------------------------------*/
1250 template <typename R, typename P0 = Void, typename P1 = Void, typename P2 = Void, typename P3 = Void>
1251 struct Signature
1252 {
1253     typedef R Ret;
1254     typedef P0 Arg0;
1255     typedef P1 Arg1;
1256     typedef P2 Arg2;
1257     typedef P3 Arg3;
1258     typedef typename Traits<Ret>::IVal IRet;
1259     typedef typename Traits<Arg0>::IVal IArg0;
1260     typedef typename Traits<Arg1>::IVal IArg1;
1261     typedef typename Traits<Arg2>::IVal IArg2;
1262     typedef typename Traits<Arg3>::IVal IArg3;
1263 
1264     typedef Tuple4<const Arg0 &, const Arg1 &, const Arg2 &, const Arg3 &> Args;
1265     typedef Tuple4<const IArg0 &, const IArg1 &, const IArg2 &, const IArg3 &> IArgs;
1266     typedef Tuple4<ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3>> ArgExprs;
1267 };
1268 
1269 typedef vector<const ExprBase *> BaseArgExprs;
1270 
1271 /*--------------------------------------------------------------------*//*!
1272  * \brief Type-independent operations for function objects.
1273  *
1274  *//*--------------------------------------------------------------------*/
1275 class FuncBase
1276 {
1277 public:
~FuncBase(void)1278     virtual ~FuncBase(void)
1279     {
1280     }
1281     virtual string getName(void) const = 0;
1282     //! Name of extension that this function requires, or empty.
getRequiredExtension(const RenderContext &) const1283     virtual string getRequiredExtension(const RenderContext &) const
1284     {
1285         return "";
1286     }
1287     virtual void print(ostream &, const BaseArgExprs &) const = 0;
1288     //! Index of output parameter, or -1 if none of the parameters is output.
getOutParamIndex(void) const1289     virtual int getOutParamIndex(void) const
1290     {
1291         return -1;
1292     }
1293 
printDefinition(ostream & os) const1294     void printDefinition(ostream &os) const
1295     {
1296         doPrintDefinition(os);
1297     }
1298 
getUsedFuncs(FuncSet & dst) const1299     void getUsedFuncs(FuncSet &dst) const
1300     {
1301         this->doGetUsedFuncs(dst);
1302     }
1303 
1304 protected:
1305     virtual void doPrintDefinition(ostream &os) const = 0;
1306     virtual void doGetUsedFuncs(FuncSet &dst) const   = 0;
1307 };
1308 
1309 typedef Tuple4<string, string, string, string> ParamNames;
1310 
1311 /*--------------------------------------------------------------------*//*!
1312  * \brief Function objects.
1313  *
1314  * Each Func object represents a GLSL function. It can be applied to interval
1315  * arguments, and it returns the an interval that is a conservative
1316  * approximation of the image of the GLSL function over the argument
1317  * intervals. That is, it is given a set of possible arguments and it returns
1318  * the set of possible values.
1319  *
1320  *//*--------------------------------------------------------------------*/
1321 template <typename Sig_>
1322 class Func : public FuncBase
1323 {
1324 public:
1325     typedef Sig_ Sig;
1326     typedef typename Sig::Ret Ret;
1327     typedef typename Sig::Arg0 Arg0;
1328     typedef typename Sig::Arg1 Arg1;
1329     typedef typename Sig::Arg2 Arg2;
1330     typedef typename Sig::Arg3 Arg3;
1331     typedef typename Sig::IRet IRet;
1332     typedef typename Sig::IArg0 IArg0;
1333     typedef typename Sig::IArg1 IArg1;
1334     typedef typename Sig::IArg2 IArg2;
1335     typedef typename Sig::IArg3 IArg3;
1336     typedef typename Sig::Args Args;
1337     typedef typename Sig::IArgs IArgs;
1338     typedef typename Sig::ArgExprs ArgExprs;
1339 
print(ostream & os,const BaseArgExprs & args) const1340     void print(ostream &os, const BaseArgExprs &args) const
1341     {
1342         this->doPrint(os, args);
1343     }
1344 
apply(const EvalContext & ctx,const IArg0 & arg0=IArg0 (),const IArg1 & arg1=IArg1 (),const IArg2 & arg2=IArg2 (),const IArg3 & arg3=IArg3 ()) const1345     IRet apply(const EvalContext &ctx, const IArg0 &arg0 = IArg0(), const IArg1 &arg1 = IArg1(),
1346                const IArg2 &arg2 = IArg2(), const IArg3 &arg3 = IArg3()) const
1347     {
1348         return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1349     }
applyArgs(const EvalContext & ctx,const IArgs & args) const1350     IRet applyArgs(const EvalContext &ctx, const IArgs &args) const
1351     {
1352         return this->doApply(ctx, args);
1353     }
1354     ExprP<Ret> operator()(const ExprP<Arg0> &arg0 = voidP(), const ExprP<Arg1> &arg1 = voidP(),
1355                           const ExprP<Arg2> &arg2 = voidP(), const ExprP<Arg3> &arg3 = voidP()) const;
1356 
getParamNames(void) const1357     const ParamNames &getParamNames(void) const
1358     {
1359         return this->doGetParamNames();
1360     }
1361 
1362 protected:
1363     virtual IRet doApply(const EvalContext &, const IArgs &) const = 0;
doPrint(ostream & os,const BaseArgExprs & args) const1364     virtual void doPrint(ostream &os, const BaseArgExprs &args) const
1365     {
1366         os << getName() << "(";
1367 
1368         if (isTypeValid<Arg0>())
1369             os << *args[0];
1370 
1371         if (isTypeValid<Arg1>())
1372             os << ", " << *args[1];
1373 
1374         if (isTypeValid<Arg2>())
1375             os << ", " << *args[2];
1376 
1377         if (isTypeValid<Arg3>())
1378             os << ", " << *args[3];
1379 
1380         os << ")";
1381     }
1382 
doGetParamNames(void) const1383     virtual const ParamNames &doGetParamNames(void) const
1384     {
1385         static ParamNames names("a", "b", "c", "d");
1386         return names;
1387     }
1388 };
1389 
1390 template <typename Sig>
1391 class Apply : public Expr<typename Sig::Ret>
1392 {
1393 public:
1394     typedef typename Sig::Ret Ret;
1395     typedef typename Sig::Arg0 Arg0;
1396     typedef typename Sig::Arg1 Arg1;
1397     typedef typename Sig::Arg2 Arg2;
1398     typedef typename Sig::Arg3 Arg3;
1399     typedef typename Expr<Ret>::Val Val;
1400     typedef typename Expr<Ret>::IVal IVal;
1401     typedef Func<Sig> ApplyFunc;
1402     typedef typename ApplyFunc::ArgExprs ArgExprs;
1403 
Apply(const ApplyFunc & func,const ExprP<Arg0> & arg0=voidP (),const ExprP<Arg1> & arg1=voidP (),const ExprP<Arg2> & arg2=voidP (),const ExprP<Arg3> & arg3=voidP ())1404     Apply(const ApplyFunc &func, const ExprP<Arg0> &arg0 = voidP(), const ExprP<Arg1> &arg1 = voidP(),
1405           const ExprP<Arg2> &arg2 = voidP(), const ExprP<Arg3> &arg3 = voidP())
1406         : m_func(func)
1407         , m_args(arg0, arg1, arg2, arg3)
1408     {
1409     }
1410 
Apply(const ApplyFunc & func,const ArgExprs & args)1411     Apply(const ApplyFunc &func, const ArgExprs &args) : m_func(func), m_args(args)
1412     {
1413     }
1414 
1415 protected:
doPrintExpr(ostream & os) const1416     void doPrintExpr(ostream &os) const
1417     {
1418         BaseArgExprs args;
1419         args.push_back(m_args.a.get());
1420         args.push_back(m_args.b.get());
1421         args.push_back(m_args.c.get());
1422         args.push_back(m_args.d.get());
1423         m_func.print(os, args);
1424     }
1425 
doEvaluate(const EvalContext & ctx) const1426     IVal doEvaluate(const EvalContext &ctx) const
1427     {
1428         return m_func.apply(ctx, m_args.a->evaluate(ctx), m_args.b->evaluate(ctx), m_args.c->evaluate(ctx),
1429                             m_args.d->evaluate(ctx));
1430     }
1431 
doGetUsedFuncs(FuncSet & dst) const1432     void doGetUsedFuncs(FuncSet &dst) const
1433     {
1434         m_func.getUsedFuncs(dst);
1435         m_args.a->getUsedFuncs(dst);
1436         m_args.b->getUsedFuncs(dst);
1437         m_args.c->getUsedFuncs(dst);
1438         m_args.d->getUsedFuncs(dst);
1439     }
1440 
1441     const ApplyFunc &m_func;
1442     ArgExprs m_args;
1443 };
1444 
1445 template <typename T>
1446 class Alternatives : public Func<Signature<T, T, T>>
1447 {
1448 public:
1449     typedef typename Alternatives::Sig Sig;
1450 
1451 protected:
1452     typedef typename Alternatives::IRet IRet;
1453     typedef typename Alternatives::IArgs IArgs;
1454 
getName(void) const1455     virtual string getName(void) const
1456     {
1457         return "alternatives";
1458     }
doPrintDefinition(std::ostream &) const1459     virtual void doPrintDefinition(std::ostream &) const
1460     {
1461     }
doGetUsedFuncs(FuncSet &) const1462     void doGetUsedFuncs(FuncSet &) const
1463     {
1464     }
1465 
doApply(const EvalContext &,const IArgs & args) const1466     virtual IRet doApply(const EvalContext &, const IArgs &args) const
1467     {
1468         return unionIVal<T>(args.a, args.b);
1469     }
1470 
doPrint(ostream & os,const BaseArgExprs & args) const1471     virtual void doPrint(ostream &os, const BaseArgExprs &args) const
1472     {
1473         os << "{" << *args[0] << " | " << *args[1] << "}";
1474     }
1475 };
1476 
1477 template <typename Sig>
createApply(const Func<Sig> & func,const typename Func<Sig>::ArgExprs & args)1478 ExprP<typename Sig::Ret> createApply(const Func<Sig> &func, const typename Func<Sig>::ArgExprs &args)
1479 {
1480     return exprP(new Apply<Sig>(func, args));
1481 }
1482 
1483 template <typename Sig>
createApply(const Func<Sig> & func,const ExprP<typename Sig::Arg0> & arg0=voidP (),const ExprP<typename Sig::Arg1> & arg1=voidP (),const ExprP<typename Sig::Arg2> & arg2=voidP (),const ExprP<typename Sig::Arg3> & arg3=voidP ())1484 ExprP<typename Sig::Ret> createApply(const Func<Sig> &func, const ExprP<typename Sig::Arg0> &arg0 = voidP(),
1485                                      const ExprP<typename Sig::Arg1> &arg1 = voidP(),
1486                                      const ExprP<typename Sig::Arg2> &arg2 = voidP(),
1487                                      const ExprP<typename Sig::Arg3> &arg3 = voidP())
1488 {
1489     return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1490 }
1491 
1492 template <typename Sig>
operator ()(const ExprP<typename Sig::Arg0> & arg0,const ExprP<typename Sig::Arg1> & arg1,const ExprP<typename Sig::Arg2> & arg2,const ExprP<typename Sig::Arg3> & arg3) const1493 ExprP<typename Sig::Ret> Func<Sig>::operator()(const ExprP<typename Sig::Arg0> &arg0,
1494                                                const ExprP<typename Sig::Arg1> &arg1,
1495                                                const ExprP<typename Sig::Arg2> &arg2,
1496                                                const ExprP<typename Sig::Arg3> &arg3) const
1497 {
1498     return createApply(*this, arg0, arg1, arg2, arg3);
1499 }
1500 
1501 template <typename F>
app(const ExprP<typename F::Arg0> & arg0=voidP (),const ExprP<typename F::Arg1> & arg1=voidP (),const ExprP<typename F::Arg2> & arg2=voidP (),const ExprP<typename F::Arg3> & arg3=voidP ())1502 ExprP<typename F::Ret> app(const ExprP<typename F::Arg0> &arg0 = voidP(), const ExprP<typename F::Arg1> &arg1 = voidP(),
1503                            const ExprP<typename F::Arg2> &arg2 = voidP(), const ExprP<typename F::Arg3> &arg3 = voidP())
1504 {
1505     return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1506 }
1507 
1508 template <typename F>
call(const EvalContext & ctx,const typename F::IArg0 & arg0=Void (),const typename F::IArg1 & arg1=Void (),const typename F::IArg2 & arg2=Void (),const typename F::IArg3 & arg3=Void ())1509 typename F::IRet call(const EvalContext &ctx, const typename F::IArg0 &arg0 = Void(),
1510                       const typename F::IArg1 &arg1 = Void(), const typename F::IArg2 &arg2 = Void(),
1511                       const typename F::IArg3 &arg3 = Void())
1512 {
1513     return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1514 }
1515 
1516 template <typename T>
alternatives(const ExprP<T> & arg0,const ExprP<T> & arg1)1517 ExprP<T> alternatives(const ExprP<T> &arg0, const ExprP<T> &arg1)
1518 {
1519     return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T>>(), arg0, arg1);
1520 }
1521 
1522 template <typename Sig>
1523 class ApplyVar : public Apply<Sig>
1524 {
1525 public:
1526     typedef typename Sig::Ret Ret;
1527     typedef typename Sig::Arg0 Arg0;
1528     typedef typename Sig::Arg1 Arg1;
1529     typedef typename Sig::Arg2 Arg2;
1530     typedef typename Sig::Arg3 Arg3;
1531     typedef typename Expr<Ret>::Val Val;
1532     typedef typename Expr<Ret>::IVal IVal;
1533     typedef Func<Sig> ApplyFunc;
1534     typedef typename ApplyFunc::ArgExprs ArgExprs;
1535 
ApplyVar(const ApplyFunc & func,const VariableP<Arg0> & arg0,const VariableP<Arg1> & arg1,const VariableP<Arg2> & arg2,const VariableP<Arg3> & arg3)1536     ApplyVar(const ApplyFunc &func, const VariableP<Arg0> &arg0, const VariableP<Arg1> &arg1,
1537              const VariableP<Arg2> &arg2, const VariableP<Arg3> &arg3)
1538         : Apply<Sig>(func, arg0, arg1, arg2, arg3)
1539     {
1540     }
1541 
1542 protected:
doEvaluate(const EvalContext & ctx) const1543     IVal doEvaluate(const EvalContext &ctx) const
1544     {
1545         const Variable<Arg0> &var0 = static_cast<const Variable<Arg0> &>(*this->m_args.a);
1546         const Variable<Arg1> &var1 = static_cast<const Variable<Arg1> &>(*this->m_args.b);
1547         const Variable<Arg2> &var2 = static_cast<const Variable<Arg2> &>(*this->m_args.c);
1548         const Variable<Arg3> &var3 = static_cast<const Variable<Arg3> &>(*this->m_args.d);
1549         return this->m_func.apply(ctx, ctx.env.lookup(var0), ctx.env.lookup(var1), ctx.env.lookup(var2),
1550                                   ctx.env.lookup(var3));
1551     }
1552 };
1553 
1554 template <typename Sig>
applyVar(const Func<Sig> & func,const VariableP<typename Sig::Arg0> & arg0,const VariableP<typename Sig::Arg1> & arg1,const VariableP<typename Sig::Arg2> & arg2,const VariableP<typename Sig::Arg3> & arg3)1555 ExprP<typename Sig::Ret> applyVar(const Func<Sig> &func, const VariableP<typename Sig::Arg0> &arg0,
1556                                   const VariableP<typename Sig::Arg1> &arg1, const VariableP<typename Sig::Arg2> &arg2,
1557                                   const VariableP<typename Sig::Arg3> &arg3)
1558 {
1559     return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1560 }
1561 
1562 template <typename Sig_>
1563 class DerivedFunc : public Func<Sig_>
1564 {
1565 public:
1566     typedef typename DerivedFunc::ArgExprs ArgExprs;
1567     typedef typename DerivedFunc::IRet IRet;
1568     typedef typename DerivedFunc::IArgs IArgs;
1569     typedef typename DerivedFunc::Ret Ret;
1570     typedef typename DerivedFunc::Arg0 Arg0;
1571     typedef typename DerivedFunc::Arg1 Arg1;
1572     typedef typename DerivedFunc::Arg2 Arg2;
1573     typedef typename DerivedFunc::Arg3 Arg3;
1574     typedef typename DerivedFunc::IArg0 IArg0;
1575     typedef typename DerivedFunc::IArg1 IArg1;
1576     typedef typename DerivedFunc::IArg2 IArg2;
1577     typedef typename DerivedFunc::IArg3 IArg3;
1578 
1579 protected:
doPrintDefinition(ostream & os) const1580     void doPrintDefinition(ostream &os) const
1581     {
1582         const ParamNames &paramNames = this->getParamNames();
1583 
1584         initialize();
1585 
1586         os << dataTypeNameOf<Ret>() << " " << this->getName() << "(";
1587         if (isTypeValid<Arg0>())
1588             os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1589         if (isTypeValid<Arg1>())
1590             os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1591         if (isTypeValid<Arg2>())
1592             os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1593         if (isTypeValid<Arg3>())
1594             os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1595         os << ")\n{\n";
1596 
1597         for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1598             os << *m_body[ndx];
1599         os << "return " << *m_ret << ";\n";
1600         os << "}\n";
1601     }
1602 
doApply(const EvalContext & ctx,const IArgs & args) const1603     IRet doApply(const EvalContext &ctx, const IArgs &args) const
1604     {
1605         Environment funEnv;
1606         IArgs &mutArgs = const_cast<IArgs &>(args);
1607         IRet ret;
1608 
1609         initialize();
1610 
1611         funEnv.bind(*m_var0, args.a);
1612         funEnv.bind(*m_var1, args.b);
1613         funEnv.bind(*m_var2, args.c);
1614         funEnv.bind(*m_var3, args.d);
1615 
1616         {
1617             EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1618 
1619             for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1620                 m_body[ndx]->execute(funCtx);
1621 
1622             ret = m_ret->evaluate(funCtx);
1623         }
1624 
1625         // \todo [lauri] Store references instead of values in environment
1626         const_cast<IArg0 &>(mutArgs.a) = funEnv.lookup(*m_var0);
1627         const_cast<IArg1 &>(mutArgs.b) = funEnv.lookup(*m_var1);
1628         const_cast<IArg2 &>(mutArgs.c) = funEnv.lookup(*m_var2);
1629         const_cast<IArg3 &>(mutArgs.d) = funEnv.lookup(*m_var3);
1630 
1631         return ret;
1632     }
1633 
doGetUsedFuncs(FuncSet & dst) const1634     void doGetUsedFuncs(FuncSet &dst) const
1635     {
1636         initialize();
1637         if (dst.insert(this).second)
1638         {
1639             for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1640                 m_body[ndx]->getUsedFuncs(dst);
1641             m_ret->getUsedFuncs(dst);
1642         }
1643     }
1644 
1645     virtual ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args_) const = 0;
1646 
1647     // These are transparently initialized when first needed. They cannot be
1648     // initialized in the constructor because they depend on the doExpand
1649     // method of the subclass.
1650 
1651     mutable VariableP<Arg0> m_var0;
1652     mutable VariableP<Arg1> m_var1;
1653     mutable VariableP<Arg2> m_var2;
1654     mutable VariableP<Arg3> m_var3;
1655     mutable vector<StatementP> m_body;
1656     mutable ExprP<Ret> m_ret;
1657 
1658 private:
initialize(void) const1659     void initialize(void) const
1660     {
1661         if (!m_ret)
1662         {
1663             const ParamNames &paramNames = this->getParamNames();
1664             Counter symCounter;
1665             ExpandContext ctx(symCounter);
1666             ArgExprs args;
1667 
1668             args.a = m_var0 = variable<Arg0>(paramNames.a);
1669             args.b = m_var1 = variable<Arg1>(paramNames.b);
1670             args.c = m_var2 = variable<Arg2>(paramNames.c);
1671             args.d = m_var3 = variable<Arg3>(paramNames.d);
1672 
1673             m_ret  = this->doExpand(ctx, args);
1674             m_body = ctx.getStatements();
1675         }
1676     }
1677 };
1678 
1679 template <typename Sig>
1680 class PrimitiveFunc : public Func<Sig>
1681 {
1682 public:
1683     typedef typename PrimitiveFunc::Ret Ret;
1684     typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1685 
1686 protected:
doPrintDefinition(ostream &) const1687     void doPrintDefinition(ostream &) const
1688     {
1689     }
doGetUsedFuncs(FuncSet &) const1690     void doGetUsedFuncs(FuncSet &) const
1691     {
1692     }
1693 };
1694 
1695 template <typename T>
1696 class Cond : public PrimitiveFunc<Signature<T, bool, T, T>>
1697 {
1698 public:
1699     typedef typename Cond::IArgs IArgs;
1700     typedef typename Cond::IRet IRet;
1701 
getName(void) const1702     string getName(void) const
1703     {
1704         return "_cond";
1705     }
1706 
1707 protected:
doPrint(ostream & os,const BaseArgExprs & args) const1708     void doPrint(ostream &os, const BaseArgExprs &args) const
1709     {
1710         os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1711     }
1712 
doApply(const EvalContext &,const IArgs & iargs) const1713     IRet doApply(const EvalContext &, const IArgs &iargs) const
1714     {
1715         IRet ret;
1716 
1717         if (iargs.a.contains(true))
1718             ret = unionIVal<T>(ret, iargs.b);
1719 
1720         if (iargs.a.contains(false))
1721             ret = unionIVal<T>(ret, iargs.c);
1722 
1723         return ret;
1724     }
1725 };
1726 
1727 template <typename T>
1728 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T>>
1729 {
1730 public:
1731     typedef typename CompareOperator::IArgs IArgs;
1732     typedef typename CompareOperator::IArg0 IArg0;
1733     typedef typename CompareOperator::IArg1 IArg1;
1734     typedef typename CompareOperator::IRet IRet;
1735 
1736 protected:
doPrint(ostream & os,const BaseArgExprs & args) const1737     void doPrint(ostream &os, const BaseArgExprs &args) const
1738     {
1739         os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1740     }
1741 
doApply(const EvalContext &,const IArgs & iargs) const1742     Interval doApply(const EvalContext &, const IArgs &iargs) const
1743     {
1744         const IArg0 &arg0 = iargs.a;
1745         const IArg1 &arg1 = iargs.b;
1746         IRet ret;
1747 
1748         if (canSucceed(arg0, arg1))
1749             ret |= true;
1750         if (canFail(arg0, arg1))
1751             ret |= false;
1752 
1753         return ret;
1754     }
1755 
1756     virtual string getSymbol(void) const                        = 0;
1757     virtual bool canSucceed(const IArg0 &, const IArg1 &) const = 0;
1758     virtual bool canFail(const IArg0 &, const IArg1 &) const    = 0;
1759 };
1760 
1761 template <typename T>
1762 class LessThan : public CompareOperator<T>
1763 {
1764 public:
getName(void) const1765     string getName(void) const
1766     {
1767         return "lessThan";
1768     }
1769 
1770 protected:
getSymbol(void) const1771     string getSymbol(void) const
1772     {
1773         return "<";
1774     }
1775 
canSucceed(const Interval & a,const Interval & b) const1776     bool canSucceed(const Interval &a, const Interval &b) const
1777     {
1778         return (a.lo() < b.hi());
1779     }
1780 
canFail(const Interval & a,const Interval & b) const1781     bool canFail(const Interval &a, const Interval &b) const
1782     {
1783         return !(a.hi() < b.lo());
1784     }
1785 };
1786 
1787 template <typename T>
operator <(const ExprP<T> & a,const ExprP<T> & b)1788 ExprP<bool> operator<(const ExprP<T> &a, const ExprP<T> &b)
1789 {
1790     return app<LessThan<T>>(a, b);
1791 }
1792 
1793 template <typename T>
cond(const ExprP<bool> & test,const ExprP<T> & consequent,const ExprP<T> & alternative)1794 ExprP<T> cond(const ExprP<bool> &test, const ExprP<T> &consequent, const ExprP<T> &alternative)
1795 {
1796     return app<Cond<T>>(test, consequent, alternative);
1797 }
1798 
1799 /*--------------------------------------------------------------------*//*!
1800  *
1801  * @}
1802  *
1803  *//*--------------------------------------------------------------------*/
1804 
1805 class FloatFunc1 : public PrimitiveFunc<Signature<float, float>>
1806 {
1807 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const1808     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
1809     {
1810         return this->applyMonotone(ctx, iargs.a);
1811     }
1812 
applyMonotone(const EvalContext & ctx,const Interval & iarg0) const1813     Interval applyMonotone(const EvalContext &ctx, const Interval &iarg0) const
1814     {
1815         Interval ret;
1816 
1817         TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1818                                      TCU_SET_INTERVAL(val, point, point = this->applyPoint(ctx, arg0)));
1819 
1820         ret |= innerExtrema(ctx, iarg0);
1821         ret &= (this->getCodomain() | TCU_NAN);
1822 
1823         return ctx.format.convert(ret);
1824     }
1825 
innerExtrema(const EvalContext &,const Interval &) const1826     virtual Interval innerExtrema(const EvalContext &, const Interval &) const
1827     {
1828         return Interval(); // empty interval, i.e. no extrema
1829     }
1830 
applyPoint(const EvalContext & ctx,double arg0) const1831     virtual Interval applyPoint(const EvalContext &ctx, double arg0) const
1832     {
1833         const double exact = this->applyExact(arg0);
1834         const double prec  = this->precision(ctx, exact, arg0);
1835         const double wprec = this->warningPrecision(ctx, exact, arg0);
1836         Interval ioutput   = exact + Interval(-prec, prec);
1837         ioutput.warning(exact - wprec, exact + wprec);
1838         return ioutput;
1839     }
1840 
applyExact(double) const1841     virtual double applyExact(double) const
1842     {
1843         TCU_THROW(InternalError, "Cannot apply");
1844     }
1845 
getCodomain(void) const1846     virtual Interval getCodomain(void) const
1847     {
1848         return Interval::unbounded(true);
1849     }
1850 
1851     virtual double precision(const EvalContext &ctx, double, double) const = 0;
1852 
warningPrecision(const EvalContext & ctx,double exact,double arg0) const1853     virtual double warningPrecision(const EvalContext &ctx, double exact, double arg0) const
1854     {
1855         return precision(ctx, exact, arg0);
1856     }
1857 };
1858 
1859 class CFloatFunc1 : public FloatFunc1
1860 {
1861 public:
CFloatFunc1(const string & name,DoubleFunc1 & func)1862     CFloatFunc1(const string &name, DoubleFunc1 &func) : m_name(name), m_func(func)
1863     {
1864     }
1865 
getName(void) const1866     string getName(void) const
1867     {
1868         return m_name;
1869     }
1870 
1871 protected:
applyExact(double x) const1872     double applyExact(double x) const
1873     {
1874         return m_func(x);
1875     }
1876 
1877     const string m_name;
1878     DoubleFunc1 &m_func;
1879 };
1880 
1881 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float>>
1882 {
1883 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const1884     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
1885     {
1886         return this->applyMonotone(ctx, iargs.a, iargs.b);
1887     }
1888 
applyMonotone(const EvalContext & ctx,const Interval & xi,const Interval & yi) const1889     Interval applyMonotone(const EvalContext &ctx, const Interval &xi, const Interval &yi) const
1890     {
1891         Interval reti;
1892 
1893         TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1894                                      TCU_SET_INTERVAL(ret, point, point = this->applyPoint(ctx, x, y)));
1895         reti |= innerExtrema(ctx, xi, yi);
1896         reti &= (this->getCodomain() | TCU_NAN);
1897 
1898         return ctx.format.convert(reti);
1899     }
1900 
innerExtrema(const EvalContext &,const Interval &,const Interval &) const1901     virtual Interval innerExtrema(const EvalContext &, const Interval &, const Interval &) const
1902     {
1903         return Interval(); // empty interval, i.e. no extrema
1904     }
1905 
applyPoint(const EvalContext & ctx,double x,double y) const1906     virtual Interval applyPoint(const EvalContext &ctx, double x, double y) const
1907     {
1908         const double exact = this->applyExact(x, y);
1909         const double prec  = this->precision(ctx, exact, x, y);
1910 
1911         return exact + Interval(-prec, prec);
1912     }
1913 
applyExact(double,double) const1914     virtual double applyExact(double, double) const
1915     {
1916         TCU_THROW(InternalError, "Cannot apply");
1917     }
1918 
getCodomain(void) const1919     virtual Interval getCodomain(void) const
1920     {
1921         return Interval::unbounded(true);
1922     }
1923 
1924     virtual double precision(const EvalContext &ctx, double ret, double x, double y) const = 0;
1925 };
1926 
1927 class CFloatFunc2 : public FloatFunc2
1928 {
1929 public:
CFloatFunc2(const string & name,DoubleFunc2 & func)1930     CFloatFunc2(const string &name, DoubleFunc2 &func) : m_name(name), m_func(func)
1931     {
1932     }
1933 
getName(void) const1934     string getName(void) const
1935     {
1936         return m_name;
1937     }
1938 
1939 protected:
applyExact(double x,double y) const1940     double applyExact(double x, double y) const
1941     {
1942         return m_func(x, y);
1943     }
1944 
1945     const string m_name;
1946     DoubleFunc2 &m_func;
1947 };
1948 
1949 class InfixOperator : public FloatFunc2
1950 {
1951 protected:
1952     virtual string getSymbol(void) const = 0;
1953 
doPrint(ostream & os,const BaseArgExprs & args) const1954     void doPrint(ostream &os, const BaseArgExprs &args) const
1955     {
1956         os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1957     }
1958 
applyPoint(const EvalContext & ctx,double x,double y) const1959     Interval applyPoint(const EvalContext &ctx, double x, double y) const
1960     {
1961         const double exact = this->applyExact(x, y);
1962 
1963         // Allow either representable number on both sides of the exact value,
1964         // but require exactly representable values to be preserved.
1965         return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1966     }
1967 
precision(const EvalContext &,double,double,double) const1968     double precision(const EvalContext &, double, double, double) const
1969     {
1970         return 0.0;
1971     }
1972 };
1973 
1974 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float>>
1975 {
1976 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const1977     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
1978     {
1979         return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1980     }
1981 
applyMonotone(const EvalContext & ctx,const Interval & xi,const Interval & yi,const Interval & zi) const1982     Interval applyMonotone(const EvalContext &ctx, const Interval &xi, const Interval &yi, const Interval &zi) const
1983     {
1984         Interval reti;
1985         TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1986                                      TCU_SET_INTERVAL(ret, point, point = this->applyPoint(ctx, x, y, z)));
1987         return ctx.format.convert(reti);
1988     }
1989 
applyPoint(const EvalContext & ctx,double x,double y,double z) const1990     virtual Interval applyPoint(const EvalContext &ctx, double x, double y, double z) const
1991     {
1992         const double exact = this->applyExact(x, y, z);
1993         const double prec  = this->precision(ctx, exact, x, y, z);
1994         return exact + Interval(-prec, prec);
1995     }
1996 
applyExact(double,double,double) const1997     virtual double applyExact(double, double, double) const
1998     {
1999         TCU_THROW(InternalError, "Cannot apply");
2000     }
2001 
2002     virtual double precision(const EvalContext &ctx, double result, double x, double y, double z) const = 0;
2003 };
2004 
2005 // We define syntactic sugar functions for expression constructors. Since
2006 // these have the same names as ordinary mathematical operations (sin, log
2007 // etc.), it's better to give them a dedicated namespace.
2008 namespace Functions
2009 {
2010 
2011 using namespace tcu;
2012 
2013 class Add : public InfixOperator
2014 {
2015 public:
getName(void) const2016     string getName(void) const
2017     {
2018         return "add";
2019     }
getSymbol(void) const2020     string getSymbol(void) const
2021     {
2022         return "+";
2023     }
2024 
doApply(const EvalContext & ctx,const IArgs & iargs) const2025     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
2026     {
2027         // Fast-path for common case
2028         if (iargs.a.isOrdinary(ctx.format.getMaxValue()) && iargs.b.isOrdinary(ctx.format.getMaxValue()))
2029         {
2030             Interval ret;
2031             TCU_SET_INTERVAL_BOUNDS(ret, sum, sum = iargs.a.lo() + iargs.b.lo(), sum = iargs.a.hi() + iargs.b.hi());
2032             return ctx.format.convert(ctx.format.roundOut(ret, true));
2033         }
2034         return this->applyMonotone(ctx, iargs.a, iargs.b);
2035     }
2036 
2037 protected:
applyExact(double x,double y) const2038     double applyExact(double x, double y) const
2039     {
2040         return x + y;
2041     }
2042 };
2043 
2044 class Mul : public InfixOperator
2045 {
2046 public:
getName(void) const2047     string getName(void) const
2048     {
2049         return "mul";
2050     }
getSymbol(void) const2051     string getSymbol(void) const
2052     {
2053         return "*";
2054     }
2055 
doApply(const EvalContext & ctx,const IArgs & iargs) const2056     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
2057     {
2058         Interval a = iargs.a;
2059         Interval b = iargs.b;
2060 
2061         // Fast-path for common case
2062         if (a.isOrdinary(ctx.format.getMaxValue()) && b.isOrdinary(ctx.format.getMaxValue()))
2063         {
2064             Interval ret;
2065             if (a.hi() < 0)
2066             {
2067                 a = -a;
2068                 b = -b;
2069             }
2070             if (a.lo() >= 0 && b.lo() >= 0)
2071             {
2072                 TCU_SET_INTERVAL_BOUNDS(ret, prod, prod = iargs.a.lo() * iargs.b.lo(),
2073                                         prod = iargs.a.hi() * iargs.b.hi());
2074                 return ctx.format.convert(ctx.format.roundOut(ret, true));
2075             }
2076             if (a.lo() >= 0 && b.hi() <= 0)
2077             {
2078                 TCU_SET_INTERVAL_BOUNDS(ret, prod, prod = iargs.a.hi() * iargs.b.lo(),
2079                                         prod = iargs.a.lo() * iargs.b.hi());
2080                 return ctx.format.convert(ctx.format.roundOut(ret, true));
2081             }
2082         }
2083         return this->applyMonotone(ctx, iargs.a, iargs.b);
2084     }
2085 
2086 protected:
applyExact(double x,double y) const2087     double applyExact(double x, double y) const
2088     {
2089         return x * y;
2090     }
2091 
innerExtrema(const EvalContext &,const Interval & xi,const Interval & yi) const2092     Interval innerExtrema(const EvalContext &, const Interval &xi, const Interval &yi) const
2093     {
2094         if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
2095             ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
2096             return Interval(TCU_NAN);
2097 
2098         return Interval();
2099     }
2100 };
2101 
2102 class Sub : public InfixOperator
2103 {
2104 public:
getName(void) const2105     string getName(void) const
2106     {
2107         return "sub";
2108     }
getSymbol(void) const2109     string getSymbol(void) const
2110     {
2111         return "-";
2112     }
2113 
doApply(const EvalContext & ctx,const IArgs & iargs) const2114     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
2115     {
2116         // Fast-path for common case
2117         if (iargs.a.isOrdinary(ctx.format.getMaxValue()) && iargs.b.isOrdinary(ctx.format.getMaxValue()))
2118         {
2119             Interval ret;
2120 
2121             TCU_SET_INTERVAL_BOUNDS(ret, diff, diff = iargs.a.lo() - iargs.b.hi(), diff = iargs.a.hi() - iargs.b.lo());
2122             return ctx.format.convert(ctx.format.roundOut(ret, true));
2123         }
2124         else
2125         {
2126             return this->applyMonotone(ctx, iargs.a, iargs.b);
2127         }
2128     }
2129 
2130 protected:
applyExact(double x,double y) const2131     double applyExact(double x, double y) const
2132     {
2133         return x - y;
2134     }
2135 };
2136 
2137 class Negate : public FloatFunc1
2138 {
2139 public:
getName(void) const2140     string getName(void) const
2141     {
2142         return "_negate";
2143     }
doPrint(ostream & os,const BaseArgExprs & args) const2144     void doPrint(ostream &os, const BaseArgExprs &args) const
2145     {
2146         os << "-" << *args[0];
2147     }
2148 
2149 protected:
precision(const EvalContext &,double,double) const2150     double precision(const EvalContext &, double, double) const
2151     {
2152         return 0.0;
2153     }
applyExact(double x) const2154     double applyExact(double x) const
2155     {
2156         return -x;
2157     }
2158 };
2159 
2160 class Div : public InfixOperator
2161 {
2162 public:
getName(void) const2163     string getName(void) const
2164     {
2165         return "div";
2166     }
2167 
2168 protected:
getSymbol(void) const2169     string getSymbol(void) const
2170     {
2171         return "/";
2172     }
2173 
innerExtrema(const EvalContext &,const Interval & nom,const Interval & den) const2174     Interval innerExtrema(const EvalContext &, const Interval &nom, const Interval &den) const
2175     {
2176         Interval ret;
2177 
2178         if (den.contains(0.0))
2179         {
2180             if (nom.contains(0.0))
2181                 ret |= TCU_NAN;
2182 
2183             if (nom.lo() < 0.0 || nom.hi() > 0.0)
2184                 ret |= Interval::unbounded();
2185         }
2186 
2187         return ret;
2188     }
2189 
applyExact(double x,double y) const2190     double applyExact(double x, double y) const
2191     {
2192         return x / y;
2193     }
2194 
applyPoint(const EvalContext & ctx,double x,double y) const2195     Interval applyPoint(const EvalContext &ctx, double x, double y) const
2196     {
2197         Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2198 
2199         if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2200         {
2201             const Interval dst = ctx.format.convert(ret);
2202             if (dst.contains(-TCU_INFINITY))
2203                 ret |= -ctx.format.getMaxValue();
2204             if (dst.contains(+TCU_INFINITY))
2205                 ret |= +ctx.format.getMaxValue();
2206         }
2207 
2208         return ret;
2209     }
2210 
precision(const EvalContext & ctx,double ret,double,double den) const2211     double precision(const EvalContext &ctx, double ret, double, double den) const
2212     {
2213         const FloatFormat &fmt = ctx.format;
2214 
2215         // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2216         // For now, we assume that division's precision is 2.5 ULP when the value is within
2217         // [2^MINEXP, 2^MAXEXP-1]
2218 
2219         if (den == 0.0)
2220             return 0.0; // Result must be exactly inf
2221         else if (de::inBounds(deAbs(den), deLdExp(1.0, fmt.getMinExp()), deLdExp(1.0, fmt.getMaxExp() - 1)))
2222             return fmt.ulp(ret, 2.5);
2223         else
2224             return TCU_INFINITY; // Can be any number, but must be a number.
2225     }
2226 };
2227 
2228 class InverseSqrt : public FloatFunc1
2229 {
2230 public:
getName(void) const2231     string getName(void) const
2232     {
2233         return "inversesqrt";
2234     }
2235 
2236 protected:
applyExact(double x) const2237     double applyExact(double x) const
2238     {
2239         return 1.0 / deSqrt(x);
2240     }
2241 
precision(const EvalContext & ctx,double ret,double x) const2242     double precision(const EvalContext &ctx, double ret, double x) const
2243     {
2244         return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2245     }
2246 
getCodomain(void) const2247     Interval getCodomain(void) const
2248     {
2249         return Interval(0.0, TCU_INFINITY);
2250     }
2251 };
2252 
2253 class ExpFunc : public CFloatFunc1
2254 {
2255 public:
ExpFunc(const string & name,DoubleFunc1 & func)2256     ExpFunc(const string &name, DoubleFunc1 &func) : CFloatFunc1(name, func)
2257     {
2258     }
2259 
2260 protected:
precision(const EvalContext & ctx,double ret,double x) const2261     double precision(const EvalContext &ctx, double ret, double x) const
2262     {
2263         switch (ctx.floatPrecision)
2264         {
2265         case glu::PRECISION_HIGHP:
2266             return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2267         case glu::PRECISION_MEDIUMP:
2268             return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2269         case glu::PRECISION_LOWP:
2270             return ctx.format.ulp(ret, 2.0);
2271         default:
2272             DE_FATAL("Impossible");
2273         }
2274         return 0;
2275     }
2276 
getCodomain(void) const2277     Interval getCodomain(void) const
2278     {
2279         return Interval(0.0, TCU_INFINITY);
2280     }
2281 };
2282 
2283 class Exp2 : public ExpFunc
2284 {
2285 public:
Exp2(void)2286     Exp2(void) : ExpFunc("exp2", deExp2)
2287     {
2288     }
2289 };
2290 class Exp : public ExpFunc
2291 {
2292 public:
Exp(void)2293     Exp(void) : ExpFunc("exp", deExp)
2294     {
2295     }
2296 };
2297 
exp2(const ExprP<float> & x)2298 ExprP<float> exp2(const ExprP<float> &x)
2299 {
2300     return app<Exp2>(x);
2301 }
exp(const ExprP<float> & x)2302 ExprP<float> exp(const ExprP<float> &x)
2303 {
2304     return app<Exp>(x);
2305 }
2306 
2307 class LogFunc : public CFloatFunc1
2308 {
2309 public:
LogFunc(const string & name,DoubleFunc1 & func)2310     LogFunc(const string &name, DoubleFunc1 &func) : CFloatFunc1(name, func)
2311     {
2312     }
2313 
2314 protected:
precision(const EvalContext & ctx,double ret,double x) const2315     double precision(const EvalContext &ctx, double ret, double x) const
2316     {
2317         if (x <= 0)
2318             return TCU_NAN;
2319 
2320         switch (ctx.floatPrecision)
2321         {
2322         case glu::PRECISION_HIGHP:
2323             return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2324         case glu::PRECISION_MEDIUMP:
2325             return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2326         case glu::PRECISION_LOWP:
2327             return ctx.format.ulp(ret, 2.0);
2328         default:
2329             DE_FATAL("Impossible");
2330         }
2331 
2332         return 0;
2333     }
2334 
2335     // OpenGL API Issue #57 "Clarifying the required ULP precision for GLSL built-in log()". Agreed that
2336     // implementations will be allowed 4 ULPs for HIGHP Log/Log2, but CTS should generate a quality warning.
warningPrecision(const EvalContext & ctx,double ret,double x) const2337     double warningPrecision(const EvalContext &ctx, double ret, double x) const
2338     {
2339         if (ctx.floatPrecision == glu::PRECISION_HIGHP && x > 0)
2340         {
2341             return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 4.0);
2342         }
2343         else
2344         {
2345             return precision(ctx, ret, x);
2346         }
2347     }
2348 };
2349 
2350 class Log2 : public LogFunc
2351 {
2352 public:
Log2(void)2353     Log2(void) : LogFunc("log2", deLog2)
2354     {
2355     }
2356 };
2357 class Log : public LogFunc
2358 {
2359 public:
Log(void)2360     Log(void) : LogFunc("log", deLog)
2361     {
2362     }
2363 };
2364 
log2(const ExprP<float> & x)2365 ExprP<float> log2(const ExprP<float> &x)
2366 {
2367     return app<Log2>(x);
2368 }
log(const ExprP<float> & x)2369 ExprP<float> log(const ExprP<float> &x)
2370 {
2371     return app<Log>(x);
2372 }
2373 
2374 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2375     ExprP<TRET> NAME(const ExprP<T0> &arg0)        \
2376     {                                              \
2377         return app<CLASS>(arg0);                   \
2378     }
2379 
2380 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION)                   \
2381     class CLASS : public DerivedFunc<Signature<TRET, T0>> /* NOLINT(CLASS) */     \
2382     {                                                                             \
2383     public:                                                                       \
2384         string getName(void) const                                                \
2385         {                                                                         \
2386             return #NAME;                                                         \
2387         }                                                                         \
2388                                                                                   \
2389     protected:                                                                    \
2390         ExprP<TRET> doExpand(ExpandContext &, const CLASS::ArgExprs &args_) const \
2391         {                                                                         \
2392             const ExprP<float> &ARG0 = args_.a;                                   \
2393             return EXPANSION;                                                     \
2394         }                                                                         \
2395     };                                                                            \
2396     DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2397 
2398 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2399 
2400 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)             \
2401     ExprP<TRET> NAME(const ExprP<T0> &arg0, const ExprP<T1> &arg1) \
2402     {                                                              \
2403         return app<CLASS>(arg0, arg1);                             \
2404     }
2405 
2406 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION)         \
2407     class CLASS : public DerivedFunc<Signature<TRET, T0, T1>> /* NOLINT(CLASS) */ \
2408     {                                                                             \
2409     public:                                                                       \
2410         string getName(void) const                                                \
2411         {                                                                         \
2412             return #NAME;                                                         \
2413         }                                                                         \
2414                                                                                   \
2415     protected:                                                                    \
2416         ExprP<TRET> doExpand(ExpandContext &, const ArgExprs &args_) const        \
2417         {                                                                         \
2418             const ExprP<T0> &Arg0 = args_.a;                                      \
2419             const ExprP<T1> &Arg1 = args_.b;                                      \
2420             return EXPANSION;                                                     \
2421         }                                                                         \
2422     };                                                                            \
2423     DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2424 
2425 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2426     DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2427 
2428 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)                                \
2429     ExprP<TRET> NAME(const ExprP<T0> &arg0, const ExprP<T1> &arg1, const ExprP<T2> &arg2) \
2430     {                                                                                     \
2431         return app<CLASS>(arg0, arg1, arg2);                                              \
2432     }
2433 
2434 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION)   \
2435     class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2>> /* NOLINT(CLASS) */ \
2436     {                                                                                 \
2437     public:                                                                           \
2438         string getName(void) const                                                    \
2439         {                                                                             \
2440             return #NAME;                                                             \
2441         }                                                                             \
2442                                                                                       \
2443     protected:                                                                        \
2444         ExprP<TRET> doExpand(ExpandContext &, const ArgExprs &args_) const            \
2445         {                                                                             \
2446             const ExprP<T0> &ARG0 = args_.a;                                          \
2447             const ExprP<T1> &ARG1 = args_.b;                                          \
2448             const ExprP<T2> &ARG2 = args_.c;                                          \
2449             return EXPANSION;                                                         \
2450         }                                                                             \
2451     };                                                                                \
2452     DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2453 
2454 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2455     DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2456 
2457 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3)                                                   \
2458     ExprP<TRET> NAME(const ExprP<T0> &arg0, const ExprP<T1> &arg1, const ExprP<T2> &arg2, const ExprP<T3> &arg3) \
2459     {                                                                                                            \
2460         return app<CLASS>(arg0, arg1, arg2, arg3);                                                               \
2461     }
2462 
2463 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, (x == 0.0f ? constant(1.0f) : (constant(1.0f) / app<InverseSqrt>(x))))
2464 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y *log2(x)))
2465 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d)
2466 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r)
2467 
2468 class TrigFunc : public CFloatFunc1
2469 {
2470 public:
TrigFunc(const string & name,DoubleFunc1 & func,const Interval & loEx,const Interval & hiEx)2471     TrigFunc(const string &name, DoubleFunc1 &func, const Interval &loEx, const Interval &hiEx)
2472         : CFloatFunc1(name, func)
2473         , m_loExtremum(loEx)
2474         , m_hiExtremum(hiEx)
2475     {
2476     }
2477 
2478 protected:
innerExtrema(const EvalContext &,const Interval & angle) const2479     Interval innerExtrema(const EvalContext &, const Interval &angle) const
2480     {
2481         const double lo   = angle.lo();
2482         const double hi   = angle.hi();
2483         const int loSlope = doGetSlope(lo);
2484         const int hiSlope = doGetSlope(hi);
2485 
2486         // Detect the high and low values the function can take between the
2487         // interval endpoints.
2488         if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2489         {
2490             // The interval is longer than a full cycle, so it must get all possible values.
2491             return m_hiExtremum | m_loExtremum;
2492         }
2493         else if (loSlope == 1 && hiSlope == -1)
2494         {
2495             // The slope can change from positive to negative only at the maximum value.
2496             return m_hiExtremum;
2497         }
2498         else if (loSlope == -1 && hiSlope == 1)
2499         {
2500             // The slope can change from negative to positive only at the maximum value.
2501             return m_loExtremum;
2502         }
2503         else if (loSlope == hiSlope && deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2504         {
2505             // The slope has changed twice between the endpoints, so both extrema are included.
2506             return m_hiExtremum | m_loExtremum;
2507         }
2508 
2509         return Interval();
2510     }
2511 
getCodomain(void) const2512     Interval getCodomain(void) const
2513     {
2514         // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2515         return Interval(-1.0, 1.0) | TCU_NAN;
2516     }
2517 
precision(const EvalContext & ctx,double ret,double arg) const2518     double precision(const EvalContext &ctx, double ret, double arg) const
2519     {
2520         if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2521         {
2522             // Use precision from OpenCL fast relaxed math
2523             if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2524             {
2525                 return deLdExp(1.0, -11);
2526             }
2527             else
2528             {
2529                 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2530                 // 2^-11 at x == pi.
2531                 return deLdExp(deAbs(arg), -12);
2532             }
2533         }
2534         else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2535         {
2536             if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2537             {
2538                 // from OpenCL half-float extension specification
2539                 return ctx.format.ulp(ret, 2.0);
2540             }
2541             else
2542             {
2543                 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2544                 return deLdExp(deAbs(arg), -10);
2545             }
2546         }
2547         else
2548         {
2549             DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2550 
2551             // from OpenCL half-float extension specification
2552             return ctx.format.ulp(ret, 2.0);
2553         }
2554     }
2555 
2556     virtual int doGetSlope(double angle) const = 0;
2557 
2558     Interval m_loExtremum;
2559     Interval m_hiExtremum;
2560 };
2561 
2562 class Sin : public TrigFunc
2563 {
2564 public:
Sin(void)2565     Sin(void) : TrigFunc("sin", deSin, -1.0, 1.0)
2566     {
2567     }
2568 
2569 protected:
doGetSlope(double angle) const2570     int doGetSlope(double angle) const
2571     {
2572         return deIntSign(deCos(angle));
2573     }
2574 };
2575 
sin(const ExprP<float> & x)2576 ExprP<float> sin(const ExprP<float> &x)
2577 {
2578     return app<Sin>(x);
2579 }
2580 
2581 class Cos : public TrigFunc
2582 {
2583 public:
Cos(void)2584     Cos(void) : TrigFunc("cos", deCos, -1.0, 1.0)
2585     {
2586     }
2587 
2588 protected:
doGetSlope(double angle) const2589     int doGetSlope(double angle) const
2590     {
2591         return -deIntSign(deSin(angle));
2592     }
2593 };
2594 
cos(const ExprP<float> & x)2595 ExprP<float> cos(const ExprP<float> &x)
2596 {
2597     return app<Cos>(x);
2598 }
2599 
2600 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)))
2601 
2602 class ASin : public CFloatFunc1
2603 {
2604 public:
ASin(void)2605     ASin(void) : CFloatFunc1("asin", deAsin)
2606     {
2607     }
2608 
2609 protected:
precision(const EvalContext & ctx,double,double x) const2610     double precision(const EvalContext &ctx, double, double x) const
2611     {
2612         if (!de::inBounds(x, -1.0, 1.0))
2613             return TCU_NAN;
2614 
2615         if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2616         {
2617             // Absolute error of 2^-11
2618             return deLdExp(1.0, -11);
2619         }
2620         else
2621         {
2622             // Absolute error of 2^-8
2623             return deLdExp(1.0, -8);
2624         }
2625     }
2626 };
2627 
2628 class ArcTrigFunc : public CFloatFunc1
2629 {
2630 public:
ArcTrigFunc(const string & name,DoubleFunc1 & func,double precisionULPs,const Interval & domain,const Interval & codomain)2631     ArcTrigFunc(const string &name, DoubleFunc1 &func, double precisionULPs, const Interval &domain,
2632                 const Interval &codomain)
2633         : CFloatFunc1(name, func)
2634         , m_precision(precisionULPs)
2635         , m_domain(domain)
2636         , m_codomain(codomain)
2637     {
2638     }
2639 
2640 protected:
precision(const EvalContext & ctx,double ret,double x) const2641     double precision(const EvalContext &ctx, double ret, double x) const
2642     {
2643         if (!m_domain.contains(x))
2644             return TCU_NAN;
2645 
2646         if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2647         {
2648             // Use OpenCL's fast relaxed math precision
2649             return ctx.format.ulp(ret, m_precision);
2650         }
2651         else
2652         {
2653             // Use OpenCL half-float spec
2654             return ctx.format.ulp(ret, 2.0);
2655         }
2656     }
2657 
2658     // We could implement getCodomain with m_codomain, but choose not to,
2659     // because it seems too strict with trascendental constants like pi.
2660 
2661     const double m_precision;
2662     const Interval m_domain;
2663     const Interval m_codomain;
2664 };
2665 
2666 class ACos : public ArcTrigFunc
2667 {
2668 public:
ACos(void)2669     ACos(void) : ArcTrigFunc("acos", deAcos, 4096.0, Interval(-1.0, 1.0), Interval(0.0, DE_PI_DOUBLE))
2670     {
2671     }
2672 };
2673 
2674 class ATan : public ArcTrigFunc
2675 {
2676 public:
ATan(void)2677     ATan(void)
2678         : ArcTrigFunc("atan", deAtanOver, 4096.0, Interval::unbounded(),
2679                       Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5))
2680     {
2681     }
2682 };
2683 
2684 class ATan2 : public CFloatFunc2
2685 {
2686 public:
ATan2(void)2687     ATan2(void) : CFloatFunc2("atan", deAtan2)
2688     {
2689     }
2690 
2691 protected:
innerExtrema(const EvalContext & ctx,const Interval & yi,const Interval & xi) const2692     Interval innerExtrema(const EvalContext &ctx, const Interval &yi, const Interval &xi) const
2693     {
2694         Interval ret;
2695 
2696         if (yi.contains(0.0))
2697         {
2698             if (xi.contains(0.0))
2699                 ret |= TCU_NAN;
2700             if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2701                 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2702         }
2703 
2704         if (!yi.isFinite(ctx.format.getMaxValue()) || !xi.isFinite(ctx.format.getMaxValue()))
2705         {
2706             // Infinities may not be supported, allow anything, including NaN
2707             ret |= TCU_NAN;
2708         }
2709 
2710         return ret;
2711     }
2712 
precision(const EvalContext & ctx,double ret,double,double) const2713     double precision(const EvalContext &ctx, double ret, double, double) const
2714     {
2715         if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2716             return ctx.format.ulp(ret, 4096.0);
2717         else
2718             return ctx.format.ulp(ret, 2.0);
2719     }
2720 
2721     // Codomain could be [-pi, pi], but that would probably be too strict.
2722 };
2723 
2724 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f))
2725 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f))
2726 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x))
2727 
2728 // These are not defined as derived forms in the GLSL ES spec, but
2729 // that gives us a reasonable precision.
2730 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))))
2731 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x,
2732                       log(x +
2733                           sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)), (x * x - constant(1.0f))))))
2734 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) / (constant(1.0f) - x)))
2735 
2736 template <typename T>
2737 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int>>
2738 {
2739 public:
2740     typedef typename GetComponent::IRet IRet;
2741 
getName(void) const2742     string getName(void) const
2743     {
2744         return "_getComponent";
2745     }
2746 
print(ostream & os,const BaseArgExprs & args) const2747     void print(ostream &os, const BaseArgExprs &args) const
2748     {
2749         os << *args[0] << "[" << *args[1] << "]";
2750     }
2751 
2752 protected:
doApply(const EvalContext &,const typename GetComponent::IArgs & iargs) const2753     IRet doApply(const EvalContext &, const typename GetComponent::IArgs &iargs) const
2754     {
2755         IRet ret;
2756 
2757         for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2758         {
2759             if (iargs.b.contains(compNdx))
2760                 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2761         }
2762 
2763         return ret;
2764     }
2765 };
2766 
2767 template <typename T>
getComponent(const ExprP<T> & container,int ndx)2768 ExprP<typename T::Element> getComponent(const ExprP<T> &container, int ndx)
2769 {
2770     DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2771     return app<GetComponent<T>>(container, constant(ndx));
2772 }
2773 
2774 template <typename T>
2775 string vecNamePrefix(void);
2776 template <>
vecNamePrefix(void)2777 string vecNamePrefix<float>(void)
2778 {
2779     return "";
2780 }
2781 template <>
vecNamePrefix(void)2782 string vecNamePrefix<int>(void)
2783 {
2784     return "i";
2785 }
2786 template <>
vecNamePrefix(void)2787 string vecNamePrefix<bool>(void)
2788 {
2789     return "b";
2790 }
2791 
2792 template <typename T, int Size>
vecName(void)2793 string vecName(void)
2794 {
2795     return vecNamePrefix<T>() + "vec" + de::toString(Size);
2796 }
2797 
2798 template <typename T, int Size>
2799 class GenVec;
2800 
2801 template <typename T>
2802 class GenVec<T, 1> : public DerivedFunc<Signature<T, T>>
2803 {
2804 public:
2805     typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2806 
getName(void) const2807     string getName(void) const
2808     {
2809         return "_" + vecName<T, 1>();
2810     }
2811 
2812 protected:
doExpand(ExpandContext &,const ArgExprs & args) const2813     ExprP<T> doExpand(ExpandContext &, const ArgExprs &args) const
2814     {
2815         return args.a;
2816     }
2817 };
2818 
2819 template <typename T>
2820 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T>>
2821 {
2822 public:
2823     typedef typename GenVec::IRet IRet;
2824     typedef typename GenVec::IArgs IArgs;
2825 
getName(void) const2826     string getName(void) const
2827     {
2828         return vecName<T, 2>();
2829     }
2830 
2831 protected:
doApply(const EvalContext &,const IArgs & iargs) const2832     IRet doApply(const EvalContext &, const IArgs &iargs) const
2833     {
2834         return IRet(iargs.a, iargs.b);
2835     }
2836 };
2837 
2838 template <typename T>
2839 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T>>
2840 {
2841 public:
2842     typedef typename GenVec::IRet IRet;
2843     typedef typename GenVec::IArgs IArgs;
2844 
getName(void) const2845     string getName(void) const
2846     {
2847         return vecName<T, 3>();
2848     }
2849 
2850 protected:
doApply(const EvalContext &,const IArgs & iargs) const2851     IRet doApply(const EvalContext &, const IArgs &iargs) const
2852     {
2853         return IRet(iargs.a, iargs.b, iargs.c);
2854     }
2855 };
2856 
2857 template <typename T>
2858 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T>>
2859 {
2860 public:
2861     typedef typename GenVec::IRet IRet;
2862     typedef typename GenVec::IArgs IArgs;
2863 
getName(void) const2864     string getName(void) const
2865     {
2866         return vecName<T, 4>();
2867     }
2868 
2869 protected:
doApply(const EvalContext &,const IArgs & iargs) const2870     IRet doApply(const EvalContext &, const IArgs &iargs) const
2871     {
2872         return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2873     }
2874 };
2875 
2876 template <typename T, int Rows, int Columns>
2877 class GenMat;
2878 
2879 template <typename T, int Rows>
2880 class GenMat<T, Rows, 2> : public PrimitiveFunc<Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows>>>
2881 {
2882 public:
2883     typedef typename GenMat::Ret Ret;
2884     typedef typename GenMat::IRet IRet;
2885     typedef typename GenMat::IArgs IArgs;
2886 
getName(void) const2887     string getName(void) const
2888     {
2889         return dataTypeNameOf<Ret>();
2890     }
2891 
2892 protected:
doApply(const EvalContext &,const IArgs & iargs) const2893     IRet doApply(const EvalContext &, const IArgs &iargs) const
2894     {
2895         IRet ret;
2896         ret[0] = iargs.a;
2897         ret[1] = iargs.b;
2898         return ret;
2899     }
2900 };
2901 
2902 template <typename T, int Rows>
2903 class GenMat<T, Rows, 3>
2904     : public PrimitiveFunc<Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>>>
2905 {
2906 public:
2907     typedef typename GenMat::Ret Ret;
2908     typedef typename GenMat::IRet IRet;
2909     typedef typename GenMat::IArgs IArgs;
2910 
getName(void) const2911     string getName(void) const
2912     {
2913         return dataTypeNameOf<Ret>();
2914     }
2915 
2916 protected:
doApply(const EvalContext &,const IArgs & iargs) const2917     IRet doApply(const EvalContext &, const IArgs &iargs) const
2918     {
2919         IRet ret;
2920         ret[0] = iargs.a;
2921         ret[1] = iargs.b;
2922         ret[2] = iargs.c;
2923         return ret;
2924     }
2925 };
2926 
2927 template <typename T, int Rows>
2928 class GenMat<T, Rows, 4>
2929     : public PrimitiveFunc<
2930           Signature<Matrix<T, Rows, 4>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>>>
2931 {
2932 public:
2933     typedef typename GenMat::Ret Ret;
2934     typedef typename GenMat::IRet IRet;
2935     typedef typename GenMat::IArgs IArgs;
2936 
getName(void) const2937     string getName(void) const
2938     {
2939         return dataTypeNameOf<Ret>();
2940     }
2941 
2942 protected:
doApply(const EvalContext &,const IArgs & iargs) const2943     IRet doApply(const EvalContext &, const IArgs &iargs) const
2944     {
2945         IRet ret;
2946         ret[0] = iargs.a;
2947         ret[1] = iargs.b;
2948         ret[2] = iargs.c;
2949         ret[3] = iargs.d;
2950         return ret;
2951     }
2952 };
2953 
2954 template <typename T, int Rows>
mat2(const ExprP<Vector<T,Rows>> & arg0,const ExprP<Vector<T,Rows>> & arg1)2955 ExprP<Matrix<T, Rows, 2>> mat2(const ExprP<Vector<T, Rows>> &arg0, const ExprP<Vector<T, Rows>> &arg1)
2956 {
2957     return app<GenMat<T, Rows, 2>>(arg0, arg1);
2958 }
2959 
2960 template <typename T, int Rows>
mat3(const ExprP<Vector<T,Rows>> & arg0,const ExprP<Vector<T,Rows>> & arg1,const ExprP<Vector<T,Rows>> & arg2)2961 ExprP<Matrix<T, Rows, 3>> mat3(const ExprP<Vector<T, Rows>> &arg0, const ExprP<Vector<T, Rows>> &arg1,
2962                                const ExprP<Vector<T, Rows>> &arg2)
2963 {
2964     return app<GenMat<T, Rows, 3>>(arg0, arg1, arg2);
2965 }
2966 
2967 template <typename T, int Rows>
mat4(const ExprP<Vector<T,Rows>> & arg0,const ExprP<Vector<T,Rows>> & arg1,const ExprP<Vector<T,Rows>> & arg2,const ExprP<Vector<T,Rows>> & arg3)2968 ExprP<Matrix<T, Rows, 4>> mat4(const ExprP<Vector<T, Rows>> &arg0, const ExprP<Vector<T, Rows>> &arg1,
2969                                const ExprP<Vector<T, Rows>> &arg2, const ExprP<Vector<T, Rows>> &arg3)
2970 {
2971     return app<GenMat<T, Rows, 4>>(arg0, arg1, arg2, arg3);
2972 }
2973 
2974 template <int Rows, int Cols>
2975 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>, Matrix<float, Rows, Cols>>>
2976 {
2977 public:
2978     typedef typename MatNeg::IRet IRet;
2979     typedef typename MatNeg::IArgs IArgs;
2980 
getName(void) const2981     string getName(void) const
2982     {
2983         return "_matNeg";
2984     }
2985 
2986 protected:
doPrint(ostream & os,const BaseArgExprs & args) const2987     void doPrint(ostream &os, const BaseArgExprs &args) const
2988     {
2989         os << "-(" << *args[0] << ")";
2990     }
2991 
doApply(const EvalContext &,const IArgs & iargs) const2992     IRet doApply(const EvalContext &, const IArgs &iargs) const
2993     {
2994         IRet ret;
2995 
2996         for (int col = 0; col < Cols; ++col)
2997         {
2998             for (int row = 0; row < Rows; ++row)
2999                 ret[col][row] = -iargs.a[col][row];
3000         }
3001 
3002         return ret;
3003     }
3004 };
3005 
3006 template <typename T, typename Sig>
3007 class CompWiseFunc : public PrimitiveFunc<Sig>
3008 {
3009 public:
3010     typedef Func<Signature<T, T, T>> ScalarFunc;
3011 
getName(void) const3012     string getName(void) const
3013     {
3014         return doGetScalarFunc().getName();
3015     }
3016 
3017 protected:
doPrint(ostream & os,const BaseArgExprs & args) const3018     void doPrint(ostream &os, const BaseArgExprs &args) const
3019     {
3020         doGetScalarFunc().print(os, args);
3021     }
3022 
3023     virtual const ScalarFunc &doGetScalarFunc(void) const = 0;
3024 };
3025 
3026 template <int Rows, int Cols>
3027 class CompMatFuncBase
3028     : public CompWiseFunc<float,
3029                           Signature<Matrix<float, Rows, Cols>, Matrix<float, Rows, Cols>, Matrix<float, Rows, Cols>>>
3030 {
3031 public:
3032     typedef typename CompMatFuncBase::IRet IRet;
3033     typedef typename CompMatFuncBase::IArgs IArgs;
3034 
3035 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3036     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3037     {
3038         IRet ret;
3039 
3040         for (int col = 0; col < Cols; ++col)
3041         {
3042             for (int row = 0; row < Rows; ++row)
3043                 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b[col][row]);
3044         }
3045 
3046         return ret;
3047     }
3048 };
3049 
3050 template <typename F, int Rows, int Cols>
3051 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
3052 {
3053 protected:
doGetScalarFunc(void) const3054     const typename CompMatFunc::ScalarFunc &doGetScalarFunc(void) const
3055     {
3056         return instance<F>();
3057     }
3058 };
3059 
3060 class ScalarMatrixCompMult : public Mul
3061 {
3062 public:
getName(void) const3063     string getName(void) const
3064     {
3065         return "matrixCompMult";
3066     }
3067 
doPrint(ostream & os,const BaseArgExprs & args) const3068     void doPrint(ostream &os, const BaseArgExprs &args) const
3069     {
3070         Func<Sig>::doPrint(os, args);
3071     }
3072 };
3073 
3074 template <int Rows, int Cols>
3075 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
3076 {
3077 };
3078 
3079 template <int Rows, int Cols>
3080 class ScalarMatFuncBase
3081     : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>, Matrix<float, Rows, Cols>, float>>
3082 {
3083 public:
3084     typedef typename ScalarMatFuncBase::IRet IRet;
3085     typedef typename ScalarMatFuncBase::IArgs IArgs;
3086 
3087 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3088     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3089     {
3090         IRet ret;
3091 
3092         for (int col = 0; col < Cols; ++col)
3093         {
3094             for (int row = 0; row < Rows; ++row)
3095                 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
3096         }
3097 
3098         return ret;
3099     }
3100 };
3101 
3102 template <typename F, int Rows, int Cols>
3103 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
3104 {
3105 protected:
doGetScalarFunc(void) const3106     const typename ScalarMatFunc::ScalarFunc &doGetScalarFunc(void) const
3107     {
3108         return instance<F>();
3109     }
3110 };
3111 
3112 template <typename T, int Size>
3113 struct GenXType;
3114 
3115 template <typename T>
3116 struct GenXType<T, 1>
3117 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType3118     static ExprP<T> genXType(const ExprP<T> &x)
3119     {
3120         return x;
3121     }
3122 };
3123 
3124 template <typename T>
3125 struct GenXType<T, 2>
3126 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType3127     static ExprP<Vector<T, 2>> genXType(const ExprP<T> &x)
3128     {
3129         return app<GenVec<T, 2>>(x, x);
3130     }
3131 };
3132 
3133 template <typename T>
3134 struct GenXType<T, 3>
3135 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType3136     static ExprP<Vector<T, 3>> genXType(const ExprP<T> &x)
3137     {
3138         return app<GenVec<T, 3>>(x, x, x);
3139     }
3140 };
3141 
3142 template <typename T>
3143 struct GenXType<T, 4>
3144 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType3145     static ExprP<Vector<T, 4>> genXType(const ExprP<T> &x)
3146     {
3147         return app<GenVec<T, 4>>(x, x, x, x);
3148     }
3149 };
3150 
3151 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
3152 //! with each element initialized with the expression `x`.
3153 template <typename T, int Size>
genXType(const ExprP<T> & x)3154 ExprP<typename ContainerOf<T, Size>::Container> genXType(const ExprP<T> &x)
3155 {
3156     return GenXType<T, Size>::genXType(x);
3157 }
3158 
3159 typedef GenVec<float, 2> FloatVec2;
3160 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
3161 
3162 typedef GenVec<float, 3> FloatVec3;
3163 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
3164 
3165 typedef GenVec<float, 4> FloatVec4;
3166 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
3167 
3168 template <int Size>
3169 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size>>>
3170 {
3171 public:
3172     typedef typename Dot::ArgExprs ArgExprs;
3173 
getName(void) const3174     string getName(void) const
3175     {
3176         return "dot";
3177     }
3178 
3179 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3180     ExprP<float> doExpand(ExpandContext &, const ArgExprs &args) const
3181     {
3182         ExprP<float> op[Size];
3183         // Precompute all products.
3184         for (int ndx = 0; ndx < Size; ++ndx)
3185             op[ndx] = args.a[ndx] * args.b[ndx];
3186 
3187         int idx[Size];
3188         //Prepare an array of indices.
3189         for (int ndx = 0; ndx < Size; ++ndx)
3190             idx[ndx] = ndx;
3191 
3192         ExprP<float> res = op[0];
3193         // Compute the first dot alternative: SUM(a[i]*b[i]), i = 0 .. Size-1
3194         for (int ndx = 1; ndx < Size; ++ndx)
3195             res = res + op[ndx];
3196 
3197         // Generate all permutations of indices and
3198         // using a permutation compute a dot alternative.
3199         // Generates all possible variants fo summation of products in the dot product expansion expression.
3200         do
3201         {
3202             ExprP<float> alt = constant(0.0f);
3203             for (int ndx = 0; ndx < Size; ++ndx)
3204                 alt = alt + op[idx[ndx]];
3205             res = alternatives(res, alt);
3206         } while (std::next_permutation(idx, idx + Size));
3207 
3208         return res;
3209     }
3210 };
3211 
3212 template <>
3213 class Dot<1> : public DerivedFunc<Signature<float, float, float>>
3214 {
3215 public:
getName(void) const3216     string getName(void) const
3217     {
3218         return "dot";
3219     }
3220 
doExpand(ExpandContext &,const ArgExprs & args) const3221     ExprP<float> doExpand(ExpandContext &, const ArgExprs &args) const
3222     {
3223         return args.a * args.b;
3224     }
3225 };
3226 
3227 template <int Size>
dot(const ExprP<Vector<float,Size>> & x,const ExprP<Vector<float,Size>> & y)3228 ExprP<float> dot(const ExprP<Vector<float, Size>> &x, const ExprP<Vector<float, Size>> &y)
3229 {
3230     return app<Dot<Size>>(x, y);
3231 }
3232 
dot(const ExprP<float> & x,const ExprP<float> & y)3233 ExprP<float> dot(const ExprP<float> &x, const ExprP<float> &y)
3234 {
3235     return app<Dot<1>>(x, y);
3236 }
3237 
3238 template <int Size>
3239 class Length : public DerivedFunc<Signature<float, typename ContainerOf<float, Size>::Container>>
3240 {
3241 public:
3242     typedef typename Length::ArgExprs ArgExprs;
3243 
getName(void) const3244     string getName(void) const
3245     {
3246         return "length";
3247     }
3248 
3249 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3250     ExprP<float> doExpand(ExpandContext &, const ArgExprs &args) const
3251     {
3252         return sqrt(dot(args.a, args.a));
3253     }
3254 };
3255 
3256 template <int Size>
length(const ExprP<typename ContainerOf<float,Size>::Container> & x)3257 ExprP<float> length(const ExprP<typename ContainerOf<float, Size>::Container> &x)
3258 {
3259     return app<Length<Size>>(x);
3260 }
3261 
3262 template <int Size>
3263 class Distance
3264     : public DerivedFunc<
3265           Signature<float, typename ContainerOf<float, Size>::Container, typename ContainerOf<float, Size>::Container>>
3266 {
3267 public:
3268     typedef typename Distance::Ret Ret;
3269     typedef typename Distance::ArgExprs ArgExprs;
3270 
getName(void) const3271     string getName(void) const
3272     {
3273         return "distance";
3274     }
3275 
3276 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3277     ExprP<Ret> doExpand(ExpandContext &, const ArgExprs &args) const
3278     {
3279         return length<Size>(args.a - args.b);
3280     }
3281 };
3282 
3283 // cross
3284 
3285 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3>>
3286 {
3287 public:
getName(void) const3288     string getName(void) const
3289     {
3290         return "cross";
3291     }
3292 
3293 protected:
doExpand(ExpandContext &,const ArgExprs & x) const3294     ExprP<Vec3> doExpand(ExpandContext &, const ArgExprs &x) const
3295     {
3296         return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2], x.a[2] * x.b[0] - x.b[2] * x.a[0],
3297                     x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3298     }
3299 };
3300 
3301 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3302 
3303 template <int Size>
3304 class Normalize
3305     : public DerivedFunc<
3306           Signature<typename ContainerOf<float, Size>::Container, typename ContainerOf<float, Size>::Container>>
3307 {
3308 public:
3309     typedef typename Normalize::Ret Ret;
3310     typedef typename Normalize::ArgExprs ArgExprs;
3311 
getName(void) const3312     string getName(void) const
3313     {
3314         return "normalize";
3315     }
3316 
3317 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3318     ExprP<Ret> doExpand(ExpandContext &, const ArgExprs &args) const
3319     {
3320         return args.a / length<Size>(args.a);
3321     }
3322 };
3323 
3324 template <int Size>
3325 class FaceForward
3326     : public DerivedFunc<
3327           Signature<typename ContainerOf<float, Size>::Container, typename ContainerOf<float, Size>::Container,
3328                     typename ContainerOf<float, Size>::Container, typename ContainerOf<float, Size>::Container>>
3329 {
3330 public:
3331     typedef typename FaceForward::Ret Ret;
3332     typedef typename FaceForward::ArgExprs ArgExprs;
3333 
getName(void) const3334     string getName(void) const
3335     {
3336         return "faceforward";
3337     }
3338 
3339 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3340     ExprP<Ret> doExpand(ExpandContext &, const ArgExprs &args) const
3341     {
3342         return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3343     }
3344 };
3345 
3346 template <int Size, typename Ret, typename Arg0, typename Arg1>
3347 struct ApplyReflect
3348 {
applydeqp::gls::BuiltinPrecisionTests::Functions::ApplyReflect3349     static ExprP<Ret> apply(ExpandContext &ctx, const ExprP<Arg0> &i, const ExprP<Arg1> &n)
3350     {
3351         const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3352 
3353         return i - alternatives((n * dotNI) * constant(2.0f), n * (dotNI * constant(2.0f)));
3354     }
3355 };
3356 
3357 template <typename Ret, typename Arg0, typename Arg1>
3358 struct ApplyReflect<1, Ret, Arg0, Arg1>
3359 {
applydeqp::gls::BuiltinPrecisionTests::Functions::ApplyReflect3360     static ExprP<Ret> apply(ExpandContext &, const ExprP<Arg0> &i, const ExprP<Arg1> &n)
3361     {
3362         return i - alternatives(alternatives((n * (n * i)) * constant(2.0f), n * ((n * i) * constant(2.0f))),
3363                                 (n * n) * (i * constant(2.0f)));
3364     }
3365 };
3366 
3367 template <int Size>
3368 class Reflect
3369     : public DerivedFunc<
3370           Signature<typename ContainerOf<float, Size>::Container, typename ContainerOf<float, Size>::Container,
3371                     typename ContainerOf<float, Size>::Container>>
3372 {
3373 public:
3374     typedef typename Reflect::Ret Ret;
3375     typedef typename Reflect::Arg0 Arg0;
3376     typedef typename Reflect::Arg1 Arg1;
3377     typedef typename Reflect::ArgExprs ArgExprs;
3378 
getName(void) const3379     string getName(void) const
3380     {
3381         return "reflect";
3382     }
3383 
3384 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3385     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
3386     {
3387         const ExprP<Arg0> &i = args.a;
3388         const ExprP<Arg1> &n = args.b;
3389 
3390         return ApplyReflect<Size, Ret, Arg0, Arg1>::apply(ctx, i, n);
3391     }
3392 };
3393 
3394 template <int Size>
3395 class Refract
3396     : public DerivedFunc<
3397           Signature<typename ContainerOf<float, Size>::Container, typename ContainerOf<float, Size>::Container,
3398                     typename ContainerOf<float, Size>::Container, float>>
3399 {
3400 public:
3401     typedef typename Refract::Ret Ret;
3402     typedef typename Refract::Arg0 Arg0;
3403     typedef typename Refract::Arg1 Arg1;
3404     typedef typename Refract::ArgExprs ArgExprs;
3405 
getName(void) const3406     string getName(void) const
3407     {
3408         return "refract";
3409     }
3410 
3411 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3412     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
3413     {
3414         const ExprP<Arg0> &i     = args.a;
3415         const ExprP<Arg1> &n     = args.b;
3416         const ExprP<float> &eta  = args.c;
3417         const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3418         const ExprP<float> k1 =
3419             bindExpression("k1", ctx, constant(1.0f) - eta * eta * (constant(1.0f) - dotNI * dotNI));
3420 
3421         const ExprP<float> k2 =
3422             bindExpression("k2", ctx, (((dotNI * (-dotNI)) + constant(1.0f)) * eta) * (-eta) + constant(1.0f));
3423         const ExprP<float> k = bindExpression("k", ctx, alternatives(k1, k2));
3424 
3425         return cond(k < constant(0.0f), genXType<float, Size>(constant(0.0f)), i * eta - n * (eta * dotNI + sqrt(k)));
3426     }
3427 };
3428 
3429 class PreciseFunc1 : public CFloatFunc1
3430 {
3431 public:
PreciseFunc1(const string & name,DoubleFunc1 & func)3432     PreciseFunc1(const string &name, DoubleFunc1 &func) : CFloatFunc1(name, func)
3433     {
3434     }
3435 
3436 protected:
precision(const EvalContext &,double,double) const3437     double precision(const EvalContext &, double, double) const
3438     {
3439         return 0.0;
3440     }
3441 };
3442 
3443 class Abs : public PreciseFunc1
3444 {
3445 public:
Abs(void)3446     Abs(void) : PreciseFunc1("abs", deAbs)
3447     {
3448     }
3449 };
3450 
3451 class Sign : public PreciseFunc1
3452 {
3453 public:
Sign(void)3454     Sign(void) : PreciseFunc1("sign", deSign)
3455     {
3456     }
3457 };
3458 
3459 class Floor : public PreciseFunc1
3460 {
3461 public:
Floor(void)3462     Floor(void) : PreciseFunc1("floor", deFloor)
3463     {
3464     }
3465 };
3466 
3467 class Trunc : public PreciseFunc1
3468 {
3469 public:
Trunc(void)3470     Trunc(void) : PreciseFunc1("trunc", deTrunc)
3471     {
3472     }
3473 };
3474 
3475 class Round : public FloatFunc1
3476 {
3477 public:
getName(void) const3478     string getName(void) const
3479     {
3480         return "round";
3481     }
3482 
3483 protected:
applyPoint(const EvalContext &,double x) const3484     Interval applyPoint(const EvalContext &, double x) const
3485     {
3486         double truncated   = 0.0;
3487         const double fract = deModf(x, &truncated);
3488         Interval ret;
3489 
3490         if (fabs(fract) <= 0.5)
3491             ret |= truncated;
3492         if (fabs(fract) >= 0.5)
3493             ret |= truncated + deSign(fract);
3494 
3495         return ret;
3496     }
3497 
precision(const EvalContext &,double,double) const3498     double precision(const EvalContext &, double, double) const
3499     {
3500         return 0.0;
3501     }
3502 };
3503 
3504 class RoundEven : public PreciseFunc1
3505 {
3506 public:
RoundEven(void)3507     RoundEven(void) : PreciseFunc1("roundEven", deRoundEven)
3508     {
3509     }
3510 };
3511 
3512 class Ceil : public PreciseFunc1
3513 {
3514 public:
Ceil(void)3515     Ceil(void) : PreciseFunc1("ceil", deCeil)
3516     {
3517     }
3518 };
3519 
3520 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x))
3521 
3522 class PreciseFunc2 : public CFloatFunc2
3523 {
3524 public:
PreciseFunc2(const string & name,DoubleFunc2 & func)3525     PreciseFunc2(const string &name, DoubleFunc2 &func) : CFloatFunc2(name, func)
3526     {
3527     }
3528 
3529 protected:
precision(const EvalContext &,double,double,double) const3530     double precision(const EvalContext &, double, double, double) const
3531     {
3532         return 0.0;
3533     }
3534 };
3535 
3536 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y))
3537 
3538 class Modf : public PrimitiveFunc<Signature<float, float, float>>
3539 {
3540 public:
getName(void) const3541     string getName(void) const
3542     {
3543         return "modf";
3544     }
3545 
3546 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3547     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3548     {
3549         Interval fracIV;
3550         Interval &wholeIV = const_cast<Interval &>(iargs.b);
3551         double intPart    = 0;
3552 
3553         TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3554         TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole, deModf(x, &intPart); whole = intPart);
3555 
3556         if (!iargs.a.isFinite(ctx.format.getMaxValue()))
3557         {
3558             // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3559             // See Khronos bug 13907
3560             fracIV |= TCU_NAN;
3561         }
3562 
3563         return fracIV;
3564     }
3565 
getOutParamIndex(void) const3566     int getOutParamIndex(void) const
3567     {
3568         return 1;
3569     }
3570 };
3571 
compare(const EvalContext & ctx,double x,double y)3572 int compare(const EvalContext &ctx, double x, double y)
3573 {
3574     if (ctx.format.hasSubnormal() != tcu::YES)
3575     {
3576         const int minExp           = ctx.format.getMinExp();
3577         const int fractionBits     = ctx.format.getFractionBits();
3578         const double minQuantum    = deLdExp(1.0f, minExp - fractionBits);
3579         const double minNormalized = deLdExp(1.0f, minExp);
3580         const double maxSubnormal  = minNormalized - minQuantum;
3581         const double minSubnormal  = -maxSubnormal;
3582 
3583         if (minSubnormal <= x && x <= maxSubnormal && minSubnormal <= y && y <= maxSubnormal)
3584             return 0;
3585     }
3586 
3587     if (x < y)
3588         return -1;
3589     if (y < x)
3590         return 1;
3591     return 0;
3592 }
3593 
3594 class MinMaxFunc : public FloatFunc2
3595 {
3596 public:
MinMaxFunc(const string & name,int sign)3597     MinMaxFunc(const string &name, int sign) : m_name(name), m_sign(sign)
3598     {
3599     }
3600 
getName(void) const3601     string getName(void) const
3602     {
3603         return m_name;
3604     }
3605 
3606 protected:
applyPoint(const EvalContext & ctx,double x,double y) const3607     Interval applyPoint(const EvalContext &ctx, double x, double y) const
3608     {
3609         const int cmp = compare(ctx, x, y) * m_sign;
3610 
3611         if (cmp > 0)
3612             return x;
3613         if (cmp < 0)
3614             return y;
3615 
3616         // An implementation without subnormals may not be able to distinguish
3617         // between x and y even when they're not equal in host arithmetic.
3618         return Interval(x, y);
3619     }
3620 
precision(const EvalContext &,double,double,double) const3621     double precision(const EvalContext &, double, double, double) const
3622     {
3623         return 0.0;
3624     }
3625 
3626     const string m_name;
3627     const int m_sign;
3628 };
3629 
3630 class Min : public MinMaxFunc
3631 {
3632 public:
Min(void)3633     Min(void) : MinMaxFunc("min", -1)
3634     {
3635     }
3636 };
3637 class Max : public MinMaxFunc
3638 {
3639 public:
Max(void)3640     Max(void) : MinMaxFunc("max", 1)
3641     {
3642     }
3643 };
3644 
3645 class Clamp : public FloatFunc3
3646 {
3647 public:
getName(void) const3648     string getName(void) const
3649     {
3650         return "clamp";
3651     }
3652 
3653 protected:
applyPoint(const EvalContext & ctx,double x,double minVal,double maxVal) const3654     Interval applyPoint(const EvalContext &ctx, double x, double minVal, double maxVal) const
3655     {
3656         if (minVal > maxVal)
3657             return TCU_NAN;
3658 
3659         const int cmpMin    = compare(ctx, x, minVal);
3660         const int cmpMax    = compare(ctx, x, maxVal);
3661         const int cmpMinMax = compare(ctx, minVal, maxVal);
3662 
3663         if (cmpMin < 0)
3664         {
3665             if (cmpMinMax < 0)
3666                 return minVal;
3667             else
3668                 return Interval(minVal, maxVal);
3669         }
3670         if (cmpMax > 0)
3671         {
3672             if (cmpMinMax < 0)
3673                 return maxVal;
3674             else
3675                 return Interval(minVal, maxVal);
3676         }
3677 
3678         Interval result = x;
3679         if (cmpMin == 0)
3680             result |= minVal;
3681         if (cmpMax == 0)
3682             result |= maxVal;
3683         return result;
3684     }
3685 
precision(const EvalContext &,double,double,double minVal,double maxVal) const3686     double precision(const EvalContext &, double, double, double minVal, double maxVal) const
3687     {
3688         return minVal > maxVal ? TCU_NAN : 0.0;
3689     }
3690 };
3691 
clamp(const ExprP<float> & x,const ExprP<float> & minVal,const ExprP<float> & maxVal)3692 ExprP<float> clamp(const ExprP<float> &x, const ExprP<float> &minVal, const ExprP<float> &maxVal)
3693 {
3694     return app<Clamp>(x, minVal, maxVal);
3695 }
3696 
3697 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a, x + (y - x) * a))
3698 
step(double edge,double x)3699 static double step(double edge, double x)
3700 {
3701     return x < edge ? 0.0 : 1.0;
3702 }
3703 
3704 class Step : public PreciseFunc2
3705 {
3706 public:
Step(void)3707     Step(void) : PreciseFunc2("step", step)
3708     {
3709     }
3710 };
3711 
3712 class SmoothStep : public DerivedFunc<Signature<float, float, float, float>>
3713 {
3714 public:
getName(void) const3715     string getName(void) const
3716     {
3717         return "smoothstep";
3718     }
3719 
3720 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3721     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
3722     {
3723         const ExprP<float> &edge0 = args.a;
3724         const ExprP<float> &edge1 = args.b;
3725         const ExprP<float> &x     = args.c;
3726         const ExprP<float> tExpr  = clamp((x - edge0) / (edge1 - edge0), constant(0.0f), constant(1.0f));
3727         const ExprP<float> t      = bindExpression("t", ctx, tExpr);
3728 
3729         return (t * t * (constant(3.0f) - constant(2.0f) * t));
3730     }
3731 };
3732 
3733 class FrExp : public PrimitiveFunc<Signature<float, float, int>>
3734 {
3735 public:
getName(void) const3736     string getName(void) const
3737     {
3738         return "frexp";
3739     }
3740 
3741 protected:
doApply(const EvalContext &,const IArgs & iargs) const3742     IRet doApply(const EvalContext &, const IArgs &iargs) const
3743     {
3744         IRet ret;
3745         const IArg0 &x  = iargs.a;
3746         IArg1 &exponent = const_cast<IArg1 &>(iargs.b);
3747 
3748         if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3749         {
3750             // GLSL (in contrast to IEEE) says that result of applying frexp
3751             // to infinity is undefined
3752             ret      = Interval::unbounded() | TCU_NAN;
3753             exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31) - 1);
3754         }
3755         else if (!x.empty())
3756         {
3757             int loExp           = 0;
3758             const double loFrac = deFrExp(x.lo(), &loExp);
3759             int hiExp           = 0;
3760             const double hiFrac = deFrExp(x.hi(), &hiExp);
3761 
3762             if (deSign(loFrac) != deSign(hiFrac))
3763             {
3764                 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3765                 ret      = Interval();
3766                 if (deSign(loFrac) < 0)
3767                     ret |= Interval(-1.0 + DBL_EPSILON * 0.5, 0.0);
3768                 if (deSign(hiFrac) > 0)
3769                     ret |= Interval(0.0, 1.0 - DBL_EPSILON * 0.5);
3770             }
3771             else
3772             {
3773                 exponent = Interval(loExp, hiExp);
3774                 if (loExp == hiExp)
3775                     ret = Interval(loFrac, hiFrac);
3776                 else
3777                     ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON * 0.5);
3778             }
3779         }
3780 
3781         return ret;
3782     }
3783 
getOutParamIndex(void) const3784     int getOutParamIndex(void) const
3785     {
3786         return 1;
3787     }
3788 };
3789 
3790 class LdExp : public PrimitiveFunc<Signature<float, float, int>>
3791 {
3792 public:
getName(void) const3793     string getName(void) const
3794     {
3795         return "ldexp";
3796     }
3797 
3798 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3799     Interval doApply(const EvalContext &ctx, const IArgs &iargs) const
3800     {
3801         Interval ret = call<Exp2>(ctx, iargs.b);
3802         // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3803         // the result is undefined.
3804 
3805         if (ret.contains(TCU_INFINITY) || ret.contains(-TCU_INFINITY))
3806             ret |= TCU_NAN;
3807 
3808         return call<Mul>(ctx, iargs.a, ret);
3809     }
3810 };
3811 
3812 template <int Rows, int Columns>
3813 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>, Matrix<float, Columns, Rows>>>
3814 {
3815 public:
3816     typedef typename Transpose::IRet IRet;
3817     typedef typename Transpose::IArgs IArgs;
3818 
getName(void) const3819     string getName(void) const
3820     {
3821         return "transpose";
3822     }
3823 
3824 protected:
doApply(const EvalContext &,const IArgs & iargs) const3825     IRet doApply(const EvalContext &, const IArgs &iargs) const
3826     {
3827         IRet ret;
3828 
3829         for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3830         {
3831             for (int colNdx = 0; colNdx < Columns; ++colNdx)
3832                 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3833         }
3834 
3835         return ret;
3836     }
3837 };
3838 
3839 template <typename Ret, typename Arg0, typename Arg1>
3840 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1>>
3841 {
3842 public:
getName(void) const3843     string getName(void) const
3844     {
3845         return "mul";
3846     }
3847 
3848 protected:
doPrint(ostream & os,const BaseArgExprs & args) const3849     void doPrint(ostream &os, const BaseArgExprs &args) const
3850     {
3851         os << "(" << *args[0] << " * " << *args[1] << ")";
3852     }
3853 };
3854 
3855 template <int LeftRows, int Middle, int RightCols>
3856 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>, Matrix<float, LeftRows, Middle>,
3857                               Matrix<float, Middle, RightCols>>
3858 {
3859 protected:
3860     typedef typename MatMul::IRet IRet;
3861     typedef typename MatMul::IArgs IArgs;
3862     typedef typename MatMul::IArg0 IArg0;
3863     typedef typename MatMul::IArg1 IArg1;
3864 
doApply(const EvalContext & ctx,const IArgs & iargs) const3865     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3866     {
3867         const IArg0 &left  = iargs.a;
3868         const IArg1 &right = iargs.b;
3869         IRet ret;
3870 
3871         for (int row = 0; row < LeftRows; ++row)
3872         {
3873             for (int col = 0; col < RightCols; ++col)
3874             {
3875                 Interval element(0.0);
3876 
3877                 for (int ndx = 0; ndx < Middle; ++ndx)
3878                     element = call<Add>(ctx, element, call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3879 
3880                 ret[col][row] = element;
3881             }
3882         }
3883 
3884         return ret;
3885     }
3886 };
3887 
3888 template <int Rows, int Cols>
3889 class VecMatMul : public MulFunc<Vector<float, Cols>, Vector<float, Rows>, Matrix<float, Rows, Cols>>
3890 {
3891 public:
3892     typedef typename VecMatMul::IRet IRet;
3893     typedef typename VecMatMul::IArgs IArgs;
3894     typedef typename VecMatMul::IArg0 IArg0;
3895     typedef typename VecMatMul::IArg1 IArg1;
3896 
3897 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3898     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3899     {
3900         const IArg0 &left  = iargs.a;
3901         const IArg1 &right = iargs.b;
3902         IRet ret;
3903 
3904         for (int col = 0; col < Cols; ++col)
3905         {
3906             Interval element(0.0);
3907 
3908             for (int row = 0; row < Rows; ++row)
3909                 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3910 
3911             ret[col] = element;
3912         }
3913 
3914         return ret;
3915     }
3916 };
3917 
3918 template <int Rows, int Cols>
3919 class MatVecMul : public MulFunc<Vector<float, Rows>, Matrix<float, Rows, Cols>, Vector<float, Cols>>
3920 {
3921 public:
3922     typedef typename MatVecMul::IRet IRet;
3923     typedef typename MatVecMul::IArgs IArgs;
3924     typedef typename MatVecMul::IArg0 IArg0;
3925     typedef typename MatVecMul::IArg1 IArg1;
3926 
3927 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3928     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3929     {
3930         const IArg0 &left  = iargs.a;
3931         const IArg1 &right = iargs.b;
3932 
3933         return call<VecMatMul<Cols, Rows>>(ctx, right, call<Transpose<Rows, Cols>>(ctx, left));
3934     }
3935 };
3936 
3937 template <int Rows, int Cols>
3938 class OuterProduct
3939     : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>, Vector<float, Rows>, Vector<float, Cols>>>
3940 {
3941 public:
3942     typedef typename OuterProduct::IRet IRet;
3943     typedef typename OuterProduct::IArgs IArgs;
3944 
getName(void) const3945     string getName(void) const
3946     {
3947         return "outerProduct";
3948     }
3949 
3950 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3951     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
3952     {
3953         IRet ret;
3954 
3955         for (int row = 0; row < Rows; ++row)
3956         {
3957             for (int col = 0; col < Cols; ++col)
3958                 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3959         }
3960 
3961         return ret;
3962     }
3963 };
3964 
3965 template <int Rows, int Cols>
outerProduct(const ExprP<Vector<float,Rows>> & left,const ExprP<Vector<float,Cols>> & right)3966 ExprP<Matrix<float, Rows, Cols>> outerProduct(const ExprP<Vector<float, Rows>> &left,
3967                                               const ExprP<Vector<float, Cols>> &right)
3968 {
3969     return app<OuterProduct<Rows, Cols>>(left, right);
3970 }
3971 
3972 template <int Size>
3973 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size>>>
3974 {
3975 public:
getName(void) const3976     string getName(void) const
3977     {
3978         return "determinant";
3979     }
3980 };
3981 
3982 template <int Size>
3983 class Determinant;
3984 
3985 template <int Size>
determinant(ExprP<Matrix<float,Size,Size>> mat)3986 ExprP<float> determinant(ExprP<Matrix<float, Size, Size>> mat)
3987 {
3988     return app<Determinant<Size>>(mat);
3989 }
3990 
3991 template <>
3992 class Determinant<2> : public DeterminantBase<2>
3993 {
3994 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3995     ExprP<Ret> doExpand(ExpandContext &, const ArgExprs &args) const
3996     {
3997         ExprP<Mat2> mat = args.a;
3998 
3999         return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
4000     }
4001 };
4002 
4003 template <>
4004 class Determinant<3> : public DeterminantBase<3>
4005 {
4006 protected:
doExpand(ExpandContext &,const ArgExprs & args) const4007     ExprP<Ret> doExpand(ExpandContext &, const ArgExprs &args) const
4008     {
4009         ExprP<Mat3> mat = args.a;
4010 
4011         return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
4012                 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
4013                 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
4014     }
4015 };
4016 
4017 template <>
4018 class Determinant<4> : public DeterminantBase<4>
4019 {
4020 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const4021     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
4022     {
4023         ExprP<Mat4> mat = args.a;
4024         ExprP<Mat3> minors[4];
4025 
4026         for (int ndx = 0; ndx < 4; ++ndx)
4027         {
4028             ExprP<Vec4> minorColumns[3];
4029             ExprP<Vec3> columns[3];
4030 
4031             for (int col = 0; col < 3; ++col)
4032                 minorColumns[col] = mat[col < ndx ? col : col + 1];
4033 
4034             for (int col = 0; col < 3; ++col)
4035                 columns[col] = vec3(minorColumns[0][col + 1], minorColumns[1][col + 1], minorColumns[2][col + 1]);
4036 
4037             minors[ndx] = bindExpression("minor", ctx, mat3(columns[0], columns[1], columns[2]));
4038         }
4039 
4040         return (mat[0][0] * determinant(minors[0]) - mat[1][0] * determinant(minors[1]) +
4041                 mat[2][0] * determinant(minors[2]) - mat[3][0] * determinant(minors[3]));
4042     }
4043 };
4044 
4045 template <int Size>
4046 class Inverse;
4047 
4048 template <int Size>
inverse(ExprP<Matrix<float,Size,Size>> mat)4049 ExprP<Matrix<float, Size, Size>> inverse(ExprP<Matrix<float, Size, Size>> mat)
4050 {
4051     return app<Inverse<Size>>(mat);
4052 }
4053 
4054 template <>
4055 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2>>
4056 {
4057 public:
getName(void) const4058     string getName(void) const
4059     {
4060         return "inverse";
4061     }
4062 
4063 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const4064     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
4065     {
4066         ExprP<Mat2> mat  = args.a;
4067         ExprP<float> det = bindExpression("det", ctx, determinant(mat));
4068 
4069         return mat2(vec2(mat[1][1] / det, -mat[0][1] / det), vec2(-mat[1][0] / det, mat[0][0] / det));
4070     }
4071 };
4072 
4073 template <>
4074 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3>>
4075 {
4076 public:
getName(void) const4077     string getName(void) const
4078     {
4079         return "inverse";
4080     }
4081 
4082 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const4083     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
4084     {
4085         ExprP<Mat3> mat = args.a;
4086         ExprP<Mat2> invA =
4087             bindExpression("invA", ctx, inverse(mat2(vec2(mat[0][0], mat[0][1]), vec2(mat[1][0], mat[1][1]))));
4088 
4089         ExprP<Vec2> matB  = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
4090         ExprP<Vec2> matC  = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
4091         ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
4092 
4093         ExprP<float> schur = bindExpression("schur", ctx, constant(1.0f) / (matD - dot(matC * invA, matB)));
4094 
4095         ExprP<Vec2> t1     = invA * matB;
4096         ExprP<Vec2> t2     = t1 * schur;
4097         ExprP<Mat2> t3     = outerProduct(t2, matC);
4098         ExprP<Mat2> t4     = t3 * invA;
4099         ExprP<Mat2> t5     = invA + t4;
4100         ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
4101         ExprP<Vec2> blockB = bindExpression("blockB", ctx, (invA * matB) * -schur);
4102         ExprP<Vec2> blockC = bindExpression("blockC", ctx, (matC * invA) * -schur);
4103 
4104         return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]), vec3(blockA[1][0], blockA[1][1], blockC[1]),
4105                     vec3(blockB[0], blockB[1], schur));
4106     }
4107 };
4108 
4109 template <>
4110 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4>>
4111 {
4112 public:
getName(void) const4113     string getName(void) const
4114     {
4115         return "inverse";
4116     }
4117 
4118 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const4119     ExprP<Ret> doExpand(ExpandContext &ctx, const ArgExprs &args) const
4120     {
4121         ExprP<Mat4> mat = args.a;
4122         ExprP<Mat2> invA =
4123             bindExpression("invA", ctx, inverse(mat2(vec2(mat[0][0], mat[0][1]), vec2(mat[1][0], mat[1][1]))));
4124         ExprP<Mat2> matB   = bindExpression("matB", ctx, mat2(vec2(mat[2][0], mat[2][1]), vec2(mat[3][0], mat[3][1])));
4125         ExprP<Mat2> matC   = bindExpression("matC", ctx, mat2(vec2(mat[0][2], mat[0][3]), vec2(mat[1][2], mat[1][3])));
4126         ExprP<Mat2> matD   = bindExpression("matD", ctx, mat2(vec2(mat[2][2], mat[2][3]), vec2(mat[3][2], mat[3][3])));
4127         ExprP<Mat2> schur  = bindExpression("schur", ctx, inverse(matD + -(matC * invA * matB)));
4128         ExprP<Mat2> blockA = bindExpression("blockA", ctx, invA + (invA * matB * schur * matC * invA));
4129         ExprP<Mat2> blockB = bindExpression("blockB", ctx, (-invA) * matB * schur);
4130         ExprP<Mat2> blockC = bindExpression("blockC", ctx, (-schur) * matC * invA);
4131 
4132         return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
4133                     vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
4134                     vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
4135                     vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
4136     }
4137 };
4138 
4139 class Fma : public DerivedFunc<Signature<float, float, float, float>>
4140 {
4141 public:
getName(void) const4142     string getName(void) const
4143     {
4144         return "fma";
4145     }
4146 
getRequiredExtension(const RenderContext & context) const4147     string getRequiredExtension(const RenderContext &context) const
4148     {
4149         return (glu::contextSupports(context.getType(), glu::ApiType::core(4, 5))) ? "" : "GL_EXT_gpu_shader5";
4150     }
4151 
4152 protected:
doExpand(ExpandContext &,const ArgExprs & x) const4153     ExprP<float> doExpand(ExpandContext &, const ArgExprs &x) const
4154     {
4155         return x.a * x.b + x.c;
4156     }
4157 };
4158 
4159 } // namespace Functions
4160 
4161 using namespace Functions;
4162 
4163 template <typename T>
operator [](int i) const4164 ExprP<typename T::Element> ContainerExprPBase<T>::operator[](int i) const
4165 {
4166     return Functions::getComponent(exprP<T>(*this), i);
4167 }
4168 
operator +(const ExprP<float> & arg0,const ExprP<float> & arg1)4169 ExprP<float> operator+(const ExprP<float> &arg0, const ExprP<float> &arg1)
4170 {
4171     return app<Add>(arg0, arg1);
4172 }
4173 
operator -(const ExprP<float> & arg0,const ExprP<float> & arg1)4174 ExprP<float> operator-(const ExprP<float> &arg0, const ExprP<float> &arg1)
4175 {
4176     return app<Sub>(arg0, arg1);
4177 }
4178 
operator -(const ExprP<float> & arg0)4179 ExprP<float> operator-(const ExprP<float> &arg0)
4180 {
4181     return app<Negate>(arg0);
4182 }
4183 
operator *(const ExprP<float> & arg0,const ExprP<float> & arg1)4184 ExprP<float> operator*(const ExprP<float> &arg0, const ExprP<float> &arg1)
4185 {
4186     return app<Mul>(arg0, arg1);
4187 }
4188 
operator /(const ExprP<float> & arg0,const ExprP<float> & arg1)4189 ExprP<float> operator/(const ExprP<float> &arg0, const ExprP<float> &arg1)
4190 {
4191     return app<Div>(arg0, arg1);
4192 }
4193 
4194 template <typename Sig_, int Size>
4195 class GenFunc : public PrimitiveFunc<Signature<typename ContainerOf<typename Sig_::Ret, Size>::Container,
4196                                                typename ContainerOf<typename Sig_::Arg0, Size>::Container,
4197                                                typename ContainerOf<typename Sig_::Arg1, Size>::Container,
4198                                                typename ContainerOf<typename Sig_::Arg2, Size>::Container,
4199                                                typename ContainerOf<typename Sig_::Arg3, Size>::Container>>
4200 {
4201 public:
4202     typedef typename GenFunc::IArgs IArgs;
4203     typedef typename GenFunc::IRet IRet;
4204 
GenFunc(const Func<Sig_> & scalarFunc)4205     GenFunc(const Func<Sig_> &scalarFunc) : m_func(scalarFunc)
4206     {
4207     }
4208 
getName(void) const4209     string getName(void) const
4210     {
4211         return m_func.getName();
4212     }
4213 
getOutParamIndex(void) const4214     int getOutParamIndex(void) const
4215     {
4216         return m_func.getOutParamIndex();
4217     }
4218 
getRequiredExtension(const RenderContext & context) const4219     string getRequiredExtension(const RenderContext &context) const
4220     {
4221         return m_func.getRequiredExtension(context);
4222     }
4223 
4224 protected:
doPrint(ostream & os,const BaseArgExprs & args) const4225     void doPrint(ostream &os, const BaseArgExprs &args) const
4226     {
4227         m_func.print(os, args);
4228     }
4229 
doApply(const EvalContext & ctx,const IArgs & iargs) const4230     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
4231     {
4232         IRet ret;
4233 
4234         for (int ndx = 0; ndx < Size; ++ndx)
4235         {
4236             ret[ndx] = m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
4237         }
4238 
4239         return ret;
4240     }
4241 
doGetUsedFuncs(FuncSet & dst) const4242     void doGetUsedFuncs(FuncSet &dst) const
4243     {
4244         m_func.getUsedFuncs(dst);
4245     }
4246 
4247     const Func<Sig_> &m_func;
4248 };
4249 
4250 template <typename F, int Size>
4251 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
4252 {
4253 public:
VectorizedFunc(void)4254     VectorizedFunc(void) : GenFunc<typename F::Sig, Size>(instance<F>())
4255     {
4256     }
4257 };
4258 
4259 template <typename Sig_, int Size>
4260 class FixedGenFunc
4261     : public PrimitiveFunc<Signature<typename ContainerOf<typename Sig_::Ret, Size>::Container,
4262                                      typename ContainerOf<typename Sig_::Arg0, Size>::Container, typename Sig_::Arg1,
4263                                      typename ContainerOf<typename Sig_::Arg2, Size>::Container,
4264                                      typename ContainerOf<typename Sig_::Arg3, Size>::Container>>
4265 {
4266 public:
4267     typedef typename FixedGenFunc::IArgs IArgs;
4268     typedef typename FixedGenFunc::IRet IRet;
4269 
getName(void) const4270     string getName(void) const
4271     {
4272         return this->doGetScalarFunc().getName();
4273     }
4274 
4275 protected:
doPrint(ostream & os,const BaseArgExprs & args) const4276     void doPrint(ostream &os, const BaseArgExprs &args) const
4277     {
4278         this->doGetScalarFunc().print(os, args);
4279     }
4280 
doApply(const EvalContext & ctx,const IArgs & iargs) const4281     IRet doApply(const EvalContext &ctx, const IArgs &iargs) const
4282     {
4283         IRet ret;
4284         const Func<Sig_> &func = this->doGetScalarFunc();
4285 
4286         for (int ndx = 0; ndx < Size; ++ndx)
4287             ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
4288 
4289         return ret;
4290     }
4291 
4292     virtual const Func<Sig_> &doGetScalarFunc(void) const = 0;
4293 };
4294 
4295 template <typename F, int Size>
4296 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
4297 {
4298 protected:
doGetScalarFunc(void) const4299     const Func<typename F::Sig> &doGetScalarFunc(void) const
4300     {
4301         return instance<F>();
4302     }
4303 };
4304 
4305 template <typename Sig>
4306 struct GenFuncs
4307 {
GenFuncsdeqp::gls::BuiltinPrecisionTests::GenFuncs4308     GenFuncs(const Func<Sig> &func_, const GenFunc<Sig, 2> &func2_, const GenFunc<Sig, 3> &func3_,
4309              const GenFunc<Sig, 4> &func4_)
4310         : func(func_)
4311         , func2(func2_)
4312         , func3(func3_)
4313         , func4(func4_)
4314     {
4315     }
4316 
4317     const Func<Sig> &func;
4318     const GenFunc<Sig, 2> &func2;
4319     const GenFunc<Sig, 3> &func3;
4320     const GenFunc<Sig, 4> &func4;
4321 };
4322 
4323 template <typename F>
makeVectorizedFuncs(void)4324 GenFuncs<typename F::Sig> makeVectorizedFuncs(void)
4325 {
4326     return GenFuncs<typename F::Sig>(instance<F>(), instance<VectorizedFunc<F, 2>>(), instance<VectorizedFunc<F, 3>>(),
4327                                      instance<VectorizedFunc<F, 4>>());
4328 }
4329 
4330 template <int Size>
operator *(const ExprP<Vector<float,Size>> & arg0,const ExprP<Vector<float,Size>> & arg1)4331 ExprP<Vector<float, Size>> operator*(const ExprP<Vector<float, Size>> &arg0, const ExprP<Vector<float, Size>> &arg1)
4332 {
4333     return app<VectorizedFunc<Mul, Size>>(arg0, arg1);
4334 }
4335 
4336 template <int Size>
operator *(const ExprP<Vector<float,Size>> & arg0,const ExprP<float> & arg1)4337 ExprP<Vector<float, Size>> operator*(const ExprP<Vector<float, Size>> &arg0, const ExprP<float> &arg1)
4338 {
4339     return app<FixedVecFunc<Mul, Size>>(arg0, arg1);
4340 }
4341 
4342 template <int Size>
operator /(const ExprP<Vector<float,Size>> & arg0,const ExprP<float> & arg1)4343 ExprP<Vector<float, Size>> operator/(const ExprP<Vector<float, Size>> &arg0, const ExprP<float> &arg1)
4344 {
4345     return app<FixedVecFunc<Div, Size>>(arg0, arg1);
4346 }
4347 
4348 template <int Size>
operator -(const ExprP<Vector<float,Size>> & arg0)4349 ExprP<Vector<float, Size>> operator-(const ExprP<Vector<float, Size>> &arg0)
4350 {
4351     return app<VectorizedFunc<Negate, Size>>(arg0);
4352 }
4353 
4354 template <int Size>
operator -(const ExprP<Vector<float,Size>> & arg0,const ExprP<Vector<float,Size>> & arg1)4355 ExprP<Vector<float, Size>> operator-(const ExprP<Vector<float, Size>> &arg0, const ExprP<Vector<float, Size>> &arg1)
4356 {
4357     return app<VectorizedFunc<Sub, Size>>(arg0, arg1);
4358 }
4359 
4360 template <int LeftRows, int Middle, int RightCols>
operator *(const ExprP<Matrix<float,LeftRows,Middle>> & left,const ExprP<Matrix<float,Middle,RightCols>> & right)4361 ExprP<Matrix<float, LeftRows, RightCols>> operator*(const ExprP<Matrix<float, LeftRows, Middle>> &left,
4362                                                     const ExprP<Matrix<float, Middle, RightCols>> &right)
4363 {
4364     return app<MatMul<LeftRows, Middle, RightCols>>(left, right);
4365 }
4366 
4367 template <int Rows, int Cols>
operator *(const ExprP<Vector<float,Cols>> & left,const ExprP<Matrix<float,Rows,Cols>> & right)4368 ExprP<Vector<float, Rows>> operator*(const ExprP<Vector<float, Cols>> &left,
4369                                      const ExprP<Matrix<float, Rows, Cols>> &right)
4370 {
4371     return app<VecMatMul<Rows, Cols>>(left, right);
4372 }
4373 
4374 template <int Rows, int Cols>
operator *(const ExprP<Matrix<float,Rows,Cols>> & left,const ExprP<Vector<float,Rows>> & right)4375 ExprP<Vector<float, Cols>> operator*(const ExprP<Matrix<float, Rows, Cols>> &left,
4376                                      const ExprP<Vector<float, Rows>> &right)
4377 {
4378     return app<MatVecMul<Rows, Cols>>(left, right);
4379 }
4380 
4381 template <int Rows, int Cols>
operator *(const ExprP<Matrix<float,Rows,Cols>> & left,const ExprP<float> & right)4382 ExprP<Matrix<float, Rows, Cols>> operator*(const ExprP<Matrix<float, Rows, Cols>> &left, const ExprP<float> &right)
4383 {
4384     return app<ScalarMatFunc<Mul, Rows, Cols>>(left, right);
4385 }
4386 
4387 template <int Rows, int Cols>
operator +(const ExprP<Matrix<float,Rows,Cols>> & left,const ExprP<Matrix<float,Rows,Cols>> & right)4388 ExprP<Matrix<float, Rows, Cols>> operator+(const ExprP<Matrix<float, Rows, Cols>> &left,
4389                                            const ExprP<Matrix<float, Rows, Cols>> &right)
4390 {
4391     return app<CompMatFunc<Add, Rows, Cols>>(left, right);
4392 }
4393 
4394 template <int Rows, int Cols>
operator -(const ExprP<Matrix<float,Rows,Cols>> & mat)4395 ExprP<Matrix<float, Rows, Cols>> operator-(const ExprP<Matrix<float, Rows, Cols>> &mat)
4396 {
4397     return app<MatNeg<Rows, Cols>>(mat);
4398 }
4399 
4400 template <typename T>
4401 class Sampling
4402 {
4403 public:
genFixeds(const FloatFormat &,vector<T> &) const4404     virtual void genFixeds(const FloatFormat &, vector<T> &) const
4405     {
4406     }
genRandom(const FloatFormat &,Precision,Random &) const4407     virtual T genRandom(const FloatFormat &, Precision, Random &) const
4408     {
4409         return T();
4410     }
getWeight(void) const4411     virtual double getWeight(void) const
4412     {
4413         return 0.0;
4414     }
4415 };
4416 
4417 template <>
4418 class DefaultSampling<Void> : public Sampling<Void>
4419 {
4420 public:
genFixeds(const FloatFormat &,vector<Void> & dst) const4421     void genFixeds(const FloatFormat &, vector<Void> &dst) const
4422     {
4423         dst.push_back(Void());
4424     }
4425 };
4426 
4427 template <>
4428 class DefaultSampling<bool> : public Sampling<bool>
4429 {
4430 public:
genFixeds(const FloatFormat &,vector<bool> & dst) const4431     void genFixeds(const FloatFormat &, vector<bool> &dst) const
4432     {
4433         dst.push_back(true);
4434         dst.push_back(false);
4435     }
4436 };
4437 
4438 template <>
4439 class DefaultSampling<int> : public Sampling<int>
4440 {
4441 public:
genRandom(const FloatFormat &,Precision prec,Random & rnd) const4442     int genRandom(const FloatFormat &, Precision prec, Random &rnd) const
4443     {
4444         const int exp  = rnd.getInt(0, getNumBits(prec) - 2);
4445         const int sign = rnd.getBool() ? -1 : 1;
4446 
4447         return sign * rnd.getInt(0, (int32_t)1 << exp);
4448     }
4449 
genFixeds(const FloatFormat &,vector<int> & dst) const4450     void genFixeds(const FloatFormat &, vector<int> &dst) const
4451     {
4452         dst.push_back(0);
4453         dst.push_back(-1);
4454         dst.push_back(1);
4455     }
getWeight(void) const4456     double getWeight(void) const
4457     {
4458         return 1.0;
4459     }
4460 
4461 private:
getNumBits(Precision prec)4462     static inline int getNumBits(Precision prec)
4463     {
4464         switch (prec)
4465         {
4466         case glu::PRECISION_LOWP:
4467             return 8;
4468         case glu::PRECISION_MEDIUMP:
4469             return 16;
4470         case glu::PRECISION_HIGHP:
4471             return 32;
4472         default:
4473             DE_ASSERT(false);
4474             return 0;
4475         }
4476     }
4477 };
4478 
4479 template <>
4480 class DefaultSampling<float> : public Sampling<float>
4481 {
4482 public:
4483     float genRandom(const FloatFormat &format, Precision prec, Random &rnd) const;
4484     void genFixeds(const FloatFormat &format, vector<float> &dst) const;
getWeight(void) const4485     double getWeight(void) const
4486     {
4487         return 1.0;
4488     }
4489 };
4490 
4491 //! Generate a random float from a reasonable general-purpose distribution.
genRandom(const FloatFormat & format,Precision,Random & rnd) const4492 float DefaultSampling<float>::genRandom(const FloatFormat &format, Precision, Random &rnd) const
4493 {
4494     const int minExp         = format.getMinExp();
4495     const int maxExp         = format.getMaxExp();
4496     const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4497 
4498     // Choose exponent so that the cumulative distribution is cubic.
4499     // This makes the probability distribution quadratic, with the peak centered on zero.
4500     const double minRoot   = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4501     const double maxRoot   = deCbrt(maxExp + 0.5);
4502     const int fractionBits = format.getFractionBits();
4503     const int exp          = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot), 3.0)));
4504     float base             = 0.0f; // integral power of two
4505     float quantum          = 0.0f; // smallest representable difference in the binade
4506     float significand      = 0.0f; // Significand.
4507 
4508     DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4509 
4510     // Generate some occasional special numbers
4511     switch (rnd.getInt(0, 64))
4512     {
4513     case 0:
4514         return 0;
4515     case 1:
4516         return TCU_INFINITY;
4517     case 2:
4518         return -TCU_INFINITY;
4519     case 3:
4520         return TCU_NAN;
4521     default:
4522         break;
4523     }
4524 
4525     if (exp >= minExp)
4526     {
4527         // Normal number
4528         base    = deFloatLdExp(1.0f, exp);
4529         quantum = deFloatLdExp(1.0f, exp - fractionBits);
4530     }
4531     else
4532     {
4533         // Subnormal
4534         base    = 0.0f;
4535         quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4536     }
4537 
4538     switch (rnd.getInt(0, 16))
4539     {
4540     case 0: // The highest number in this binade, significand is all bits one.
4541         significand = base - quantum;
4542         break;
4543     case 1: // Significand is one.
4544         significand = quantum;
4545         break;
4546     case 2: // Significand is zero.
4547         significand = 0.0;
4548         break;
4549     default: // Random (evenly distributed) significand.
4550     {
4551         uint64_t intFraction = rnd.getUint64() & ((1ull << fractionBits) - 1);
4552         significand          = float(intFraction) * quantum;
4553     }
4554     }
4555 
4556     // Produce positive numbers more often than negative.
4557     return (rnd.getInt(0, 3) == 0 ? -1.0f : 1.0f) * (base + significand);
4558 }
4559 
4560 //! Generate a standard set of floats that should always be tested.
genFixeds(const FloatFormat & format,vector<float> & dst) const4561 void DefaultSampling<float>::genFixeds(const FloatFormat &format, vector<float> &dst) const
4562 {
4563     const int minExp          = format.getMinExp();
4564     const int maxExp          = format.getMaxExp();
4565     const int fractionBits    = format.getFractionBits();
4566     const float minQuantum    = deFloatLdExp(1.0f, minExp - fractionBits);
4567     const float minNormalized = deFloatLdExp(1.0f, minExp);
4568     const float maxQuantum    = deFloatLdExp(1.0f, maxExp - fractionBits);
4569 
4570     // NaN
4571     dst.push_back(TCU_NAN);
4572     // Zero
4573     dst.push_back(0.0f);
4574 
4575     for (int sign = -1; sign <= 1; sign += 2)
4576     {
4577         // Smallest subnormal
4578         dst.push_back((float)sign * minQuantum);
4579 
4580         // Largest subnormal
4581         dst.push_back((float)sign * (minNormalized - minQuantum));
4582 
4583         // Smallest normalized
4584         dst.push_back((float)sign * minNormalized);
4585 
4586         // Next smallest normalized
4587         dst.push_back((float)sign * (minNormalized + minQuantum));
4588 
4589         dst.push_back((float)sign * 0.5f);
4590         dst.push_back((float)sign * 1.0f);
4591         dst.push_back((float)sign * 2.0f);
4592 
4593         // Largest number
4594         dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) + (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4595 
4596         dst.push_back((float)sign * TCU_INFINITY);
4597     }
4598 }
4599 
4600 template <typename T, int Size>
4601 class DefaultSampling<Vector<T, Size>> : public Sampling<Vector<T, Size>>
4602 {
4603 public:
4604     typedef Vector<T, Size> Value;
4605 
genRandom(const FloatFormat & fmt,Precision prec,Random & rnd) const4606     Value genRandom(const FloatFormat &fmt, Precision prec, Random &rnd) const
4607     {
4608         Value ret;
4609 
4610         for (int ndx = 0; ndx < Size; ++ndx)
4611             ret[ndx] = instance<DefaultSampling<T>>().genRandom(fmt, prec, rnd);
4612 
4613         return ret;
4614     }
4615 
genFixeds(const FloatFormat & fmt,vector<Value> & dst) const4616     void genFixeds(const FloatFormat &fmt, vector<Value> &dst) const
4617     {
4618         vector<T> scalars;
4619 
4620         instance<DefaultSampling<T>>().genFixeds(fmt, scalars);
4621 
4622         for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4623             dst.push_back(Value(scalars[scalarNdx]));
4624     }
4625 
getWeight(void) const4626     double getWeight(void) const
4627     {
4628         return dePow(instance<DefaultSampling<T>>().getWeight(), Size);
4629     }
4630 };
4631 
4632 template <typename T, int Rows, int Columns>
4633 class DefaultSampling<Matrix<T, Rows, Columns>> : public Sampling<Matrix<T, Rows, Columns>>
4634 {
4635 public:
4636     typedef Matrix<T, Rows, Columns> Value;
4637 
genRandom(const FloatFormat & fmt,Precision prec,Random & rnd) const4638     Value genRandom(const FloatFormat &fmt, Precision prec, Random &rnd) const
4639     {
4640         Value ret;
4641 
4642         for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4643             for (int colNdx = 0; colNdx < Columns; ++colNdx)
4644                 ret(rowNdx, colNdx) = instance<DefaultSampling<T>>().genRandom(fmt, prec, rnd);
4645 
4646         return ret;
4647     }
4648 
genFixeds(const FloatFormat & fmt,vector<Value> & dst) const4649     void genFixeds(const FloatFormat &fmt, vector<Value> &dst) const
4650     {
4651         vector<T> scalars;
4652 
4653         instance<DefaultSampling<T>>().genFixeds(fmt, scalars);
4654 
4655         for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4656             dst.push_back(Value(scalars[scalarNdx]));
4657 
4658         if (Columns == Rows)
4659         {
4660             Value mat(0.0);
4661             T x       = T(1.0f);
4662             mat[0][0] = x;
4663             for (int ndx = 0; ndx < Columns; ++ndx)
4664             {
4665                 mat[Columns - 1 - ndx][ndx] = x;
4666                 x *= T(2.0f);
4667             }
4668             dst.push_back(mat);
4669         }
4670     }
4671 
getWeight(void) const4672     double getWeight(void) const
4673     {
4674         return dePow(instance<DefaultSampling<T>>().getWeight(), Rows * Columns);
4675     }
4676 };
4677 
4678 struct Context
4679 {
Contextdeqp::gls::BuiltinPrecisionTests::Context4680     Context(const string &name_, TestContext &testContext_, RenderContext &renderContext_,
4681             const FloatFormat &floatFormat_, const FloatFormat &highpFormat_, Precision precision_,
4682             ShaderType shaderType_, size_t numRandoms_)
4683         : name(name_)
4684         , testContext(testContext_)
4685         , renderContext(renderContext_)
4686         , floatFormat(floatFormat_)
4687         , highpFormat(highpFormat_)
4688         , precision(precision_)
4689         , shaderType(shaderType_)
4690         , numRandoms(numRandoms_)
4691     {
4692     }
4693 
4694     string name;
4695     TestContext &testContext;
4696     RenderContext &renderContext;
4697     FloatFormat floatFormat;
4698     FloatFormat highpFormat;
4699     Precision precision;
4700     ShaderType shaderType;
4701     size_t numRandoms;
4702 };
4703 
4704 template <typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4705 struct InTypes
4706 {
4707     typedef In0_ In0;
4708     typedef In1_ In1;
4709     typedef In2_ In2;
4710     typedef In3_ In3;
4711 };
4712 
4713 template <typename In>
numInputs(void)4714 int numInputs(void)
4715 {
4716     return (!isTypeValid<typename In::In0>() ? 0 :
4717             !isTypeValid<typename In::In1>() ? 1 :
4718             !isTypeValid<typename In::In2>() ? 2 :
4719             !isTypeValid<typename In::In3>() ? 3 :
4720                                                4);
4721 }
4722 
4723 template <typename Out0_, typename Out1_ = Void>
4724 struct OutTypes
4725 {
4726     typedef Out0_ Out0;
4727     typedef Out1_ Out1;
4728 };
4729 
4730 template <typename Out>
numOutputs(void)4731 int numOutputs(void)
4732 {
4733     return (!isTypeValid<typename Out::Out0>() ? 0 : !isTypeValid<typename Out::Out1>() ? 1 : 2);
4734 }
4735 
4736 template <typename In>
4737 struct Inputs
4738 {
4739     vector<typename In::In0> in0;
4740     vector<typename In::In1> in1;
4741     vector<typename In::In2> in2;
4742     vector<typename In::In3> in3;
4743 };
4744 
4745 template <typename Out>
4746 struct Outputs
4747 {
Outputsdeqp::gls::BuiltinPrecisionTests::Outputs4748     Outputs(size_t size) : out0(size), out1(size)
4749     {
4750     }
4751 
4752     vector<typename Out::Out0> out0;
4753     vector<typename Out::Out1> out1;
4754 };
4755 
4756 template <typename In, typename Out>
4757 struct Variables
4758 {
4759     VariableP<typename In::In0> in0;
4760     VariableP<typename In::In1> in1;
4761     VariableP<typename In::In2> in2;
4762     VariableP<typename In::In3> in3;
4763     VariableP<typename Out::Out0> out0;
4764     VariableP<typename Out::Out1> out1;
4765 };
4766 
4767 template <typename In>
4768 struct Samplings
4769 {
Samplingsdeqp::gls::BuiltinPrecisionTests::Samplings4770     Samplings(const Sampling<typename In::In0> &in0_, const Sampling<typename In::In1> &in1_,
4771               const Sampling<typename In::In2> &in2_, const Sampling<typename In::In3> &in3_)
4772         : in0(in0_)
4773         , in1(in1_)
4774         , in2(in2_)
4775         , in3(in3_)
4776     {
4777     }
4778 
4779     const Sampling<typename In::In0> &in0;
4780     const Sampling<typename In::In1> &in1;
4781     const Sampling<typename In::In2> &in2;
4782     const Sampling<typename In::In3> &in3;
4783 };
4784 
4785 template <typename In>
4786 struct DefaultSamplings : Samplings<In>
4787 {
DefaultSamplingsdeqp::gls::BuiltinPrecisionTests::DefaultSamplings4788     DefaultSamplings(void)
4789         : Samplings<In>(instance<DefaultSampling<typename In::In0>>(), instance<DefaultSampling<typename In::In1>>(),
4790                         instance<DefaultSampling<typename In::In2>>(), instance<DefaultSampling<typename In::In3>>())
4791     {
4792     }
4793 };
4794 
4795 class PrecisionCase : public TestCase
4796 {
4797 public:
4798     IterateResult iterate(void);
4799 
4800 protected:
PrecisionCase(const Context & context,const string & name,const string & extension="")4801     PrecisionCase(const Context &context, const string &name, const string &extension = "")
4802         : TestCase(context.testContext, name.c_str(), name.c_str())
4803         , m_ctx(context)
4804         , m_status()
4805         , m_rnd(0xdeadbeefu + context.testContext.getCommandLine().getBaseSeed())
4806         , m_extension(extension)
4807     {
4808     }
4809 
getRenderContext(void) const4810     RenderContext &getRenderContext(void) const
4811     {
4812         return m_ctx.renderContext;
4813     }
4814 
getFormat(void) const4815     const FloatFormat &getFormat(void) const
4816     {
4817         return m_ctx.floatFormat;
4818     }
4819 
log(void) const4820     TestLog &log(void) const
4821     {
4822         return m_testCtx.getLog();
4823     }
4824 
4825     virtual void runTest(void) = 0;
4826 
4827     template <typename In, typename Out>
4828     void testStatement(const Variables<In, Out> &variables, const Inputs<In> &inputs, const Statement &stmt);
4829 
4830     template <typename T>
makeSymbol(const Variable<T> & variable)4831     Symbol makeSymbol(const Variable<T> &variable)
4832     {
4833         return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4834     }
4835 
4836     Context m_ctx;
4837     ResultCollector m_status;
4838     Random m_rnd;
4839     const string m_extension;
4840 };
4841 
iterate(void)4842 IterateResult PrecisionCase::iterate(void)
4843 {
4844     runTest();
4845     m_status.setTestContextResult(m_testCtx);
4846     return STOP;
4847 }
4848 
4849 template <typename In, typename Out>
testStatement(const Variables<In,Out> & variables,const Inputs<In> & inputs,const Statement & stmt)4850 void PrecisionCase::testStatement(const Variables<In, Out> &variables, const Inputs<In> &inputs, const Statement &stmt)
4851 {
4852     using namespace ShaderExecUtil;
4853 
4854     typedef typename In::In0 In0;
4855     typedef typename In::In1 In1;
4856     typedef typename In::In2 In2;
4857     typedef typename In::In3 In3;
4858     typedef typename Out::Out0 Out0;
4859     typedef typename Out::Out1 Out1;
4860 
4861     const FloatFormat &fmt = getFormat();
4862     const int inCount      = numInputs<In>();
4863     const int outCount     = numOutputs<Out>();
4864     const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4865     Outputs<Out> outputs(numValues);
4866     ShaderSpec spec;
4867     const FloatFormat highpFmt = m_ctx.highpFormat;
4868     const int maxMsgs          = 100;
4869     int numErrors              = 0;
4870     Environment env; // Hoisted out of the inner loop for optimization.
4871 
4872     switch (inCount)
4873     {
4874     case 4:
4875         DE_ASSERT(inputs.in3.size() == numValues);
4876     // Fallthrough
4877     case 3:
4878         DE_ASSERT(inputs.in2.size() == numValues);
4879     // Fallthrough
4880     case 2:
4881         DE_ASSERT(inputs.in1.size() == numValues);
4882     // Fallthrough
4883     case 1:
4884         DE_ASSERT(inputs.in0.size() == numValues);
4885     // Fallthrough
4886     default:
4887         break;
4888     }
4889 
4890     // Print out the statement and its definitions
4891     log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
4892     {
4893         ostringstream oss;
4894         FuncSet funcs;
4895 
4896         stmt.getUsedFuncs(funcs);
4897         for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4898         {
4899             (*it)->printDefinition(oss);
4900         }
4901         if (!funcs.empty())
4902             log() << TestLog::Message << "Reference definitions:\n" << oss.str() << TestLog::EndMessage;
4903     }
4904 
4905     // Initialize ShaderSpec from precision, variables and statement.
4906     {
4907         ostringstream os;
4908         os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4909         spec.globalDeclarations = os.str();
4910     }
4911 
4912     spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
4913 
4914     if (!m_extension.empty())
4915         spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4916 
4917     spec.inputs.resize(inCount);
4918 
4919     switch (inCount)
4920     {
4921     case 4:
4922         spec.inputs[3] = makeSymbol(*variables.in3);
4923     // Fallthrough
4924     case 3:
4925         spec.inputs[2] = makeSymbol(*variables.in2);
4926     // Fallthrough
4927     case 2:
4928         spec.inputs[1] = makeSymbol(*variables.in1);
4929     // Fallthrough
4930     case 1:
4931         spec.inputs[0] = makeSymbol(*variables.in0);
4932     // Fallthrough
4933     default:
4934         break;
4935     }
4936 
4937     spec.outputs.resize(outCount);
4938 
4939     switch (outCount)
4940     {
4941     case 2:
4942         spec.outputs[1] = makeSymbol(*variables.out1); // Fallthrough
4943     case 1:
4944         spec.outputs[0] = makeSymbol(*variables.out0);
4945     default:
4946         break;
4947     }
4948 
4949     spec.source = de::toString(stmt);
4950 
4951     // Run the shader with inputs.
4952     {
4953         UniquePtr<ShaderExecutor> executor(createExecutor(getRenderContext(), m_ctx.shaderType, spec));
4954         const void *inputArr[] = {
4955             &inputs.in0.front(),
4956             &inputs.in1.front(),
4957             &inputs.in2.front(),
4958             &inputs.in3.front(),
4959         };
4960         void *outputArr[] = {
4961             &outputs.out0.front(),
4962             &outputs.out1.front(),
4963         };
4964 
4965         executor->log(log());
4966         if (!executor->isOk())
4967             TCU_FAIL("Shader compilation failed");
4968 
4969         executor->useProgram();
4970         executor->execute(int(numValues), inputArr, outputArr);
4971     }
4972 
4973     // Initialize environment with unused values so we don't need to bind in inner loop.
4974     {
4975         const typename Traits<In0>::IVal in0;
4976         const typename Traits<In1>::IVal in1;
4977         const typename Traits<In2>::IVal in2;
4978         const typename Traits<In3>::IVal in3;
4979         const typename Traits<Out0>::IVal reference0;
4980         const typename Traits<Out1>::IVal reference1;
4981 
4982         env.bind(*variables.in0, in0);
4983         env.bind(*variables.in1, in1);
4984         env.bind(*variables.in2, in2);
4985         env.bind(*variables.in3, in3);
4986         env.bind(*variables.out0, reference0);
4987         env.bind(*variables.out1, reference1);
4988     }
4989 
4990     // For each input tuple, compute output reference interval and compare
4991     // shader output to the reference.
4992     for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4993     {
4994         bool result = true;
4995         bool inExpectedRange;
4996         bool inWarningRange;
4997         const char *failStr = "Fail";
4998         typename Traits<Out0>::IVal reference0;
4999         typename Traits<Out1>::IVal reference1;
5000 
5001         if (valueNdx % (size_t)TOUCH_WATCHDOG_VALUE_FREQUENCY == 0)
5002             m_testCtx.touchWatchdog();
5003 
5004         env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
5005         env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
5006         env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
5007         env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
5008 
5009         {
5010             EvalContext ctx(fmt, m_ctx.precision, env);
5011             stmt.execute(ctx);
5012         }
5013 
5014         switch (outCount)
5015         {
5016         case 2:
5017             reference1      = convert<Out1>(highpFmt, env.lookup(*variables.out1));
5018             inExpectedRange = contains(reference1, outputs.out1[valueNdx]);
5019             inWarningRange  = containsWarning(reference1, outputs.out1[valueNdx]);
5020             if (!inExpectedRange && inWarningRange)
5021             {
5022                 m_status.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Shader output 1 has low-quality shader precision");
5023                 failStr = "QualityWarning";
5024                 result  = false;
5025             }
5026             else if (!inExpectedRange)
5027             {
5028                 m_status.addResult(QP_TEST_RESULT_FAIL, "Shader output 1 is outside acceptable range");
5029                 failStr = "Fail";
5030                 result  = false;
5031             }
5032             // Fallthrough
5033 
5034         case 1:
5035             reference0      = convert<Out0>(highpFmt, env.lookup(*variables.out0));
5036             inExpectedRange = contains(reference0, outputs.out0[valueNdx]);
5037             inWarningRange  = containsWarning(reference0, outputs.out0[valueNdx]);
5038             if (!inExpectedRange && inWarningRange)
5039             {
5040                 m_status.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Shader output 0 has low-quality shader precision");
5041                 failStr = "QualityWarning";
5042                 result  = false;
5043             }
5044             else if (!inExpectedRange)
5045             {
5046                 m_status.addResult(QP_TEST_RESULT_FAIL, "Shader output 0 is outside acceptable range");
5047                 failStr = "Fail";
5048                 result  = false;
5049             }
5050 
5051         default:
5052             break;
5053         }
5054 
5055         if (!result)
5056             ++numErrors;
5057 
5058         if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
5059         {
5060             MessageBuilder builder = log().message();
5061 
5062             builder << (result ? "Passed" : failStr) << " sample:\n";
5063 
5064             if (inCount > 0)
5065             {
5066                 builder << "\t" << variables.in0->getName() << " = " << valueToString(highpFmt, inputs.in0[valueNdx])
5067                         << "\n";
5068             }
5069 
5070             if (inCount > 1)
5071             {
5072                 builder << "\t" << variables.in1->getName() << " = " << valueToString(highpFmt, inputs.in1[valueNdx])
5073                         << "\n";
5074             }
5075 
5076             if (inCount > 2)
5077             {
5078                 builder << "\t" << variables.in2->getName() << " = " << valueToString(highpFmt, inputs.in2[valueNdx])
5079                         << "\n";
5080             }
5081 
5082             if (inCount > 3)
5083             {
5084                 builder << "\t" << variables.in3->getName() << " = " << valueToString(highpFmt, inputs.in3[valueNdx])
5085                         << "\n";
5086             }
5087 
5088             if (outCount > 0)
5089             {
5090                 builder << "\t" << variables.out0->getName() << " = " << valueToString(highpFmt, outputs.out0[valueNdx])
5091                         << "\n"
5092                         << "\tExpected range: " << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
5093             }
5094 
5095             if (outCount > 1)
5096             {
5097                 builder << "\t" << variables.out1->getName() << " = " << valueToString(highpFmt, outputs.out1[valueNdx])
5098                         << "\n"
5099                         << "\tExpected range: " << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
5100             }
5101 
5102             builder << TestLog::EndMessage;
5103         }
5104     }
5105 
5106     if (numErrors > maxMsgs)
5107     {
5108         log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)" << TestLog::EndMessage;
5109     }
5110 
5111     if (numErrors == 0)
5112     {
5113         log() << TestLog::Message << "All " << numValues << " inputs passed." << TestLog::EndMessage;
5114     }
5115     else
5116     {
5117         log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed or had quality warnings."
5118               << TestLog::EndMessage;
5119     }
5120 }
5121 
5122 template <typename T>
5123 struct InputLess
5124 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess5125     bool operator()(const T &val1, const T &val2) const
5126     {
5127         return val1 < val2;
5128     }
5129 };
5130 
5131 template <typename T>
inputLess(const T & val1,const T & val2)5132 bool inputLess(const T &val1, const T &val2)
5133 {
5134     return InputLess<T>()(val1, val2);
5135 }
5136 
5137 template <>
5138 struct InputLess<float>
5139 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess5140     bool operator()(const float &val1, const float &val2) const
5141     {
5142         if (deIsNaN(val1))
5143             return false;
5144         if (deIsNaN(val2))
5145             return true;
5146         return val1 < val2;
5147     }
5148 };
5149 
5150 template <typename T, int Size>
5151 struct InputLess<Vector<T, Size>>
5152 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess5153     bool operator()(const Vector<T, Size> &vec1, const Vector<T, Size> &vec2) const
5154     {
5155         for (int ndx = 0; ndx < Size; ++ndx)
5156         {
5157             if (inputLess(vec1[ndx], vec2[ndx]))
5158                 return true;
5159             if (inputLess(vec2[ndx], vec1[ndx]))
5160                 return false;
5161         }
5162 
5163         return false;
5164     }
5165 };
5166 
5167 template <typename T, int Rows, int Cols>
5168 struct InputLess<Matrix<T, Rows, Cols>>
5169 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess5170     bool operator()(const Matrix<T, Rows, Cols> &mat1, const Matrix<T, Rows, Cols> &mat2) const
5171     {
5172         for (int col = 0; col < Cols; ++col)
5173         {
5174             if (inputLess(mat1[col], mat2[col]))
5175                 return true;
5176             if (inputLess(mat2[col], mat1[col]))
5177                 return false;
5178         }
5179 
5180         return false;
5181     }
5182 };
5183 
5184 template <typename In>
5185 struct InTuple : public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
5186 {
InTupledeqp::gls::BuiltinPrecisionTests::InTuple5187     InTuple(const typename In::In0 &in0, const typename In::In1 &in1, const typename In::In2 &in2,
5188             const typename In::In3 &in3)
5189         : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>(in0, in1, in2, in3)
5190     {
5191     }
5192 };
5193 
5194 template <typename In>
5195 struct InputLess<InTuple<In>>
5196 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess5197     bool operator()(const InTuple<In> &in1, const InTuple<In> &in2) const
5198     {
5199         if (inputLess(in1.a, in2.a))
5200             return true;
5201         if (inputLess(in2.a, in1.a))
5202             return false;
5203         if (inputLess(in1.b, in2.b))
5204             return true;
5205         if (inputLess(in2.b, in1.b))
5206             return false;
5207         if (inputLess(in1.c, in2.c))
5208             return true;
5209         if (inputLess(in2.c, in1.c))
5210             return false;
5211         if (inputLess(in1.d, in2.d))
5212             return true;
5213         return false;
5214     }
5215 };
5216 
5217 template <typename In>
generateInputs(const Samplings<In> & samplings,const FloatFormat & floatFormat,Precision intPrecision,size_t numSamples,Random & rnd)5218 Inputs<In> generateInputs(const Samplings<In> &samplings, const FloatFormat &floatFormat, Precision intPrecision,
5219                           size_t numSamples, Random &rnd)
5220 {
5221     Inputs<In> ret;
5222     Inputs<In> fixedInputs;
5223     set<InTuple<In>, InputLess<InTuple<In>>> seenInputs;
5224 
5225     samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
5226     samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
5227     samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
5228     samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
5229 
5230     for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
5231     {
5232         for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
5233         {
5234             for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
5235             {
5236                 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
5237                 {
5238                     const InTuple<In> tuple(fixedInputs.in0[ndx0], fixedInputs.in1[ndx1], fixedInputs.in2[ndx2],
5239                                             fixedInputs.in3[ndx3]);
5240 
5241                     seenInputs.insert(tuple);
5242                     ret.in0.push_back(tuple.a);
5243                     ret.in1.push_back(tuple.b);
5244                     ret.in2.push_back(tuple.c);
5245                     ret.in3.push_back(tuple.d);
5246                 }
5247             }
5248         }
5249     }
5250 
5251     for (size_t ndx = 0; ndx < numSamples; ++ndx)
5252     {
5253         const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
5254         const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
5255         const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
5256         const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
5257         const InTuple<In> tuple(in0, in1, in2, in3);
5258 
5259         if (de::contains(seenInputs, tuple))
5260             continue;
5261 
5262         seenInputs.insert(tuple);
5263         ret.in0.push_back(in0);
5264         ret.in1.push_back(in1);
5265         ret.in2.push_back(in2);
5266         ret.in3.push_back(in3);
5267     }
5268 
5269     return ret;
5270 }
5271 
5272 class FuncCaseBase : public PrecisionCase
5273 {
5274 public:
5275     IterateResult iterate(void);
5276 
5277 protected:
FuncCaseBase(const Context & context,const string & name,const FuncBase & func)5278     FuncCaseBase(const Context &context, const string &name, const FuncBase &func)
5279         : PrecisionCase(context, name, func.getRequiredExtension(context.renderContext))
5280     {
5281     }
5282 };
5283 
iterate(void)5284 IterateResult FuncCaseBase::iterate(void)
5285 {
5286     MovePtr<ContextInfo> info(ContextInfo::create(getRenderContext()));
5287 
5288     if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str()) &&
5289         !glu::contextSupports(getRenderContext().getType(), glu::ApiType::core(4, 5)))
5290         throw NotSupportedError("Unsupported extension: " + m_extension);
5291 
5292     runTest();
5293 
5294     m_status.setTestContextResult(m_testCtx);
5295     return STOP;
5296 }
5297 
5298 template <typename Sig>
5299 class FuncCase : public FuncCaseBase
5300 {
5301 public:
5302     typedef Func<Sig> CaseFunc;
5303     typedef typename Sig::Ret Ret;
5304     typedef typename Sig::Arg0 Arg0;
5305     typedef typename Sig::Arg1 Arg1;
5306     typedef typename Sig::Arg2 Arg2;
5307     typedef typename Sig::Arg3 Arg3;
5308     typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
5309     typedef OutTypes<Ret> Out;
5310 
FuncCase(const Context & context,const string & name,const CaseFunc & func)5311     FuncCase(const Context &context, const string &name, const CaseFunc &func)
5312         : FuncCaseBase(context, name, func)
5313         , m_func(func)
5314     {
5315     }
5316 
5317 protected:
5318     void runTest(void);
5319 
getSamplings(void)5320     virtual const Samplings<In> &getSamplings(void)
5321     {
5322         return instance<DefaultSamplings<In>>();
5323     }
5324 
5325 private:
5326     const CaseFunc &m_func;
5327 };
5328 
5329 template <typename Sig>
runTest(void)5330 void FuncCase<Sig>::runTest(void)
5331 {
5332     const Inputs<In> inputs(
5333         generateInputs(getSamplings(), m_ctx.floatFormat, m_ctx.precision, m_ctx.numRandoms, m_rnd));
5334     Variables<In, Out> variables;
5335 
5336     variables.out0 = variable<Ret>("out0");
5337     variables.out1 = variable<Void>("out1");
5338     variables.in0  = variable<Arg0>("in0");
5339     variables.in1  = variable<Arg1>("in1");
5340     variables.in2  = variable<Arg2>("in2");
5341     variables.in3  = variable<Arg3>("in3");
5342 
5343     {
5344         ExprP<Ret> expr = applyVar(m_func, variables.in0, variables.in1, variables.in2, variables.in3);
5345         StatementP stmt = variableAssignment(variables.out0, expr);
5346 
5347         this->testStatement(variables, inputs, *stmt);
5348     }
5349 }
5350 
5351 template <typename Sig>
5352 class InOutFuncCase : public FuncCaseBase
5353 {
5354 public:
5355     typedef Func<Sig> CaseFunc;
5356     typedef typename Sig::Ret Ret;
5357     typedef typename Sig::Arg0 Arg0;
5358     typedef typename Sig::Arg1 Arg1;
5359     typedef typename Sig::Arg2 Arg2;
5360     typedef typename Sig::Arg3 Arg3;
5361     typedef InTypes<Arg0, Arg2, Arg3> In;
5362     typedef OutTypes<Ret, Arg1> Out;
5363 
InOutFuncCase(const Context & context,const string & name,const CaseFunc & func)5364     InOutFuncCase(const Context &context, const string &name, const CaseFunc &func)
5365         : FuncCaseBase(context, name, func)
5366         , m_func(func)
5367     {
5368     }
5369 
5370 protected:
5371     void runTest(void);
5372 
getSamplings(void)5373     virtual const Samplings<In> &getSamplings(void)
5374     {
5375         return instance<DefaultSamplings<In>>();
5376     }
5377 
5378 private:
5379     const CaseFunc &m_func;
5380 };
5381 
5382 template <typename Sig>
runTest(void)5383 void InOutFuncCase<Sig>::runTest(void)
5384 {
5385     const Inputs<In> inputs(
5386         generateInputs(getSamplings(), m_ctx.floatFormat, m_ctx.precision, m_ctx.numRandoms, m_rnd));
5387     Variables<In, Out> variables;
5388 
5389     variables.out0 = variable<Ret>("out0");
5390     variables.out1 = variable<Arg1>("out1");
5391     variables.in0  = variable<Arg0>("in0");
5392     variables.in1  = variable<Arg2>("in1");
5393     variables.in2  = variable<Arg3>("in2");
5394     variables.in3  = variable<Void>("in3");
5395 
5396     {
5397         ExprP<Ret> expr = applyVar(m_func, variables.in0, variables.out1, variables.in1, variables.in2);
5398         StatementP stmt = variableAssignment(variables.out0, expr);
5399 
5400         this->testStatement(variables, inputs, *stmt);
5401     }
5402 }
5403 
5404 template <typename Sig>
createFuncCase(const Context & context,const string & name,const Func<Sig> & func)5405 PrecisionCase *createFuncCase(const Context &context, const string &name, const Func<Sig> &func)
5406 {
5407     switch (func.getOutParamIndex())
5408     {
5409     case -1:
5410         return new FuncCase<Sig>(context, name, func);
5411     case 1:
5412         return new InOutFuncCase<Sig>(context, name, func);
5413     default:
5414         DE_FATAL("Impossible");
5415     }
5416     return DE_NULL;
5417 }
5418 
5419 class CaseFactory
5420 {
5421 public:
~CaseFactory(void)5422     virtual ~CaseFactory(void)
5423     {
5424     }
5425     virtual MovePtr<TestNode> createCase(const Context &ctx) const = 0;
5426     virtual string getName(void) const                             = 0;
5427     virtual string getDesc(void) const                             = 0;
5428 };
5429 
5430 class FuncCaseFactory : public CaseFactory
5431 {
5432 public:
5433     virtual const FuncBase &getFunc(void) const = 0;
5434 
getName(void) const5435     string getName(void) const
5436     {
5437         return de::toLower(getFunc().getName());
5438     }
5439 
getDesc(void) const5440     string getDesc(void) const
5441     {
5442         return "Function '" + getFunc().getName() + "'";
5443     }
5444 };
5445 
5446 template <typename Sig>
5447 class GenFuncCaseFactory : public CaseFactory
5448 {
5449 public:
GenFuncCaseFactory(const GenFuncs<Sig> & funcs,const string & name)5450     GenFuncCaseFactory(const GenFuncs<Sig> &funcs, const string &name) : m_funcs(funcs), m_name(de::toLower(name))
5451     {
5452     }
5453 
createCase(const Context & ctx) const5454     MovePtr<TestNode> createCase(const Context &ctx) const
5455     {
5456         TestCaseGroup *group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5457 
5458         group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
5459         group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
5460         group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
5461         group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
5462 
5463         return MovePtr<TestNode>(group);
5464     }
5465 
getName(void) const5466     string getName(void) const
5467     {
5468         return m_name;
5469     }
5470 
getDesc(void) const5471     string getDesc(void) const
5472     {
5473         return "Function '" + m_funcs.func.getName() + "'";
5474     }
5475 
5476 private:
5477     const GenFuncs<Sig> m_funcs;
5478     string m_name;
5479 };
5480 
5481 template <template <int> class GenF>
5482 class TemplateFuncCaseFactory : public FuncCaseFactory
5483 {
5484 public:
createCase(const Context & ctx) const5485     MovePtr<TestNode> createCase(const Context &ctx) const
5486     {
5487         TestCaseGroup *group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5488         group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1>>()));
5489         group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2>>()));
5490         group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3>>()));
5491         group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4>>()));
5492 
5493         return MovePtr<TestNode>(group);
5494     }
5495 
getFunc(void) const5496     const FuncBase &getFunc(void) const
5497     {
5498         return instance<GenF<1>>();
5499     }
5500 };
5501 
5502 template <template <int> class GenF>
5503 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5504 {
5505 public:
createCase(const Context & ctx) const5506     MovePtr<TestNode> createCase(const Context &ctx) const
5507     {
5508         TestCaseGroup *group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5509         group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2>>()));
5510 #if 0
5511         // disabled until we get reasonable results
5512         group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5513         group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5514 #endif
5515 
5516         return MovePtr<TestNode>(group);
5517     }
5518 
getFunc(void) const5519     const FuncBase &getFunc(void) const
5520     {
5521         return instance<GenF<2>>();
5522     }
5523 };
5524 
5525 template <template <int, int> class GenF>
5526 class MatrixFuncCaseFactory : public FuncCaseFactory
5527 {
5528 public:
createCase(const Context & ctx) const5529     MovePtr<TestNode> createCase(const Context &ctx) const
5530     {
5531         TestCaseGroup *const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5532 
5533         this->addCase<2, 2>(ctx, group);
5534         this->addCase<3, 2>(ctx, group);
5535         this->addCase<4, 2>(ctx, group);
5536         this->addCase<2, 3>(ctx, group);
5537         this->addCase<3, 3>(ctx, group);
5538         this->addCase<4, 3>(ctx, group);
5539         this->addCase<2, 4>(ctx, group);
5540         this->addCase<3, 4>(ctx, group);
5541         this->addCase<4, 4>(ctx, group);
5542 
5543         return MovePtr<TestNode>(group);
5544     }
5545 
getFunc(void) const5546     const FuncBase &getFunc(void) const
5547     {
5548         return instance<GenF<2, 2>>();
5549     }
5550 
5551 private:
5552     template <int Rows, int Cols>
addCase(const Context & ctx,TestCaseGroup * group) const5553     void addCase(const Context &ctx, TestCaseGroup *group) const
5554     {
5555         const char *const name = dataTypeNameOf<Matrix<float, Rows, Cols>>();
5556 
5557         group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols>>()));
5558     }
5559 };
5560 
5561 template <typename Sig>
5562 class SimpleFuncCaseFactory : public CaseFactory
5563 {
5564 public:
SimpleFuncCaseFactory(const Func<Sig> & func)5565     SimpleFuncCaseFactory(const Func<Sig> &func) : m_func(func)
5566     {
5567     }
5568 
createCase(const Context & ctx) const5569     MovePtr<TestNode> createCase(const Context &ctx) const
5570     {
5571         return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func));
5572     }
5573 
getName(void) const5574     string getName(void) const
5575     {
5576         return de::toLower(m_func.getName());
5577     }
5578 
getDesc(void) const5579     string getDesc(void) const
5580     {
5581         return "Function '" + getName() + "'";
5582     }
5583 
5584 private:
5585     const Func<Sig> &m_func;
5586 };
5587 
5588 template <typename F>
createSimpleFuncCaseFactory(void)5589 SharedPtr<SimpleFuncCaseFactory<typename F::Sig>> createSimpleFuncCaseFactory(void)
5590 {
5591     return SharedPtr<SimpleFuncCaseFactory<typename F::Sig>>(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5592 }
5593 
5594 class BuiltinFuncs : public CaseFactories
5595 {
5596 public:
getFactories(void) const5597     const vector<const CaseFactory *> getFactories(void) const
5598     {
5599         vector<const CaseFactory *> ret;
5600 
5601         for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5602             ret.push_back(m_factories[ndx].get());
5603 
5604         return ret;
5605     }
5606 
addFactory(SharedPtr<const CaseFactory> fact)5607     void addFactory(SharedPtr<const CaseFactory> fact)
5608     {
5609         m_factories.push_back(fact);
5610     }
5611 
5612 private:
5613     vector<SharedPtr<const CaseFactory>> m_factories;
5614 };
5615 
5616 template <typename F>
addScalarFactory(BuiltinFuncs & funcs,string name="")5617 void addScalarFactory(BuiltinFuncs &funcs, string name = "")
5618 {
5619     if (name.empty())
5620         name = instance<F>().getName();
5621 
5622     funcs.addFactory(
5623         SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name)));
5624 }
5625 
createES3BuiltinCases(void)5626 MovePtr<const CaseFactories> createES3BuiltinCases(void)
5627 {
5628     MovePtr<BuiltinFuncs> funcs(new BuiltinFuncs());
5629 
5630     addScalarFactory<Add>(*funcs);
5631     addScalarFactory<Sub>(*funcs);
5632     addScalarFactory<Mul>(*funcs);
5633     addScalarFactory<Div>(*funcs);
5634 
5635     addScalarFactory<Radians>(*funcs);
5636     addScalarFactory<Degrees>(*funcs);
5637     addScalarFactory<Sin>(*funcs);
5638     addScalarFactory<Cos>(*funcs);
5639     addScalarFactory<Tan>(*funcs);
5640     addScalarFactory<ASin>(*funcs);
5641     addScalarFactory<ACos>(*funcs);
5642     addScalarFactory<ATan2>(*funcs, "atan2");
5643     addScalarFactory<ATan>(*funcs);
5644     addScalarFactory<Sinh>(*funcs);
5645     addScalarFactory<Cosh>(*funcs);
5646     addScalarFactory<Tanh>(*funcs);
5647     addScalarFactory<ASinh>(*funcs);
5648     addScalarFactory<ACosh>(*funcs);
5649     addScalarFactory<ATanh>(*funcs);
5650 
5651     addScalarFactory<Pow>(*funcs);
5652     addScalarFactory<Exp>(*funcs);
5653     addScalarFactory<Log>(*funcs);
5654     addScalarFactory<Exp2>(*funcs);
5655     addScalarFactory<Log2>(*funcs);
5656     addScalarFactory<Sqrt>(*funcs);
5657     addScalarFactory<InverseSqrt>(*funcs);
5658 
5659     addScalarFactory<Abs>(*funcs);
5660     addScalarFactory<Sign>(*funcs);
5661     addScalarFactory<Floor>(*funcs);
5662     addScalarFactory<Trunc>(*funcs);
5663     addScalarFactory<Round>(*funcs);
5664     addScalarFactory<RoundEven>(*funcs);
5665     addScalarFactory<Ceil>(*funcs);
5666     addScalarFactory<Fract>(*funcs);
5667     addScalarFactory<Mod>(*funcs);
5668     funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5669     addScalarFactory<Min>(*funcs);
5670     addScalarFactory<Max>(*funcs);
5671     addScalarFactory<Clamp>(*funcs);
5672     addScalarFactory<Mix>(*funcs);
5673     addScalarFactory<Step>(*funcs);
5674     addScalarFactory<SmoothStep>(*funcs);
5675 
5676     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5677     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5678     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5679     funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5680     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5681     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5682     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5683     funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5684 
5685     funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5686     funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5687     funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5688     funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5689     funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5690 
5691     return MovePtr<const CaseFactories>(funcs.release());
5692 }
5693 
createES31BuiltinCases(void)5694 MovePtr<const CaseFactories> createES31BuiltinCases(void)
5695 {
5696     MovePtr<BuiltinFuncs> funcs(new BuiltinFuncs());
5697 
5698     addScalarFactory<FrExp>(*funcs);
5699     addScalarFactory<LdExp>(*funcs);
5700     addScalarFactory<Fma>(*funcs);
5701 
5702     return MovePtr<const CaseFactories>(funcs.release());
5703 }
5704 
5705 struct PrecisionTestContext
5706 {
PrecisionTestContextdeqp::gls::BuiltinPrecisionTests::PrecisionTestContext5707     PrecisionTestContext(TestContext &testCtx_, RenderContext &renderCtx_, const FloatFormat &highp_,
5708                          const FloatFormat &mediump_, const FloatFormat &lowp_, const vector<ShaderType> &shaderTypes_,
5709                          int numRandoms_)
5710         : testCtx(testCtx_)
5711         , renderCtx(renderCtx_)
5712         , shaderTypes(shaderTypes_)
5713         , numRandoms(numRandoms_)
5714     {
5715         formats[glu::PRECISION_HIGHP]   = &highp_;
5716         formats[glu::PRECISION_MEDIUMP] = &mediump_;
5717         formats[glu::PRECISION_LOWP]    = &lowp_;
5718     }
5719 
5720     TestContext &testCtx;
5721     RenderContext &renderCtx;
5722     const FloatFormat *formats[glu::PRECISION_LAST];
5723     vector<ShaderType> shaderTypes;
5724     int numRandoms;
5725 };
5726 
createFuncGroup(const PrecisionTestContext & ctx,const CaseFactory & factory)5727 TestCaseGroup *createFuncGroup(const PrecisionTestContext &ctx, const CaseFactory &factory)
5728 {
5729     TestCaseGroup *const group = new TestCaseGroup(ctx.testCtx, factory.getName().c_str(), factory.getDesc().c_str());
5730 
5731     for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx)
5732     {
5733         const Precision precision = Precision(precNdx);
5734         const string precName(glu::getPrecisionName(precision));
5735         const FloatFormat &fmt      = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5736         const FloatFormat &highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, glu::PRECISION_HIGHP);
5737 
5738         for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5739         {
5740             const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5741             const string shaderName(glu::getShaderTypeName(shaderType));
5742             const string name = precName + "_" + shaderName;
5743             const Context caseCtx(name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt, precision, shaderType,
5744                                   ctx.numRandoms);
5745 
5746             group->addChild(factory.createCase(caseCtx).release());
5747         }
5748     }
5749 
5750     return group;
5751 }
5752 
addBuiltinPrecisionTests(TestContext & testCtx,RenderContext & renderCtx,const CaseFactories & cases,const vector<ShaderType> & shaderTypes,TestCaseGroup & dstGroup)5753 void addBuiltinPrecisionTests(TestContext &testCtx, RenderContext &renderCtx, const CaseFactories &cases,
5754                               const vector<ShaderType> &shaderTypes, TestCaseGroup &dstGroup)
5755 {
5756     const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5757     const int defRandoms  = 16384;
5758     const int numRandoms  = userRandoms > 0 ? userRandoms : defRandoms;
5759     const FloatFormat highp(-126, 127, 23, true,
5760                             tcu::MAYBE,  // subnormals
5761                             tcu::YES,    // infinities
5762                             tcu::MAYBE); // NaN
5763     // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5764     const FloatFormat mediump(-13, 13, 9, false);
5765     // A fixed-point format is just a floating point format with a fixed
5766     // exponent and support for subnormals.
5767     const FloatFormat lowp(0, 0, 7, false, tcu::YES);
5768     const PrecisionTestContext ctx(testCtx, renderCtx, highp, mediump, lowp, shaderTypes, numRandoms);
5769 
5770     for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5771         dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5772 }
5773 
5774 } // namespace BuiltinPrecisionTests
5775 } // namespace gls
5776 } // namespace deqp
5777