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