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