Add CTS_ARB_gl_spirv test implementation
[platform/upstream/VK-GL-CTS.git] / framework / randomshaders / rsgBinaryOps.cpp
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 template <int Precedence, Associativity Assoc>
35 BinaryOp<Precedence, Assoc>::BinaryOp (Token::Type operatorToken)
36         : m_operator            (operatorToken)
37         , m_leftValueRange      (m_type)
38         , m_rightValueRange     (m_type)
39         , m_leftValueExpr       (DE_NULL)
40         , m_rightValueExpr      (DE_NULL)
41 {
42 }
43
44 template <int Precedence, Associativity Assoc>
45 BinaryOp<Precedence, Assoc>::~BinaryOp (void)
46 {
47         delete m_leftValueExpr;
48         delete m_rightValueExpr;
49 }
50
51 template <int Precedence, Associativity Assoc>
52 Expression* BinaryOp<Precedence, Assoc>::createNextChild (GeneratorState& state)
53 {
54         int leftPrec    = Assoc == ASSOCIATIVITY_LEFT ? Precedence : Precedence-1;
55         int rightPrec   = Assoc == ASSOCIATIVITY_LEFT ? Precedence-1 : Precedence;
56
57         if (m_rightValueExpr == DE_NULL)
58         {
59                 state.pushPrecedence(rightPrec);
60                 m_rightValueExpr = Expression::createRandom(state, m_rightValueRange.asAccess());
61                 state.popPrecedence();
62                 return m_rightValueExpr;
63         }
64         else if (m_leftValueExpr == DE_NULL)
65         {
66                 state.pushPrecedence(leftPrec);
67                 m_leftValueExpr = Expression::createRandom(state, m_leftValueRange.asAccess());
68                 state.popPrecedence();
69                 return m_leftValueExpr;
70         }
71         else
72                 return DE_NULL;
73 }
74
75 template <int Precedence, Associativity Assoc>
76 float BinaryOp<Precedence, Assoc>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
77 {
78         if (state.getPrecedence() < Precedence)
79                 return 0.0f;
80
81         int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
82
83         if (valueRange.getType().isVoid())
84                 return availableLevels >= 2 ? unusedValueWeight : 0.0f;
85
86         if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1)
87                 return 0.0f;
88
89         return 1.0f;
90 }
91
92 template <int Precedence, Associativity Assoc>
93 void BinaryOp<Precedence, Assoc>::tokenize (GeneratorState& state, TokenStream& str) const
94 {
95         m_leftValueExpr->tokenize(state, str);
96         str << m_operator;
97         m_rightValueExpr->tokenize(state, str);
98 }
99
100 template <int Precedence, Associativity Assoc>
101 void BinaryOp<Precedence, Assoc>::evaluate (ExecutionContext& execCtx)
102 {
103         m_leftValueExpr->evaluate(execCtx);
104         m_rightValueExpr->evaluate(execCtx);
105
106         ExecConstValueAccess    leftVal         = m_leftValueExpr->getValue();
107         ExecConstValueAccess    rightVal        = m_rightValueExpr->getValue();
108         ExecValueAccess                 dst                     = m_value.getValue(m_type);
109
110         evaluate(dst, leftVal, rightVal);
111 }
112
113 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
114 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::BinaryVecOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
115         : BinaryOp<Precedence, ASSOCIATIVITY_LEFT>(operatorToken)
116 {
117         ValueRange valueRange = inValueRange;
118
119         if (valueRange.getType().isVoid())
120         {
121                 int                                                     availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
122                 vector<VariableType::Type>      baseTypes;
123
124                 if (Float)      baseTypes.push_back(VariableType::TYPE_FLOAT);
125                 if (Int)        baseTypes.push_back(VariableType::TYPE_INT);
126                 if (Bool)       baseTypes.push_back(VariableType::TYPE_BOOL);
127
128                 VariableType::Type      baseType        = state.getRandom().choose<VariableType::Type>(baseTypes.begin(), baseTypes.end());
129                 int                                     numElements     = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
130
131                 valueRange = ValueRange(VariableType(baseType, numElements));
132                 computeRandomValueRange(state, valueRange.asAccess());
133         }
134
135         // Choose type, allocate storage for execution
136         this->m_type = valueRange.getType();
137         this->m_value.setStorage(this->m_type);
138
139         // Initialize storage for value ranges
140         this->m_rightValueRange = ValueRange(this->m_type);
141         this->m_leftValueRange  = ValueRange(this->m_type);
142
143         VariableType::Type baseType = this->m_type.getBaseType();
144
145         // Compute range for b that satisfies requested value range
146         for (int elemNdx = 0; elemNdx < this->m_type.getNumElements(); elemNdx++)
147         {
148                 ConstValueRangeAccess   dst             = valueRange.asAccess().component(elemNdx);
149                 ValueRangeAccess                a               = this->m_leftValueRange.asAccess().component(elemNdx); // \todo [2011-03-25 pyry] Commutative: randomize inputs
150                 ValueRangeAccess                b               = this->m_rightValueRange.asAccess().component(elemNdx);
151
152                 // Just pass undefined ranges
153                 if ((baseType == VariableType::TYPE_FLOAT || baseType == VariableType::TYPE_INT) && isUndefinedValueRange(dst))
154                 {
155                         a.getMin() = dst.getMin().value();
156                         b.getMin() = dst.getMin().value();
157                         a.getMax() = dst.getMax().value();
158                         b.getMax() = dst.getMax().value();
159                         continue;
160                 }
161
162                 if (baseType == VariableType::TYPE_FLOAT)
163                         ComputeValueRange()(state.getRandom(), dst.getMin().asFloat(), dst.getMax().asFloat(),
164                                                                 a.getMin().asFloat(), a.getMax().asFloat(),
165                                                                 b.getMin().asFloat(), b.getMax().asFloat());
166                 else if (baseType == VariableType::TYPE_INT)
167                         ComputeValueRange()(state.getRandom(), dst.getMin().asInt(), dst.getMax().asInt(),
168                                                                 a.getMin().asInt(), a.getMax().asInt(),
169                                                                 b.getMin().asInt(), b.getMax().asInt());
170                 else
171                 {
172                         DE_ASSERT(baseType == VariableType::TYPE_BOOL);
173                         ComputeValueRange()(state.getRandom(), dst.getMin().asBool(), dst.getMax().asBool(),
174                                                                 a.getMin().asBool(), a.getMax().asBool(),
175                                                                 b.getMin().asBool(), b.getMax().asBool());
176                 }
177         }
178 }
179
180 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
181 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::~BinaryVecOp (void)
182 {
183 }
184
185 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
186 void BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
187 {
188         DE_ASSERT(dst.getType() == a.getType());
189         DE_ASSERT(dst.getType() == b.getType());
190         switch (dst.getType().getBaseType())
191         {
192                 case VariableType::TYPE_FLOAT:
193                         for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
194                         {
195                                 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
196                                         dst.component(elemNdx).asFloat(compNdx) = EvaluateComp()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx));
197                         }
198                         break;
199
200                 case VariableType::TYPE_INT:
201                         for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
202                         {
203                                 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
204                                         dst.component(elemNdx).asInt(compNdx) = EvaluateComp()(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx));
205                         }
206                         break;
207
208                 default:
209                         DE_ASSERT(DE_FALSE); // Invalid type for multiplication
210         }
211 }
212
213 void ComputeMulRange::operator() (de::Random& rnd, float dstMin, float dstMax, float& aMin, float& aMax, float& bMin, float& bMax) const
214 {
215         const float minScale     = 0.25f;
216         const float maxScale     = 2.0f;
217         const float subRangeStep = 0.25f;
218         const float scaleStep    = 0.25f;
219
220         float scale             = getQuantizedFloat(rnd, minScale, maxScale, scaleStep);
221         float scaledMin = dstMin/scale;
222         float scaledMax = dstMax/scale;
223
224         // Quantize scaled value range if possible
225         if (!quantizeFloatRange(scaledMin, scaledMax))
226         {
227                 // Fall back to 1.0 as a scale
228                 scale           = 1.0f;
229                 scaledMin       = dstMin;
230                 scaledMax       = dstMax;
231         }
232
233         float subRangeLen = getQuantizedFloat(rnd, 0.0f, scaledMax-scaledMin, subRangeStep);
234         aMin = scaledMin + getQuantizedFloat(rnd, 0.0f, (scaledMax-scaledMin)-subRangeLen, subRangeStep);
235         aMax = aMin + subRangeLen;
236
237         // Find scale range
238         bMin = scale;
239         bMax = scale;
240         for (int i = 0; i < 5; i++)
241         {
242                 if (de::inBounds(aMin*(scale-(float)i*scaleStep), dstMin, dstMax) &&
243                         de::inBounds(aMax*(scale-(float)i*scaleStep), dstMin, dstMax))
244                         bMin = scale-(float)i*scaleStep;
245
246                 if (de::inBounds(aMin*(scale+(float)i*scaleStep), dstMin, dstMax) &&
247                         de::inBounds(aMax*(scale+(float)i*scaleStep), dstMin, dstMax))
248                         bMax = scale+(float)i*scaleStep;
249         }
250
251         // Negative scale?
252         if (rnd.getBool())
253         {
254                 std::swap(aMin, aMax);
255                 std::swap(bMin, bMax);
256                 aMin    *= -1.0f;
257                 aMax    *= -1.0f;
258                 bMin    *= -1.0f;
259                 bMax    *= -1.0f;
260         }
261
262 #if defined(DE_DEBUG)
263         const float eps = 0.001f;
264         DE_ASSERT(aMin <= aMax && bMin <= bMax);
265         DE_ASSERT(de::inRange(aMin*bMin, dstMin-eps, dstMax+eps));
266         DE_ASSERT(de::inRange(aMin*bMax, dstMin-eps, dstMax+eps));
267         DE_ASSERT(de::inRange(aMax*bMin, dstMin-eps, dstMax+eps));
268         DE_ASSERT(de::inRange(aMax*bMax, dstMin-eps, dstMax+eps));
269 #endif
270 }
271
272 void ComputeMulRange::operator() (de::Random& rnd, int dstMin, int dstMax, int& aMin, int& aMax, int& bMin, int& bMax) const
273 {
274         DE_UNREF(rnd);
275         aMin    = dstMin;
276         aMax    = dstMax;
277         bMin    = 1;
278         bMax    = 1;
279 }
280
281 MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange)
282         : MulBase(state, Token::MUL, valueRange)
283 {
284 }
285
286 float MulOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
287 {
288         if (valueRange.getType().isVoid() ||
289                 valueRange.getType().isFloatOrVec() ||
290                 valueRange.getType().isIntOrVec())
291                 return MulBase::getWeight(state, valueRange);
292         else
293                 return 0.0f;
294 }
295
296 template <typename T>
297 void ComputeAddRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
298 {
299         struct GetRandom
300         {
301                 int             operator() (de::Random& rnd, int min, int max) const            { return rnd.getInt(min, max); }
302                 float   operator() (de::Random& rnd, float min, float max) const        { return getQuantizedFloat(rnd, min, max, 0.5f); }
303         };
304
305         T rangeLen              = dstMax-dstMin;
306         T subRangeLen   = GetRandom()(random, T(0), rangeLen);
307         T aOffset               = GetRandom()(random, T(-8), T(8));
308
309         aMin                    = dstMin+aOffset;
310         aMax                    = aMin+subRangeLen;
311
312         bMin                    = -aOffset;
313         bMax                    = -aOffset+(rangeLen-subRangeLen);
314
315 #if defined(DE_DEBUG)
316         T eps = T(0.001);
317         DE_ASSERT(aMin <= aMax && bMin <= bMax);
318         DE_ASSERT(de::inRange(aMin+bMin, dstMin-eps, dstMax+eps));
319         DE_ASSERT(de::inRange(aMin+bMax, dstMin-eps, dstMax+eps));
320         DE_ASSERT(de::inRange(aMax+bMin, dstMin-eps, dstMax+eps));
321         DE_ASSERT(de::inRange(aMax+bMax, dstMin-eps, dstMax+eps));
322 #endif
323 }
324
325 template <>
326 void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
327 {
328         DE_ASSERT(DE_FALSE);
329 }
330
331 AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange)
332         : AddBase(state, Token::PLUS, valueRange)
333 {
334 }
335
336 float AddOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
337 {
338         if (valueRange.getType().isVoid() ||
339                 valueRange.getType().isFloatOrVec() ||
340                 valueRange.getType().isIntOrVec())
341                 return AddBase::getWeight(state, valueRange);
342         else
343                 return 0.0f;
344 }
345
346 template <typename T>
347 void ComputeSubRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
348 {
349         struct GetRandom
350         {
351                 int             operator() (de::Random& rnd, int min, int max) const            { return rnd.getInt(min, max); }
352                 float   operator() (de::Random& rnd, float min, float max) const        { return getQuantizedFloat(rnd, min, max, 0.5f); }
353         };
354
355         T rangeLen              = dstMax-dstMin;
356         T subRangeLen   = GetRandom()(random, T(0), rangeLen);
357         T aOffset               = GetRandom()(random, T(-8), T(8));
358
359         aMin                    = dstMin+aOffset;
360         aMax                    = aMin+subRangeLen;
361
362         bMin                    = aOffset-(rangeLen-subRangeLen);
363         bMax                    = aOffset;
364
365 #if defined(DE_DEBUG)
366         T eps = T(0.001);
367         DE_ASSERT(aMin <= aMax && bMin <= bMax);
368         DE_ASSERT(de::inRange(aMin-bMin, dstMin-eps, dstMax+eps));
369         DE_ASSERT(de::inRange(aMin-bMax, dstMin-eps, dstMax+eps));
370         DE_ASSERT(de::inRange(aMax-bMin, dstMin-eps, dstMax+eps));
371         DE_ASSERT(de::inRange(aMax-bMax, dstMin-eps, dstMax+eps));
372 #endif
373 }
374
375 template <>
376 void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
377 {
378         DE_ASSERT(DE_FALSE);
379 }
380
381 SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange)
382         : SubBase(state, Token::MINUS, valueRange)
383 {
384 }
385
386 float SubOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
387 {
388         if (valueRange.getType().isVoid() ||
389                 valueRange.getType().isFloatOrVec() ||
390                 valueRange.getType().isIntOrVec())
391                 return SubBase::getWeight(state, valueRange);
392         else
393                 return 0.0f;
394 }
395
396 template <class ComputeValueRange, class EvaluateComp>
397 RelationalOp<ComputeValueRange, EvaluateComp>::RelationalOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
398         : BinaryOp<7, ASSOCIATIVITY_LEFT>(operatorToken)
399 {
400         ValueRange valueRange = inValueRange;
401
402         if (valueRange.getType().isVoid())
403         {
404                 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
405                 computeRandomValueRange(state, valueRange.asAccess());
406         }
407
408         // Choose type, allocate storage for execution
409         this->m_type = valueRange.getType();
410         this->m_value.setStorage(this->m_type);
411
412         // Choose random input type
413         VariableType::Type inBaseTypes[]        = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT };
414         VariableType::Type inBaseType           = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
415
416         // Initialize storage for input value ranges
417         this->m_rightValueRange = ValueRange(VariableType(inBaseType, 1));
418         this->m_leftValueRange  = ValueRange(VariableType(inBaseType, 1));
419
420         // Compute range for b that satisfies requested value range
421         {
422                 bool                                    dstMin  = valueRange.getMin().asBool();
423                 bool                                    dstMax  = valueRange.getMax().asBool();
424                 ValueRangeAccess                a               = this->m_leftValueRange.asAccess();
425                 ValueRangeAccess                b               = this->m_rightValueRange.asAccess();
426
427                 if (inBaseType == VariableType::TYPE_FLOAT)
428                         ComputeValueRange()(state.getRandom(), dstMin, dstMax,
429                                                                 a.getMin().asFloat(), a.getMax().asFloat(),
430                                                                 b.getMin().asFloat(), b.getMax().asFloat());
431                 else if (inBaseType == VariableType::TYPE_INT)
432                         ComputeValueRange()(state.getRandom(), dstMin, dstMax,
433                                                                 a.getMin().asInt(), a.getMax().asInt(),
434                                                                 b.getMin().asInt(), b.getMax().asInt());
435         }
436 }
437
438 template <class ComputeValueRange, class EvaluateComp>
439 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void)
440 {
441 }
442
443 template <class ComputeValueRange, class EvaluateComp>
444 void RelationalOp<ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
445 {
446         DE_ASSERT(a.getType() == b.getType());
447         switch (a.getType().getBaseType())
448         {
449                 case VariableType::TYPE_FLOAT:
450                         for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
451                                 dst.asBool(compNdx) = EvaluateComp()(a.asFloat(compNdx), b.asFloat(compNdx));
452                         break;
453
454                 case VariableType::TYPE_INT:
455                         for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
456                                 dst.asBool(compNdx) = EvaluateComp()(a.asInt(compNdx), b.asInt(compNdx));
457                         break;
458
459                 default:
460                         DE_ASSERT(DE_FALSE);
461         }
462 }
463
464 template <class ComputeValueRange, class EvaluateComp>
465 float RelationalOp<ComputeValueRange, EvaluateComp>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
466 {
467         if (!state.getProgramParameters().useComparisonOps)
468                 return 0.0f;
469
470         if (valueRange.getType().isVoid() ||
471                 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
472                 return BinaryOp<7, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
473         else
474                 return 0.0f;
475 }
476
477 namespace
478 {
479
480 template <typename T>   T               getStep (void);
481 template <> inline              float   getStep (void) { return 0.25f;  }
482 template <> inline              int             getStep (void) { return 1;              }
483
484 } // anonymous
485
486 template <typename T>
487 void ComputeLessThanRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
488 {
489         struct GetRandom
490         {
491                 int             operator() (de::Random& random, int min, int max) const         { return random.getInt(min, max); }
492                 float   operator() (de::Random& random, float min, float max) const     { return getQuantizedFloat(random, min, max, getStep<float>()); }
493         };
494
495         // One random range
496         T       rLen    = GetRandom()(rnd, T(0), T(8));
497         T       rMin    = GetRandom()(rnd, T(-4), T(4));
498         T       rMax    = rMin+rLen;
499
500         if (dstMin == false && dstMax == true)
501         {
502                 // Both values are possible, use same range for both inputs
503                 aMin    = rMin;
504                 aMax    = rMax;
505                 bMin    = rMin;
506                 bMax    = rMax;
507         }
508         else if (dstMin == true && dstMax == true)
509         {
510                 // Compute range that is less than rMin..rMax
511                 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
512
513                 aMax    = rMin - getStep<T>();
514                 aMin    = aMax - aLen;
515
516                 bMin    = rMin;
517                 bMax    = rMax;
518         }
519         else
520         {
521                 // Compute range that is greater than or equal to rMin..rMax
522                 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
523
524                 aMin    = rMax;
525                 aMax    = aMin + aLen;
526
527                 bMin    = rMin;
528                 bMax    = rMax;
529         }
530 }
531
532 LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
533         : LessThanBase(state, Token::CMP_LT, valueRange)
534 {
535 }
536
537 float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
538 {
539         return LessThanBase::getWeight(state, valueRange);
540 }
541
542 template <typename T>
543 void ComputeLessOrEqualRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
544 {
545         struct GetRandom
546         {
547                 int             operator() (de::Random& random, int min, int max) const         { return random.getInt(min, max); }
548                 float   operator() (de::Random& random, float min, float max) const     { return getQuantizedFloat(random, min, max, getStep<float>()); }
549         };
550
551         // One random range
552         T       rLen    = GetRandom()(rnd, T(0), T(8));
553         T       rMin    = GetRandom()(rnd, T(-4), T(4));
554         T       rMax    = rMin+rLen;
555
556         if (dstMin == false && dstMax == true)
557         {
558                 // Both values are possible, use same range for both inputs
559                 aMin    = rMin;
560                 aMax    = rMax;
561                 bMin    = rMin;
562                 bMax    = rMax;
563         }
564         else if (dstMin == true && dstMax == true)
565         {
566                 // Compute range that is less than or equal to rMin..rMax
567                 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
568
569                 aMax    = rMin;
570                 aMin    = aMax - aLen;
571
572                 bMin    = rMin;
573                 bMax    = rMax;
574         }
575         else
576         {
577                 // Compute range that is greater than rMin..rMax
578                 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
579
580                 aMin    = rMax + getStep<T>();
581                 aMax    = aMin + aLen;
582
583                 bMin    = rMin;
584                 bMax    = rMax;
585         }
586 }
587
588 LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
589         : LessOrEqualBase(state, Token::CMP_LE, valueRange)
590 {
591 }
592
593 float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
594 {
595         return LessOrEqualBase::getWeight(state, valueRange);
596 }
597
598 GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
599         : GreaterThanBase(state, Token::CMP_GT, valueRange)
600 {
601 }
602
603 float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
604 {
605         return GreaterThanBase::getWeight(state, valueRange);
606 }
607
608 GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
609         : GreaterOrEqualBase(state, Token::CMP_GE, valueRange)
610 {
611 }
612
613 float GreaterOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
614 {
615         return GreaterOrEqualBase::getWeight(state, valueRange);
616 }
617
618 namespace
619 {
620
621 template <bool IsEqual, typename T>
622 void computeEqualityValueRange (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax)
623 {
624         if (dstMin == false && dstMax == true)
625                 ComputeLessThanRange()(rnd, false, true, aMin, aMax, bMin, bMax);
626         else if (IsEqual && dstMin == false)
627                 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
628         else if (!IsEqual && dstMin == true)
629                 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
630         else
631         {
632                 // Must have exactly same values.
633                 struct GetRandom
634                 {
635                         int             operator() (de::Random& random, int min, int max) const         { return random.getInt(min, max); }
636                         float   operator() (de::Random& random, float min, float max) const     { return getQuantizedFloat(random, min, max, 0.5f); }
637                 };
638
639                 T val = GetRandom()(rnd, T(-1), T(1));
640
641                 aMin    = val;
642                 aMax    = val;
643                 bMin    = val;
644                 bMax    = val;
645         }
646 }
647
648 template <>
649 void computeEqualityValueRange<true, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax)
650 {
651         if (dstMin == false && dstMax == true)
652         {
653                 aMin    = false;
654                 aMax    = true;
655                 bMin    = false;
656                 bMax    = true;
657         }
658         else if (dstMin == false)
659         {
660                 DE_ASSERT(dstMax == false);
661                 bool val = rnd.getBool();
662
663                 aMin    = val;
664                 aMax    = val;
665                 bMin    = !val;
666                 bMax    = !val;
667         }
668         else
669         {
670                 DE_ASSERT(dstMin == true && dstMax == true);
671                 bool val = rnd.getBool();
672
673                 aMin    = val;
674                 aMax    = val;
675                 bMin    = val;
676                 bMax    = val;
677         }
678 }
679
680 template <>
681 void computeEqualityValueRange<false, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax)
682 {
683         if (dstMin == false && dstMax == true)
684                 computeEqualityValueRange<true>(rnd, dstMin, dstMax, aMin, aMax, bMin, bMax);
685         else
686                 computeEqualityValueRange<true>(rnd, !dstMin, !dstMax, aMin, aMax, bMin, bMax);
687 }
688
689 } // anonymous
690
691 template <bool IsEqual>
692 EqualityComparisonOp<IsEqual>::EqualityComparisonOp (GeneratorState& state, ConstValueRangeAccess inValueRange)
693         : BinaryOp<8, ASSOCIATIVITY_LEFT>(IsEqual ? Token::CMP_EQ : Token::CMP_NE)
694 {
695         ValueRange valueRange = inValueRange;
696
697         if (valueRange.getType().isVoid())
698         {
699                 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
700                 computeRandomValueRange(state, valueRange.asAccess());
701         }
702
703         // Choose type, allocate storage for execution
704         this->m_type = valueRange.getType();
705         this->m_value.setStorage(this->m_type);
706
707         // Choose random input type
708         VariableType::Type inBaseTypes[]        = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT };
709         VariableType::Type inBaseType           = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
710         int                                     availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
711         int                                     numElements             = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
712
713         // Initialize storage for input value ranges
714         this->m_rightValueRange = ValueRange(VariableType(inBaseType, numElements));
715         this->m_leftValueRange  = ValueRange(VariableType(inBaseType, numElements));
716
717         // Compute range for b that satisfies requested value range
718         for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
719         {
720                 bool                                    dstMin  = valueRange.getMin().asBool();
721                 bool                                    dstMax  = valueRange.getMax().asBool();
722
723                 ValueRangeAccess                a               = this->m_leftValueRange.asAccess().component(elementNdx);
724                 ValueRangeAccess                b               = this->m_rightValueRange.asAccess().component(elementNdx);
725
726                 if (inBaseType == VariableType::TYPE_FLOAT)
727                         computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
728                                                                                            a.getMin().asFloat(), a.getMax().asFloat(),
729                                                                                            b.getMin().asFloat(), b.getMax().asFloat());
730                 else if (inBaseType == VariableType::TYPE_INT)
731                         computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
732                                                                                            a.getMin().asInt(), a.getMax().asInt(),
733                                                                                            b.getMin().asInt(), b.getMax().asInt());
734                 else
735                 {
736                         DE_ASSERT(inBaseType == VariableType::TYPE_BOOL);
737                         computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
738                                                                                            a.getMin().asBool(), a.getMax().asBool(),
739                                                                                            b.getMin().asBool(), b.getMax().asBool());
740                 }
741         }
742 }
743
744 template <bool IsEqual>
745 float EqualityComparisonOp<IsEqual>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
746 {
747         if (!state.getProgramParameters().useComparisonOps)
748                 return 0.0f;
749
750         // \todo [2011-06-13 pyry] Weight down cases that would force constant inputs.
751
752         if (valueRange.getType().isVoid() ||
753                 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
754                 return BinaryOp<8, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
755         else
756                 return 0.0f;
757 }
758
759 namespace
760 {
761
762 template <bool IsEqual>
763 struct EqualityCompare
764 {
765         template <typename T>
766         static bool compare (T a, T b);
767         static bool combine (bool a, bool b);
768 };
769
770 template <>
771 template <typename T>
772 inline bool EqualityCompare<true>::compare      (T a, T b)                      { return a == b; }
773
774 template <>
775 inline bool EqualityCompare<true>::combine      (bool a, bool b)        { return a && b; }
776
777 template <>
778 template <typename T>
779 inline bool EqualityCompare<false>::compare     (T a, T b)                      { return a != b; }
780
781 template <>
782 inline bool EqualityCompare<false>::combine     (bool a, bool b)        { return a || b; }
783
784 } // anonymous
785
786 template <bool IsEqual>
787 void EqualityComparisonOp<IsEqual>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
788 {
789         DE_ASSERT(a.getType() == b.getType());
790
791
792         switch (a.getType().getBaseType())
793         {
794                 case VariableType::TYPE_FLOAT:
795                         for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
796                         {
797                                 bool result = IsEqual ? true : false;
798
799                                 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
800                                         result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx)));
801
802                                 dst.asBool(compNdx) = result;
803                         }
804                         break;
805
806                 case VariableType::TYPE_INT:
807                         for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
808                         {
809                                 bool result = IsEqual ? true : false;
810
811                                 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
812                                         result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx)));
813
814                                 dst.asBool(compNdx) = result;
815                         }
816                         break;
817
818                 case VariableType::TYPE_BOOL:
819                         for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
820                         {
821                                 bool result = IsEqual ? true : false;
822
823                                 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
824                                         result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asBool(compNdx), b.component(elemNdx).asBool(compNdx)));
825
826                                 dst.asBool(compNdx) = result;
827                         }
828                         break;
829
830                 default:
831                         DE_ASSERT(DE_FALSE);
832         }
833 }
834
835 EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
836         : EqualityComparisonOp<true>(state, valueRange)
837 {
838 }
839
840 float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
841 {
842         return EqualityComparisonOp<true>::getWeight(state, valueRange);
843 }
844
845 NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
846         : EqualityComparisonOp<false>(state, valueRange)
847 {
848 }
849
850 float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
851 {
852         return EqualityComparisonOp<false>::getWeight(state, valueRange);
853 }
854
855 } // rsg