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