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