1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Random Shader Generator
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 Binary ops.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "rsgBinaryOps.hpp"
25 #include "rsgVariableManager.hpp"
26 #include "rsgUtils.hpp"
27 #include "deMath.h"
28 
29 using std::vector;
30 
31 namespace rsg
32 {
33 
34 // CustomAbsOp and CustomBinaryOp are used to resolve float comparision corner case.
35 // This error happened when two floats with the same value were compared
36 // without using epsilon. If result of this comparisment influenced the
37 // output color then result and reference images could differ.
38 class CustomAbsOp : public Expression
39 {
40 public:
41 								CustomAbsOp		(void);
42 	virtual						~CustomAbsOp	(void);
43 
44 	void						setChild				(Expression* expression);
45 	Expression*					createNextChild			(GeneratorState& state);
46 	void						tokenize				(GeneratorState& state, TokenStream& str) const;
47 
48 	void						evaluate				(ExecutionContext& execCtx);
getValue(void) const49 	ExecConstValueAccess		getValue				(void) const { return m_value.getValue(m_type); }
50 
51 private:
52 	std::string					m_function;
53 	VariableType				m_type;
54 	ExecValueStorage			m_value;
55 	Expression*					m_child;
56 };
57 
CustomAbsOp(void)58 CustomAbsOp::CustomAbsOp (void)
59 	: m_function		("abs")
60 	, m_type			(VariableType::TYPE_FLOAT, 1)
61 	, m_child			(DE_NULL)
62 {
63 	m_value.setStorage(m_type);
64 }
65 
~CustomAbsOp(void)66 CustomAbsOp::~CustomAbsOp (void)
67 {
68 	delete m_child;
69 }
70 
setChild(Expression * expression)71 void CustomAbsOp::setChild(Expression* expression)
72 {
73 	m_child = expression;
74 }
75 
createNextChild(GeneratorState &)76 Expression* CustomAbsOp::createNextChild (GeneratorState&)
77 {
78 	DE_ASSERT(0);
79 	return DE_NULL;
80 }
81 
tokenize(GeneratorState & state,TokenStream & str) const82 void CustomAbsOp::tokenize (GeneratorState& state, TokenStream& str) const
83 {
84 	str << Token(m_function.c_str()) << Token::LEFT_PAREN;
85 	m_child->tokenize(state, str);
86 	str << Token::RIGHT_PAREN;
87 }
88 
evaluate(ExecutionContext & execCtx)89 void CustomAbsOp::evaluate (ExecutionContext& execCtx)
90 {
91 	m_child->evaluate(execCtx);
92 
93 	ExecConstValueAccess	srcValue	= m_child->getValue();
94 	ExecValueAccess			dstValue	= m_value.getValue(m_type);
95 
96 	for (int elemNdx = 0; elemNdx < m_type.getNumElements(); elemNdx++)
97 	{
98 		ExecConstValueAccess	srcComp		= srcValue.component(elemNdx);
99 		ExecValueAccess			dstComp		= dstValue.component(elemNdx);
100 
101 		for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
102 			dstComp.asFloat(compNdx) = deFloatAbs(srcComp.asFloat(compNdx));
103 	}
104 }
105 
106 typedef BinaryOp<5, ASSOCIATIVITY_LEFT> CustomBinaryBase;
107 
108 // CustomBinaryOp and CustomAbsOp are used to resolve float comparision corner case.
109 // CustomBinaryOp supports addition and substraction as only those functionalities
110 // were needed.
111 template <typename ComputeValue>
112 class CustomBinaryOp: public CustomBinaryBase
113 {
114 public:
115 								CustomBinaryOp		();
~CustomBinaryOp(void)116 	virtual						~CustomBinaryOp		(void) {}
117 
118 	void						setLeftValue		(Expression* expression);
119 	void						setRightValue		(Expression* expression);
120 
121 	void						evaluate			(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b);
122 };
123 
124 template <typename ComputeValue>
CustomBinaryOp()125 CustomBinaryOp<ComputeValue>::CustomBinaryOp ()
126 	: CustomBinaryBase(Token::PLUS)
127 {
128 	// By default add operation is assumed, for every other operation
129 	// separate constructor specialization should be implemented
130 	m_type = VariableType(VariableType::TYPE_FLOAT, 1);
131 	m_value.setStorage(m_type);
132 }
133 
134 template <>
CustomBinaryOp()135 CustomBinaryOp<EvaluateSub>::CustomBinaryOp ()
136 	: CustomBinaryBase(Token::MINUS)
137 {
138 	// Specialization for substraction
139 	m_type = VariableType(VariableType::TYPE_FLOAT, 1);
140 	m_leftValueRange =	ValueRange(m_type);
141 	m_rightValueRange = ValueRange(m_type);
142 	m_value.setStorage(m_type);
143 }
144 
145 template <>
CustomBinaryOp()146 CustomBinaryOp<EvaluateLessThan>::CustomBinaryOp ()
147 	: CustomBinaryBase(Token::CMP_LT)
148 {
149 	// Specialization for less_then comparision
150 	m_type = VariableType(VariableType::TYPE_BOOL, 1);
151 	VariableType floatType = VariableType(VariableType::TYPE_FLOAT, 1);
152 	m_leftValueRange =	ValueRange(floatType);
153 	m_rightValueRange = ValueRange(floatType);
154 	m_value.setStorage(m_type);
155 }
156 
157 template <typename ComputeValue>
setLeftValue(Expression * expression)158 void CustomBinaryOp<ComputeValue>::setLeftValue(Expression* expression)
159 {
160 	m_leftValueExpr = expression;
161 }
162 
163 template <typename ComputeValue>
setRightValue(Expression * expression)164 void CustomBinaryOp<ComputeValue>::setRightValue(Expression* expression)
165 {
166 	m_rightValueExpr = expression;
167 }
168 
169 template <typename ComputeValue>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)170 void CustomBinaryOp<ComputeValue>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
171 {
172 	DE_ASSERT(dst.getType() == a.getType());
173 	DE_ASSERT(dst.getType() == b.getType());
174 	DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
175 
176 	for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
177 	{
178 		for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
179 			dst.component(elemNdx).asFloat(compNdx) = ComputeValue()(a.component(elemNdx).asFloat(compNdx),b.component(elemNdx).asFloat(compNdx));
180 	}
181 }
182 
183 template <>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)184 void CustomBinaryOp<EvaluateLessThan>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
185 {
186 	DE_ASSERT(a.getType() == b.getType());
187 	DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_BOOL);
188 
189 	for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
190 	{
191 		for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
192 			dst.component(elemNdx).asBool(compNdx) = EvaluateLessThan()(a.component(elemNdx).asFloat(compNdx),b.component(elemNdx).asFloat(compNdx));
193 	}
194 }
195 
196 template <int Precedence, Associativity Assoc>
BinaryOp(Token::Type operatorToken)197 BinaryOp<Precedence, Assoc>::BinaryOp (Token::Type operatorToken)
198 	: m_operator		(operatorToken)
199 	, m_leftValueRange	(m_type)
200 	, m_rightValueRange	(m_type)
201 	, m_leftValueExpr	(DE_NULL)
202 	, m_rightValueExpr	(DE_NULL)
203 {
204 }
205 
206 template <int Precedence, Associativity Assoc>
~BinaryOp(void)207 BinaryOp<Precedence, Assoc>::~BinaryOp (void)
208 {
209 	delete m_leftValueExpr;
210 	delete m_rightValueExpr;
211 }
212 
213 template <int Precedence, Associativity Assoc>
createNextChild(GeneratorState & state)214 Expression* BinaryOp<Precedence, Assoc>::createNextChild (GeneratorState& state)
215 {
216 	int leftPrec	= Assoc == ASSOCIATIVITY_LEFT ? Precedence : Precedence-1;
217 	int rightPrec	= Assoc == ASSOCIATIVITY_LEFT ? Precedence-1 : Precedence;
218 
219 	if (m_rightValueExpr == DE_NULL)
220 	{
221 		state.pushPrecedence(rightPrec);
222 		m_rightValueExpr = Expression::createRandom(state, m_rightValueRange.asAccess());
223 		state.popPrecedence();
224 		return m_rightValueExpr;
225 	}
226 	else if (m_leftValueExpr == DE_NULL)
227 	{
228 		state.pushPrecedence(leftPrec);
229 		m_leftValueExpr = Expression::createRandom(state, m_leftValueRange.asAccess());
230 		state.popPrecedence();
231 		return m_leftValueExpr;
232 	}
233 	else
234 	{
235 		// Check for corrner cases
236 		switch (m_operator)
237 		{
238 		case Token::CMP_LE:
239 		{
240 			// When comparing two floats epsilon should be included
241 			// to eliminate the risk that we get different results
242 			// because of precission error
243 			VariableType floatType(VariableType::TYPE_FLOAT, 1);
244 			if (m_rightValueRange.getType() == floatType)
245 			{
246 				FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f);
247 
248 				typedef CustomBinaryOp<EvaluateAdd> CustomAddOp;
249 				CustomAddOp* addOperation = new CustomAddOp();
250 				addOperation->setLeftValue(m_rightValueExpr);
251 				addOperation->setRightValue(epsilonLiteral);
252 
253 				// add epsilon to right-hand side
254 				m_rightValueExpr = addOperation;
255 			}
256 			break;
257 		}
258 		case Token::CMP_GE:
259 		{
260 			// When comparing two floats epsilon should be included
261 			// to eliminate the risk that we get different results
262 			// because of precission error
263 			VariableType floatType(VariableType::TYPE_FLOAT, 1);
264 			if (m_leftValueRange.getType() == floatType)
265 			{
266 				FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f);
267 
268 				typedef CustomBinaryOp<EvaluateAdd> CustomAddOp;
269 				CustomAddOp* addOperation = new CustomAddOp();
270 				addOperation->setLeftValue(m_leftValueExpr);
271 				addOperation->setRightValue(epsilonLiteral);
272 
273 				// add epsilon to left-hand side
274 				m_leftValueExpr = addOperation;
275 			}
276 			break;
277 		}
278 		case Token::CMP_EQ:
279 		{
280 			// When comparing two floats epsilon should be included
281 			// to eliminate the risk that we get different results
282 			// because of precission error
283 			VariableType floatType(VariableType::TYPE_FLOAT, 1);
284 			if (m_leftValueRange.getType() == floatType)
285 			{
286 				VariableType boolType(VariableType::TYPE_BOOL, 1);
287 				const ValueRange boolRange(boolType);
288 
289 				ParenOp* parenRight = new ParenOp(state, boolRange);
290 				parenRight->setChild(m_rightValueExpr);
291 
292 				typedef CustomBinaryOp<EvaluateSub> CustomSubOp;
293 				CustomSubOp* subOperation = new CustomSubOp();
294 				subOperation->setLeftValue(m_leftValueExpr);
295 				subOperation->setRightValue(parenRight);
296 
297 				CustomAbsOp* absOperation = new CustomAbsOp();
298 				absOperation->setChild(subOperation);
299 				FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f);
300 
301 				typedef CustomBinaryOp<EvaluateLessThan> CustomLessThanOp;
302 				CustomLessThanOp* lessOperation = new CustomLessThanOp();
303 				lessOperation->setLeftValue(absOperation);
304 				lessOperation->setRightValue(epsilonLiteral);
305 
306 				ParenOp* parenOperation = new ParenOp(state, boolRange);
307 				parenOperation->setChild(lessOperation);
308 				BoolLiteral* trueLiteral = new BoolLiteral(true);
309 
310 				// EQ operation cant be removed so it is replaced with:
311 				// ((abs(lhs-rhs) < epsilon) == true).
312 				m_leftValueExpr = parenOperation;
313 				m_rightValueExpr = trueLiteral;
314 			}
315 			break;
316 		}
317 		default:
318 			break;
319 		}
320 
321 		return DE_NULL;
322 	}
323 }
324 
325 template <int Precedence, Associativity Assoc>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)326 float BinaryOp<Precedence, Assoc>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
327 {
328 	if (state.getPrecedence() < Precedence)
329 		return 0.0f;
330 
331 	int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
332 
333 	if (valueRange.getType().isVoid())
334 		return availableLevels >= 2 ? unusedValueWeight : 0.0f;
335 
336 	if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1)
337 		return 0.0f;
338 
339 	return 1.0f;
340 }
341 
342 template <int Precedence, Associativity Assoc>
tokenize(GeneratorState & state,TokenStream & str) const343 void BinaryOp<Precedence, Assoc>::tokenize (GeneratorState& state, TokenStream& str) const
344 {
345 	m_leftValueExpr->tokenize(state, str);
346 	str << m_operator;
347 	m_rightValueExpr->tokenize(state, str);
348 }
349 
350 template <int Precedence, Associativity Assoc>
evaluate(ExecutionContext & execCtx)351 void BinaryOp<Precedence, Assoc>::evaluate (ExecutionContext& execCtx)
352 {
353 	m_leftValueExpr->evaluate(execCtx);
354 	m_rightValueExpr->evaluate(execCtx);
355 
356 	ExecConstValueAccess	leftVal		= m_leftValueExpr->getValue();
357 	ExecConstValueAccess	rightVal	= m_rightValueExpr->getValue();
358 	ExecValueAccess			dst			= m_value.getValue(m_type);
359 
360 	evaluate(dst, leftVal, rightVal);
361 }
362 
363 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
BinaryVecOp(GeneratorState & state,Token::Type operatorToken,ConstValueRangeAccess inValueRange)364 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::BinaryVecOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
365 	: BinaryOp<Precedence, ASSOCIATIVITY_LEFT>(operatorToken)
366 {
367 	ValueRange valueRange = inValueRange;
368 
369 	if (valueRange.getType().isVoid())
370 	{
371 		int							availableLevels	= state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
372 		vector<VariableType::Type>	baseTypes;
373 
374 		if (Float)	baseTypes.push_back(VariableType::TYPE_FLOAT);
375 		if (Int)	baseTypes.push_back(VariableType::TYPE_INT);
376 		if (Bool)	baseTypes.push_back(VariableType::TYPE_BOOL);
377 
378 		VariableType::Type	baseType	= state.getRandom().choose<VariableType::Type>(baseTypes.begin(), baseTypes.end());
379 		int					numElements	= state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
380 
381 		valueRange = ValueRange(VariableType(baseType, numElements));
382 		computeRandomValueRange(state, valueRange.asAccess());
383 	}
384 
385 	// Choose type, allocate storage for execution
386 	this->m_type = valueRange.getType();
387 	this->m_value.setStorage(this->m_type);
388 
389 	// Initialize storage for value ranges
390 	this->m_rightValueRange	= ValueRange(this->m_type);
391 	this->m_leftValueRange	= ValueRange(this->m_type);
392 
393 	VariableType::Type baseType = this->m_type.getBaseType();
394 
395 	// Compute range for b that satisfies requested value range
396 	for (int elemNdx = 0; elemNdx < this->m_type.getNumElements(); elemNdx++)
397 	{
398 		ConstValueRangeAccess	dst		= valueRange.asAccess().component(elemNdx);
399 		ValueRangeAccess		a		= this->m_leftValueRange.asAccess().component(elemNdx); // \todo [2011-03-25 pyry] Commutative: randomize inputs
400 		ValueRangeAccess		b		= this->m_rightValueRange.asAccess().component(elemNdx);
401 
402 		// Just pass undefined ranges
403 		if ((baseType == VariableType::TYPE_FLOAT || baseType == VariableType::TYPE_INT) && isUndefinedValueRange(dst))
404 		{
405 			a.getMin() = dst.getMin().value();
406 			b.getMin() = dst.getMin().value();
407 			a.getMax() = dst.getMax().value();
408 			b.getMax() = dst.getMax().value();
409 			continue;
410 		}
411 
412 		if (baseType == VariableType::TYPE_FLOAT)
413 			ComputeValueRange()(state.getRandom(), dst.getMin().asFloat(), dst.getMax().asFloat(),
414 								a.getMin().asFloat(), a.getMax().asFloat(),
415 								b.getMin().asFloat(), b.getMax().asFloat());
416 		else if (baseType == VariableType::TYPE_INT)
417 			ComputeValueRange()(state.getRandom(), dst.getMin().asInt(), dst.getMax().asInt(),
418 								a.getMin().asInt(), a.getMax().asInt(),
419 								b.getMin().asInt(), b.getMax().asInt());
420 		else
421 		{
422 			DE_ASSERT(baseType == VariableType::TYPE_BOOL);
423 			ComputeValueRange()(state.getRandom(), dst.getMin().asBool(), dst.getMax().asBool(),
424 								a.getMin().asBool(), a.getMax().asBool(),
425 								b.getMin().asBool(), b.getMax().asBool());
426 		}
427 	}
428 }
429 
430 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
~BinaryVecOp(void)431 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::~BinaryVecOp (void)
432 {
433 }
434 
435 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)436 void BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
437 {
438 	DE_ASSERT(dst.getType() == a.getType());
439 	DE_ASSERT(dst.getType() == b.getType());
440 	switch (dst.getType().getBaseType())
441 	{
442 		case VariableType::TYPE_FLOAT:
443 			for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
444 			{
445 				for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
446 					dst.component(elemNdx).asFloat(compNdx) = EvaluateComp()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx));
447 			}
448 			break;
449 
450 		case VariableType::TYPE_INT:
451 			for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
452 			{
453 				for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
454 					dst.component(elemNdx).asInt(compNdx) = EvaluateComp()(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx));
455 			}
456 			break;
457 
458 		default:
459 			DE_ASSERT(DE_FALSE); // Invalid type for multiplication
460 	}
461 }
462 
operator ()(de::Random & rnd,float dstMin,float dstMax,float & aMin,float & aMax,float & bMin,float & bMax) const463 void ComputeMulRange::operator() (de::Random& rnd, float dstMin, float dstMax, float& aMin, float& aMax, float& bMin, float& bMax) const
464 {
465 	const float minScale	 = 0.25f;
466 	const float maxScale	 = 2.0f;
467 	const float subRangeStep = 0.25f;
468 	const float scaleStep	 = 0.25f;
469 
470 	float scale		= getQuantizedFloat(rnd, minScale, maxScale, scaleStep);
471 	float scaledMin	= dstMin/scale;
472 	float scaledMax	= dstMax/scale;
473 
474 	// Quantize scaled value range if possible
475 	if (!quantizeFloatRange(scaledMin, scaledMax))
476 	{
477 		// Fall back to 1.0 as a scale
478 		scale		= 1.0f;
479 		scaledMin	= dstMin;
480 		scaledMax	= dstMax;
481 	}
482 
483 	float subRangeLen = getQuantizedFloat(rnd, 0.0f, scaledMax-scaledMin, subRangeStep);
484 	aMin = scaledMin + getQuantizedFloat(rnd, 0.0f, (scaledMax-scaledMin)-subRangeLen, subRangeStep);
485 	aMax = aMin + subRangeLen;
486 
487 	// Find scale range
488 	bMin = scale;
489 	bMax = scale;
490 	for (int i = 0; i < 5; i++)
491 	{
492 		if (de::inBounds(aMin*(scale-(float)i*scaleStep), dstMin, dstMax) &&
493 			de::inBounds(aMax*(scale-(float)i*scaleStep), dstMin, dstMax))
494 			bMin = scale-(float)i*scaleStep;
495 
496 		if (de::inBounds(aMin*(scale+(float)i*scaleStep), dstMin, dstMax) &&
497 			de::inBounds(aMax*(scale+(float)i*scaleStep), dstMin, dstMax))
498 			bMax = scale+(float)i*scaleStep;
499 	}
500 
501 	// Negative scale?
502 	if (rnd.getBool())
503 	{
504 		std::swap(aMin, aMax);
505 		std::swap(bMin, bMax);
506 		aMin	*= -1.0f;
507 		aMax	*= -1.0f;
508 		bMin	*= -1.0f;
509 		bMax	*= -1.0f;
510 	}
511 
512 #if defined(DE_DEBUG)
513 	const float eps = 0.001f;
514 	DE_ASSERT(aMin <= aMax && bMin <= bMax);
515 	DE_ASSERT(de::inRange(aMin*bMin, dstMin-eps, dstMax+eps));
516 	DE_ASSERT(de::inRange(aMin*bMax, dstMin-eps, dstMax+eps));
517 	DE_ASSERT(de::inRange(aMax*bMin, dstMin-eps, dstMax+eps));
518 	DE_ASSERT(de::inRange(aMax*bMax, dstMin-eps, dstMax+eps));
519 #endif
520 }
521 
operator ()(de::Random & rnd,int dstMin,int dstMax,int & aMin,int & aMax,int & bMin,int & bMax) const522 void ComputeMulRange::operator() (de::Random& rnd, int dstMin, int dstMax, int& aMin, int& aMax, int& bMin, int& bMax) const
523 {
524 	DE_UNREF(rnd);
525 	aMin	= dstMin;
526 	aMax	= dstMax;
527 	bMin	= 1;
528 	bMax	= 1;
529 }
530 
MulOp(GeneratorState & state,ConstValueRangeAccess valueRange)531 MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange)
532 	: MulBase(state, Token::MUL, valueRange)
533 {
534 }
535 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)536 float MulOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
537 {
538 	if (valueRange.getType().isVoid() ||
539 		valueRange.getType().isFloatOrVec() ||
540 		valueRange.getType().isIntOrVec())
541 		return MulBase::getWeight(state, valueRange);
542 	else
543 		return 0.0f;
544 }
545 
546 template <typename T>
operator ()(de::Random & random,T dstMin,T dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const547 void ComputeAddRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
548 {
549 	struct GetRandom
550 	{
551 		int		operator() (de::Random& rnd, int min, int max) const		{ return rnd.getInt(min, max); }
552 		float	operator() (de::Random& rnd, float min, float max) const	{ return getQuantizedFloat(rnd, min, max, 0.5f); }
553 	};
554 
555 	T rangeLen		= dstMax-dstMin;
556 	T subRangeLen	= GetRandom()(random, T(0), rangeLen);
557 	T aOffset		= GetRandom()(random, T(-8), T(8));
558 
559 	aMin			= dstMin+aOffset;
560 	aMax			= aMin+subRangeLen;
561 
562 	bMin			= -aOffset;
563 	bMax			= -aOffset+(rangeLen-subRangeLen);
564 
565 #if defined(DE_DEBUG)
566 	T eps = T(0.001);
567 	DE_ASSERT(aMin <= aMax && bMin <= bMax);
568 	DE_ASSERT(de::inRange(aMin+bMin, dstMin-eps, dstMax+eps));
569 	DE_ASSERT(de::inRange(aMin+bMax, dstMin-eps, dstMax+eps));
570 	DE_ASSERT(de::inRange(aMax+bMin, dstMin-eps, dstMax+eps));
571 	DE_ASSERT(de::inRange(aMax+bMax, dstMin-eps, dstMax+eps));
572 #endif
573 }
574 
575 template <>
operator()576 void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
577 {
578 	DE_ASSERT(DE_FALSE);
579 }
580 
AddOp(GeneratorState & state,ConstValueRangeAccess valueRange)581 AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange)
582 	: AddBase(state, Token::PLUS, valueRange)
583 {
584 }
585 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)586 float AddOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
587 {
588 	if (valueRange.getType().isVoid() ||
589 		valueRange.getType().isFloatOrVec() ||
590 		valueRange.getType().isIntOrVec())
591 		return AddBase::getWeight(state, valueRange);
592 	else
593 		return 0.0f;
594 }
595 
596 template <typename T>
operator ()(de::Random & random,T dstMin,T dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const597 void ComputeSubRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
598 {
599 	struct GetRandom
600 	{
601 		int		operator() (de::Random& rnd, int min, int max) const		{ return rnd.getInt(min, max); }
602 		float	operator() (de::Random& rnd, float min, float max) const	{ return getQuantizedFloat(rnd, min, max, 0.5f); }
603 	};
604 
605 	T rangeLen		= dstMax-dstMin;
606 	T subRangeLen	= GetRandom()(random, T(0), rangeLen);
607 	T aOffset		= GetRandom()(random, T(-8), T(8));
608 
609 	aMin			= dstMin+aOffset;
610 	aMax			= aMin+subRangeLen;
611 
612 	bMin			= aOffset-(rangeLen-subRangeLen);
613 	bMax			= aOffset;
614 
615 #if defined(DE_DEBUG)
616 	T eps = T(0.001);
617 	DE_ASSERT(aMin <= aMax && bMin <= bMax);
618 	DE_ASSERT(de::inRange(aMin-bMin, dstMin-eps, dstMax+eps));
619 	DE_ASSERT(de::inRange(aMin-bMax, dstMin-eps, dstMax+eps));
620 	DE_ASSERT(de::inRange(aMax-bMin, dstMin-eps, dstMax+eps));
621 	DE_ASSERT(de::inRange(aMax-bMax, dstMin-eps, dstMax+eps));
622 #endif
623 }
624 
625 template <>
operator()626 void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
627 {
628 	DE_ASSERT(DE_FALSE);
629 }
630 
SubOp(GeneratorState & state,ConstValueRangeAccess valueRange)631 SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange)
632 	: SubBase(state, Token::MINUS, valueRange)
633 {
634 }
635 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)636 float SubOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
637 {
638 	if (valueRange.getType().isVoid() ||
639 		valueRange.getType().isFloatOrVec() ||
640 		valueRange.getType().isIntOrVec())
641 		return SubBase::getWeight(state, valueRange);
642 	else
643 		return 0.0f;
644 }
645 
646 template <class ComputeValueRange, class EvaluateComp>
RelationalOp(GeneratorState & state,Token::Type operatorToken,ConstValueRangeAccess inValueRange)647 RelationalOp<ComputeValueRange, EvaluateComp>::RelationalOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
648 	: BinaryOp<7, ASSOCIATIVITY_LEFT>(operatorToken)
649 {
650 	ValueRange valueRange = inValueRange;
651 
652 	if (valueRange.getType().isVoid())
653 	{
654 		valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
655 		computeRandomValueRange(state, valueRange.asAccess());
656 	}
657 
658 	// Choose type, allocate storage for execution
659 	this->m_type = valueRange.getType();
660 	this->m_value.setStorage(this->m_type);
661 
662 	// Choose random input type
663 	VariableType::Type inBaseTypes[]	= { VariableType::TYPE_FLOAT, VariableType::TYPE_INT };
664 	VariableType::Type inBaseType		= state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
665 
666 	// Initialize storage for input value ranges
667 	this->m_rightValueRange	= ValueRange(VariableType(inBaseType, 1));
668 	this->m_leftValueRange	= ValueRange(VariableType(inBaseType, 1));
669 
670 	// Compute range for b that satisfies requested value range
671 	{
672 		bool					dstMin	= valueRange.getMin().asBool();
673 		bool					dstMax	= valueRange.getMax().asBool();
674 		ValueRangeAccess		a		= this->m_leftValueRange.asAccess();
675 		ValueRangeAccess		b		= this->m_rightValueRange.asAccess();
676 
677 		if (inBaseType == VariableType::TYPE_FLOAT)
678 			ComputeValueRange()(state.getRandom(), dstMin, dstMax,
679 								a.getMin().asFloat(), a.getMax().asFloat(),
680 								b.getMin().asFloat(), b.getMax().asFloat());
681 		else if (inBaseType == VariableType::TYPE_INT)
682 			ComputeValueRange()(state.getRandom(), dstMin, dstMax,
683 								a.getMin().asInt(), a.getMax().asInt(),
684 								b.getMin().asInt(), b.getMax().asInt());
685 	}
686 }
687 
688 template <class ComputeValueRange, class EvaluateComp>
~RelationalOp(void)689 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void)
690 {
691 }
692 
693 template <class ComputeValueRange, class EvaluateComp>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)694 void RelationalOp<ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
695 {
696 	DE_ASSERT(a.getType() == b.getType());
697 	switch (a.getType().getBaseType())
698 	{
699 		case VariableType::TYPE_FLOAT:
700 			for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
701 				dst.asBool(compNdx) = EvaluateComp()(a.asFloat(compNdx), b.asFloat(compNdx));
702 			break;
703 
704 		case VariableType::TYPE_INT:
705 			for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
706 				dst.asBool(compNdx) = EvaluateComp()(a.asInt(compNdx), b.asInt(compNdx));
707 			break;
708 
709 		default:
710 			DE_ASSERT(DE_FALSE);
711 	}
712 }
713 
714 template <class ComputeValueRange, class EvaluateComp>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)715 float RelationalOp<ComputeValueRange, EvaluateComp>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
716 {
717 	if (!state.getProgramParameters().useComparisonOps)
718 		return 0.0f;
719 
720 	if (valueRange.getType().isVoid() ||
721 		(valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
722 		return BinaryOp<7, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
723 	else
724 		return 0.0f;
725 }
726 
727 namespace
728 {
729 
730 template <typename T>	T		getStep (void);
getStep(void)731 template <> inline		float	getStep (void) { return 0.25f;	}
getStep(void)732 template <> inline		int		getStep (void) { return 1;		}
733 
734 } // anonymous
735 
736 template <typename T>
operator ()(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const737 void ComputeLessThanRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
738 {
739 	struct GetRandom
740 	{
741 		int		operator() (de::Random& random, int min, int max) const		{ return random.getInt(min, max); }
742 		float	operator() (de::Random& random, float min, float max) const	{ return getQuantizedFloat(random, min, max, getStep<float>()); }
743 	};
744 
745 	// One random range
746 	T	rLen	= GetRandom()(rnd, T(0), T(8));
747 	T	rMin	= GetRandom()(rnd, T(-4), T(4));
748 	T	rMax	= rMin+rLen;
749 
750 	if (dstMin == false && dstMax == true)
751 	{
752 		// Both values are possible, use same range for both inputs
753 		aMin	= rMin;
754 		aMax	= rMax;
755 		bMin	= rMin;
756 		bMax	= rMax;
757 	}
758 	else if (dstMin == true && dstMax == true)
759 	{
760 		// Compute range that is less than rMin..rMax
761 		T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
762 
763 		aMax	= rMin - getStep<T>();
764 		aMin	= aMax - aLen;
765 
766 		bMin	= rMin;
767 		bMax	= rMax;
768 	}
769 	else
770 	{
771 		// Compute range that is greater than or equal to rMin..rMax
772 		T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
773 
774 		aMin	= rMax;
775 		aMax	= aMin + aLen;
776 
777 		bMin	= rMin;
778 		bMax	= rMax;
779 	}
780 }
781 
LessThanOp(GeneratorState & state,ConstValueRangeAccess valueRange)782 LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
783 	: LessThanBase(state, Token::CMP_LT, valueRange)
784 {
785 }
786 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)787 float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
788 {
789 	return LessThanBase::getWeight(state, valueRange);
790 }
791 
792 template <typename T>
operator ()(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const793 void ComputeLessOrEqualRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
794 {
795 	struct GetRandom
796 	{
797 		int		operator() (de::Random& random, int min, int max) const		{ return random.getInt(min, max); }
798 		float	operator() (de::Random& random, float min, float max) const	{ return getQuantizedFloat(random, min, max, getStep<float>()); }
799 	};
800 
801 	// One random range
802 	T	rLen	= GetRandom()(rnd, T(0), T(8));
803 	T	rMin	= GetRandom()(rnd, T(-4), T(4));
804 	T	rMax	= rMin+rLen;
805 
806 	if (dstMin == false && dstMax == true)
807 	{
808 		// Both values are possible, use same range for both inputs
809 		aMin	= rMin;
810 		aMax	= rMax;
811 		bMin	= rMin;
812 		bMax	= rMax;
813 	}
814 	else if (dstMin == true && dstMax == true)
815 	{
816 		// Compute range that is less than or equal to rMin..rMax
817 		T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
818 
819 		aMax	= rMin;
820 		aMin	= aMax - aLen;
821 
822 		bMin	= rMin;
823 		bMax	= rMax;
824 	}
825 	else
826 	{
827 		// Compute range that is greater than rMin..rMax
828 		T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
829 
830 		aMin	= rMax + getStep<T>();
831 		aMax	= aMin + aLen;
832 
833 		bMin	= rMin;
834 		bMax	= rMax;
835 	}
836 }
837 
LessOrEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)838 LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
839 	: LessOrEqualBase(state, Token::CMP_LE, valueRange)
840 {
841 }
842 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)843 float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
844 {
845 	return LessOrEqualBase::getWeight(state, valueRange);
846 }
847 
GreaterThanOp(GeneratorState & state,ConstValueRangeAccess valueRange)848 GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
849 	: GreaterThanBase(state, Token::CMP_GT, valueRange)
850 {
851 }
852 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)853 float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
854 {
855 	return GreaterThanBase::getWeight(state, valueRange);
856 }
857 
GreaterOrEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)858 GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
859 	: GreaterOrEqualBase(state, Token::CMP_GE, valueRange)
860 {
861 }
862 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)863 float GreaterOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
864 {
865 	return GreaterOrEqualBase::getWeight(state, valueRange);
866 }
867 
868 namespace
869 {
870 
871 template <bool IsEqual, typename T>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax)872 void computeEqualityValueRange (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax)
873 {
874 	if (dstMin == false && dstMax == true)
875 		ComputeLessThanRange()(rnd, false, true, aMin, aMax, bMin, bMax);
876 	else if (IsEqual && dstMin == false)
877 		ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
878 	else if (!IsEqual && dstMin == true)
879 		ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
880 	else
881 	{
882 		// Must have exactly same values.
883 		struct GetRandom
884 		{
885 			int		operator() (de::Random& random, int min, int max) const		{ return random.getInt(min, max); }
886 			float	operator() (de::Random& random, float min, float max) const	{ return getQuantizedFloat(random, min, max, 0.5f); }
887 		};
888 
889 		T val = GetRandom()(rnd, T(-1), T(1));
890 
891 		aMin	= val;
892 		aMax	= val;
893 		bMin	= val;
894 		bMax	= val;
895 	}
896 }
897 
898 template <>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,bool & aMin,bool & aMax,bool & bMin,bool & bMax)899 void computeEqualityValueRange<true, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax)
900 {
901 	if (dstMin == false && dstMax == true)
902 	{
903 		aMin	= false;
904 		aMax	= true;
905 		bMin	= false;
906 		bMax	= true;
907 	}
908 	else if (dstMin == false)
909 	{
910 		DE_ASSERT(dstMax == false);
911 		bool val = rnd.getBool();
912 
913 		aMin	= val;
914 		aMax	= val;
915 		bMin	= !val;
916 		bMax	= !val;
917 	}
918 	else
919 	{
920 		DE_ASSERT(dstMin == true && dstMax == true);
921 		bool val = rnd.getBool();
922 
923 		aMin	= val;
924 		aMax	= val;
925 		bMin	= val;
926 		bMax	= val;
927 	}
928 }
929 
930 template <>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,bool & aMin,bool & aMax,bool & bMin,bool & bMax)931 void computeEqualityValueRange<false, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax)
932 {
933 	if (dstMin == false && dstMax == true)
934 		computeEqualityValueRange<true>(rnd, dstMin, dstMax, aMin, aMax, bMin, bMax);
935 	else
936 		computeEqualityValueRange<true>(rnd, !dstMin, !dstMax, aMin, aMax, bMin, bMax);
937 }
938 
939 } // anonymous
940 
941 template <bool IsEqual>
EqualityComparisonOp(GeneratorState & state,ConstValueRangeAccess inValueRange)942 EqualityComparisonOp<IsEqual>::EqualityComparisonOp (GeneratorState& state, ConstValueRangeAccess inValueRange)
943 	: BinaryOp<8, ASSOCIATIVITY_LEFT>(IsEqual ? Token::CMP_EQ : Token::CMP_NE)
944 {
945 	ValueRange valueRange = inValueRange;
946 
947 	if (valueRange.getType().isVoid())
948 	{
949 		valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
950 		computeRandomValueRange(state, valueRange.asAccess());
951 	}
952 
953 	// Choose type, allocate storage for execution
954 	this->m_type = valueRange.getType();
955 	this->m_value.setStorage(this->m_type);
956 
957 	// Choose random input type
958 	VariableType::Type inBaseTypes[]	= { VariableType::TYPE_FLOAT, VariableType::TYPE_INT };
959 	VariableType::Type inBaseType		= state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
960 	int					availableLevels	= state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
961 	int					numElements		= state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
962 
963 	// Initialize storage for input value ranges
964 	this->m_rightValueRange	= ValueRange(VariableType(inBaseType, numElements));
965 	this->m_leftValueRange	= ValueRange(VariableType(inBaseType, numElements));
966 
967 	// Compute range for b that satisfies requested value range
968 	for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
969 	{
970 		bool					dstMin	= valueRange.getMin().asBool();
971 		bool					dstMax	= valueRange.getMax().asBool();
972 
973 		ValueRangeAccess		a		= this->m_leftValueRange.asAccess().component(elementNdx);
974 		ValueRangeAccess		b		= this->m_rightValueRange.asAccess().component(elementNdx);
975 
976 		if (inBaseType == VariableType::TYPE_FLOAT)
977 			computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
978 											   a.getMin().asFloat(), a.getMax().asFloat(),
979 											   b.getMin().asFloat(), b.getMax().asFloat());
980 		else if (inBaseType == VariableType::TYPE_INT)
981 			computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
982 											   a.getMin().asInt(), a.getMax().asInt(),
983 											   b.getMin().asInt(), b.getMax().asInt());
984 		else
985 		{
986 			DE_ASSERT(inBaseType == VariableType::TYPE_BOOL);
987 			computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
988 											   a.getMin().asBool(), a.getMax().asBool(),
989 											   b.getMin().asBool(), b.getMax().asBool());
990 		}
991 	}
992 }
993 
994 template <bool IsEqual>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)995 float EqualityComparisonOp<IsEqual>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
996 {
997 	if (!state.getProgramParameters().useComparisonOps)
998 		return 0.0f;
999 
1000 	// \todo [2011-06-13 pyry] Weight down cases that would force constant inputs.
1001 
1002 	if (valueRange.getType().isVoid() ||
1003 		(valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
1004 		return BinaryOp<8, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
1005 	else
1006 		return 0.0f;
1007 }
1008 
1009 namespace
1010 {
1011 
1012 template <bool IsEqual>
1013 struct EqualityCompare
1014 {
1015 	template <typename T>
1016 	static bool compare (T a, T b);
1017 	static bool combine (bool a, bool b);
1018 };
1019 
1020 template <>
1021 template <typename T>
compare(T a,T b)1022 inline bool EqualityCompare<true>::compare	(T a, T b)			{ return a == b; }
1023 
1024 template <>
combine(bool a,bool b)1025 inline bool EqualityCompare<true>::combine	(bool a, bool b)	{ return a && b; }
1026 
1027 template <>
1028 template <typename T>
compare(T a,T b)1029 inline bool EqualityCompare<false>::compare	(T a, T b)			{ return a != b; }
1030 
1031 template <>
combine(bool a,bool b)1032 inline bool EqualityCompare<false>::combine	(bool a, bool b)	{ return a || b; }
1033 
1034 } // anonymous
1035 
1036 template <bool IsEqual>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)1037 void EqualityComparisonOp<IsEqual>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
1038 {
1039 	DE_ASSERT(a.getType() == b.getType());
1040 
1041 
1042 	switch (a.getType().getBaseType())
1043 	{
1044 		case VariableType::TYPE_FLOAT:
1045 			for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
1046 			{
1047 				bool result = IsEqual ? true : false;
1048 
1049 				for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
1050 					result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx)));
1051 
1052 				dst.asBool(compNdx) = result;
1053 			}
1054 			break;
1055 
1056 		case VariableType::TYPE_INT:
1057 			for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
1058 			{
1059 				bool result = IsEqual ? true : false;
1060 
1061 				for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
1062 					result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx)));
1063 
1064 				dst.asBool(compNdx) = result;
1065 			}
1066 			break;
1067 
1068 		case VariableType::TYPE_BOOL:
1069 			for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
1070 			{
1071 				bool result = IsEqual ? true : false;
1072 
1073 				for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
1074 					result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asBool(compNdx), b.component(elemNdx).asBool(compNdx)));
1075 
1076 				dst.asBool(compNdx) = result;
1077 			}
1078 			break;
1079 
1080 		default:
1081 			DE_ASSERT(DE_FALSE);
1082 	}
1083 }
1084 
EqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)1085 EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
1086 	: EqualityComparisonOp<true>(state, valueRange)
1087 {
1088 }
1089 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1090 float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
1091 {
1092 	return EqualityComparisonOp<true>::getWeight(state, valueRange);
1093 }
1094 
NotEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)1095 NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
1096 	: EqualityComparisonOp<false>(state, valueRange)
1097 {
1098 }
1099 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1100 float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
1101 {
1102 	return EqualityComparisonOp<false>::getWeight(state, valueRange);
1103 }
1104 
1105 } // rsg
1106