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