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