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