Home | History | Annotate | Download | only in randomshaders
      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);
     49 	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 
     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 
     66 CustomAbsOp::~CustomAbsOp (void)
     67 {
     68 	delete m_child;
     69 }
     70 
     71 void CustomAbsOp::setChild(Expression* expression)
     72 {
     73 	m_child = expression;
     74 }
     75 
     76 Expression* CustomAbsOp::createNextChild (GeneratorState&)
     77 {
     78 	DE_ASSERT(0);
     79 	return DE_NULL;
     80 }
     81 
     82 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 
     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		();
    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>
    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 <>
    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 <>
    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>
    158 void CustomBinaryOp<ComputeValue>::setLeftValue(Expression* expression)
    159 {
    160 	m_leftValueExpr = expression;
    161 }
    162 
    163 template <typename ComputeValue>
    164 void CustomBinaryOp<ComputeValue>::setRightValue(Expression* expression)
    165 {
    166 	m_rightValueExpr = expression;
    167 }
    168 
    169 template <typename ComputeValue>
    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 <>
    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>
    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>
    207 BinaryOp<Precedence, Assoc>::~BinaryOp (void)
    208 {
    209 	delete m_leftValueExpr;
    210 	delete m_rightValueExpr;
    211 }
    212 
    213 template <int Precedence, Associativity Assoc>
    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>
    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>
    343 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>
    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>
    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>
    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>
    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 
    463 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 
    522 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 
    531 MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    532 	: MulBase(state, Token::MUL, valueRange)
    533 {
    534 }
    535 
    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>
    547 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 <>
    576 void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
    577 {
    578 	DE_ASSERT(DE_FALSE);
    579 }
    580 
    581 AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    582 	: AddBase(state, Token::PLUS, valueRange)
    583 {
    584 }
    585 
    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>
    597 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 <>
    626 void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
    627 {
    628 	DE_ASSERT(DE_FALSE);
    629 }
    630 
    631 SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    632 	: SubBase(state, Token::MINUS, valueRange)
    633 {
    634 }
    635 
    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>
    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>
    689 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void)
    690 {
    691 }
    692 
    693 template <class ComputeValueRange, class EvaluateComp>
    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>
    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);
    731 template <> inline		float	getStep (void) { return 0.25f;	}
    732 template <> inline		int		getStep (void) { return 1;		}
    733 
    734 } // anonymous
    735 
    736 template <typename T>
    737 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 
    782 LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    783 	: LessThanBase(state, Token::CMP_LT, valueRange)
    784 {
    785 }
    786 
    787 float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    788 {
    789 	return LessThanBase::getWeight(state, valueRange);
    790 }
    791 
    792 template <typename T>
    793 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 
    838 LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    839 	: LessOrEqualBase(state, Token::CMP_LE, valueRange)
    840 {
    841 }
    842 
    843 float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    844 {
    845 	return LessOrEqualBase::getWeight(state, valueRange);
    846 }
    847 
    848 GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    849 	: GreaterThanBase(state, Token::CMP_GT, valueRange)
    850 {
    851 }
    852 
    853 float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    854 {
    855 	return GreaterThanBase::getWeight(state, valueRange);
    856 }
    857 
    858 GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    859 	: GreaterOrEqualBase(state, Token::CMP_GE, valueRange)
    860 {
    861 }
    862 
    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>
    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 <>
    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 <>
    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>
    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>
    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>
   1022 inline bool EqualityCompare<true>::compare	(T a, T b)			{ return a == b; }
   1023 
   1024 template <>
   1025 inline bool EqualityCompare<true>::combine	(bool a, bool b)	{ return a && b; }
   1026 
   1027 template <>
   1028 template <typename T>
   1029 inline bool EqualityCompare<false>::compare	(T a, T b)			{ return a != b; }
   1030 
   1031 template <>
   1032 inline bool EqualityCompare<false>::combine	(bool a, bool b)	{ return a || b; }
   1033 
   1034 } // anonymous
   1035 
   1036 template <bool IsEqual>
   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 
   1085 EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
   1086 	: EqualityComparisonOp<true>(state, valueRange)
   1087 {
   1088 }
   1089 
   1090 float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
   1091 {
   1092 	return EqualityComparisonOp<true>::getWeight(state, valueRange);
   1093 }
   1094 
   1095 NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
   1096 	: EqualityComparisonOp<false>(state, valueRange)
   1097 {
   1098 }
   1099 
   1100 float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
   1101 {
   1102 	return EqualityComparisonOp<false>::getWeight(state, valueRange);
   1103 }
   1104 
   1105 } // rsg
   1106