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