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