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