Relax fma() verification in builtin_functions.common.fma
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fShaderCommonFunctionTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Common built-in function tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fShaderCommonFunctionTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "glsShaderExecUtil.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuFormatUtil.hpp"
29 #include "tcuFloat.hpp"
30 #include "tcuInterval.hpp"
31 #include "tcuFloatFormat.hpp"
32 #include "deRandom.hpp"
33 #include "deMath.h"
34 #include "deString.h"
35
36 namespace deqp
37 {
38 namespace gles31
39 {
40 namespace Functional
41 {
42
43 using std::vector;
44 using std::string;
45 using tcu::TestLog;
46 using namespace gls::ShaderExecUtil;
47
48 using tcu::Vec2;
49 using tcu::Vec3;
50 using tcu::Vec4;
51 using tcu::IVec2;
52 using tcu::IVec3;
53 using tcu::IVec4;
54
55 // Utilities
56
57 template<typename T, int Size>
58 struct VecArrayAccess
59 {
60 public:
61                                                                         VecArrayAccess  (const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
62                                                                         ~VecArrayAccess (void) {}
63
64         const tcu::Vector<T, Size>&             operator[]              (size_t offset) const   { return m_array[offset];       }
65         tcu::Vector<T, Size>&                   operator[]              (size_t offset)                 { return m_array[offset];       }
66
67 private:
68         tcu::Vector<T, Size>*                   m_array;
69 };
70
71 template<typename T>    T                       randomScalar    (de::Random& rnd, T minValue, T maxValue);
72 template<> inline               float           randomScalar    (de::Random& rnd, float minValue, float maxValue)               { return rnd.getFloat(minValue, maxValue);      }
73 template<> inline               deInt32         randomScalar    (de::Random& rnd, deInt32 minValue, deInt32 maxValue)   { return rnd.getInt(minValue, maxValue);        }
74 template<> inline               deUint32        randomScalar    (de::Random& rnd, deUint32 minValue, deUint32 maxValue) { return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
75
76 template<typename T, int Size>
77 inline tcu::Vector<T, Size> randomVector (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue)
78 {
79         tcu::Vector<T, Size> res;
80         for (int ndx = 0; ndx < Size; ndx++)
81                 res[ndx] = randomScalar<T>(rnd, minValue[ndx], maxValue[ndx]);
82         return res;
83 }
84
85 template<typename T, int Size>
86 static void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0)
87 {
88         VecArrayAccess<T, Size> access(dst);
89         for (int ndx = 0; ndx < numValues; ndx++)
90                 access[offset + ndx] = randomVector<T, Size>(rnd, minValue, maxValue);
91 }
92
93 template<typename T>
94 static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
95 {
96         T* typedPtr = (T*)dst;
97         for (int ndx = 0; ndx < numValues; ndx++)
98                 typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
99 }
100
101 inline int numBitsLostInOp (float input, float output)
102 {
103         const int       inExp           = tcu::Float32(input).exponent();
104         const int       outExp          = tcu::Float32(output).exponent();
105
106         return de::max(0, inExp-outExp); // Lost due to mantissa shift.
107 }
108
109 inline deUint32 getUlpDiff (float a, float b)
110 {
111         const deUint32  aBits   = tcu::Float32(a).bits();
112         const deUint32  bBits   = tcu::Float32(b).bits();
113         return aBits > bBits ? aBits - bBits : bBits - aBits;
114 }
115
116 inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
117 {
118         if (tcu::Float32(a).isZero())
119                 return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
120         else if (tcu::Float32(b).isZero())
121                 return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
122         else
123                 return getUlpDiff(a, b);
124 }
125
126 inline bool supportsSignedZero (glu::Precision precision)
127 {
128         // \note GLSL ES 3.1 doesn't really require support for -0, but we require it for highp
129         //               as it is very widely supported.
130         return precision == glu::PRECISION_HIGHP;
131 }
132
133 inline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff)
134 {
135         const int exp = tcu::Float32(value).exponent();
136         return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
137 }
138
139 inline deUint32 getMaxUlpDiffFromBits (int numAccurateBits)
140 {
141         const int               numGarbageBits  = 23-numAccurateBits;
142         const deUint32  mask                    = (1u<<numGarbageBits)-1u;
143
144         return mask;
145 }
146
147 inline float getEpsFromBits (float value, int numAccurateBits)
148 {
149         return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
150 }
151
152 static int getMinMantissaBits (glu::Precision precision)
153 {
154         const int bits[] =
155         {
156                 7,              // lowp
157                 10,             // mediump
158                 23              // highp
159         };
160         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
161         DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
162         return bits[precision];
163 }
164
165 static int getMaxNormalizedValueExponent (glu::Precision precision)
166 {
167         const int exponent[] =
168         {
169                 0,              // lowp
170                 13,             // mediump
171                 127             // highp
172         };
173         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
174         DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
175         return exponent[precision];
176 }
177
178 static int getMinNormalizedValueExponent (glu::Precision precision)
179 {
180         const int exponent[] =
181         {
182                 -7,             // lowp
183                 -13,    // mediump
184                 -126    // highp
185         };
186         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
187         DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
188         return exponent[precision];
189 }
190
191 // CommonFunctionCase
192
193 class CommonFunctionCase : public TestCase
194 {
195 public:
196                                                         CommonFunctionCase              (Context& context, const char* name, const char* description, glu::ShaderType shaderType);
197                                                         ~CommonFunctionCase             (void);
198
199         void                                    init                                    (void);
200         void                                    deinit                                  (void);
201         IterateResult                   iterate                                 (void);
202
203 protected:
204                                                         CommonFunctionCase              (const CommonFunctionCase& other);
205         CommonFunctionCase&             operator=                               (const CommonFunctionCase& other);
206
207         virtual void                    getInputValues                  (int numValues, void* const* values) const = 0;
208         virtual bool                    compare                                 (const void* const* inputs, const void* const* outputs) = 0;
209
210         glu::ShaderType                 m_shaderType;
211         ShaderSpec                              m_spec;
212         int                                             m_numValues;
213
214         std::ostringstream              m_failMsg;                              //!< Comparison failure help message.
215
216 private:
217         ShaderExecutor*                 m_executor;
218 };
219
220 CommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
221         : TestCase              (context, name, description)
222         , m_shaderType  (shaderType)
223         , m_numValues   (100)
224         , m_executor    (DE_NULL)
225 {
226         m_spec.version = glu::GLSL_VERSION_310_ES;
227 }
228
229 CommonFunctionCase::~CommonFunctionCase (void)
230 {
231         CommonFunctionCase::deinit();
232 }
233
234 void CommonFunctionCase::init (void)
235 {
236         DE_ASSERT(!m_executor);
237
238         m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
239         m_testCtx.getLog() << m_executor;
240
241         if (!m_executor->isOk())
242                 throw tcu::TestError("Compile failed");
243 }
244
245 void CommonFunctionCase::deinit (void)
246 {
247         delete m_executor;
248         m_executor = DE_NULL;
249 }
250
251 static vector<int> getScalarSizes (const vector<Symbol>& symbols)
252 {
253         vector<int> sizes(symbols.size());
254         for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
255                 sizes[ndx] = symbols[ndx].varType.getScalarSize();
256         return sizes;
257 }
258
259 static int computeTotalScalarSize (const vector<Symbol>& symbols)
260 {
261         int totalSize = 0;
262         for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
263                 totalSize += sym->varType.getScalarSize();
264         return totalSize;
265 }
266
267 static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
268 {
269         vector<void*>   pointers                (symbols.size());
270         int                             curScalarOffset = 0;
271
272         for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
273         {
274                 const Symbol&   var                             = symbols[varNdx];
275                 const int               scalarSize              = var.varType.getScalarSize();
276
277                 // Uses planar layout as input/output specs do not support strides.
278                 pointers[varNdx] = &data[curScalarOffset];
279                 curScalarOffset += scalarSize*numValues;
280         }
281
282         DE_ASSERT(curScalarOffset == (int)data.size());
283
284         return pointers;
285 }
286
287 // \todo [2013-08-08 pyry] Make generic utility and move to glu?
288
289 struct HexFloat
290 {
291         const float value;
292         HexFloat (const float value_) : value(value_) {}
293 };
294
295 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
296 {
297         return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
298 }
299
300 struct HexBool
301 {
302         const deUint32 value;
303         HexBool (const deUint32 value_) : value(value_) {}
304 };
305
306 std::ostream& operator<< (std::ostream& str, const HexBool& v)
307 {
308         return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
309 }
310
311 struct VarValue
312 {
313         const glu::VarType&     type;
314         const void*                     value;
315
316         VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
317 };
318
319 std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
320 {
321         DE_ASSERT(varValue.type.isBasicType());
322
323         const glu::DataType             basicType               = varValue.type.getBasicType();
324         const glu::DataType             scalarType              = glu::getDataTypeScalarType(basicType);
325         const int                               numComponents   = glu::getDataTypeScalarSize(basicType);
326
327         if (numComponents > 1)
328                 str << glu::getDataTypeName(basicType) << "(";
329
330         for (int compNdx = 0; compNdx < numComponents; compNdx++)
331         {
332                 if (compNdx != 0)
333                         str << ", ";
334
335                 switch (scalarType)
336                 {
337                         case glu::TYPE_FLOAT:   str << HexFloat(((const float*)varValue.value)[compNdx]);                       break;
338                         case glu::TYPE_INT:             str << ((const deInt32*)varValue.value)[compNdx];                                       break;
339                         case glu::TYPE_UINT:    str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);          break;
340                         case glu::TYPE_BOOL:    str << HexBool(((const deUint32*)varValue.value)[compNdx]);                     break;
341
342                         default:
343                                 DE_ASSERT(false);
344                 }
345         }
346
347         if (numComponents > 1)
348                 str << ")";
349
350         return str;
351 }
352
353 CommonFunctionCase::IterateResult CommonFunctionCase::iterate (void)
354 {
355         const int                               numInputScalars                 = computeTotalScalarSize(m_spec.inputs);
356         const int                               numOutputScalars                = computeTotalScalarSize(m_spec.outputs);
357         vector<deUint32>                inputData                               (numInputScalars * m_numValues);
358         vector<deUint32>                outputData                              (numOutputScalars * m_numValues);
359         const vector<void*>             inputPointers                   = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
360         const vector<void*>             outputPointers                  = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
361
362         // Initialize input data.
363         getInputValues(m_numValues, &inputPointers[0]);
364
365         // Execute shader.
366         m_executor->useProgram();
367         m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
368
369         // Compare results.
370         {
371                 const vector<int>               inScalarSizes           = getScalarSizes(m_spec.inputs);
372                 const vector<int>               outScalarSizes          = getScalarSizes(m_spec.outputs);
373                 vector<void*>                   curInputPtr                     (inputPointers.size());
374                 vector<void*>                   curOutputPtr            (outputPointers.size());
375                 int                                             numFailed                       = 0;
376
377                 for (int valNdx = 0; valNdx < m_numValues; valNdx++)
378                 {
379                         // Set up pointers for comparison.
380                         for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
381                                 curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
382
383                         for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
384                                 curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
385
386                         if (!compare(&curInputPtr[0], &curOutputPtr[0]))
387                         {
388                                 // \todo [2013-08-08 pyry] We probably want to log reference value as well?
389
390                                 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
391
392                                 m_testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
393                                 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
394                                         m_testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
395                                                                                                                    << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
396                                                                            << TestLog::EndMessage;
397
398                                 m_testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
399                                 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
400                                         m_testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
401                                                                                                                    << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
402                                                                            << TestLog::EndMessage;
403
404                                 m_failMsg.str("");
405                                 m_failMsg.clear();
406                                 numFailed += 1;
407                         }
408                 }
409
410                 m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
411
412                 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
413                                                                 numFailed == 0 ? "Pass"                                 : "Result comparison failed");
414         }
415
416         return STOP;
417 }
418
419 static const char* getPrecisionPostfix (glu::Precision precision)
420 {
421         static const char* s_postfix[] =
422         {
423                 "_lowp",
424                 "_mediump",
425                 "_highp"
426         };
427         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
428         DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
429         return s_postfix[precision];
430 }
431
432 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
433 {
434         static const char* s_postfix[] =
435         {
436                 "_vertex",
437                 "_fragment",
438                 "_geometry",
439                 "_tess_control",
440                 "_tess_eval",
441                 "_compute"
442         };
443         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
444         return s_postfix[shaderType];
445 }
446
447 static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
448 {
449         return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
450 }
451
452 class AbsCase : public CommonFunctionCase
453 {
454 public:
455         AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
456                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
457         {
458                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
459                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
460                 m_spec.source = "out0 = abs(in0);";
461         }
462
463         void getInputValues (int numValues, void* const* values) const
464         {
465                 const Vec2 floatRanges[] =
466                 {
467                         Vec2(-2.0f,             2.0f),  // lowp
468                         Vec2(-1e3f,             1e3f),  // mediump
469                         Vec2(-1e7f,             1e7f)   // highp
470                 };
471                 const IVec2 intRanges[] =
472                 {
473                         IVec2(-(1<<7)+1,        (1<<7)-1),
474                         IVec2(-(1<<15)+1,       (1<<15)-1),
475                         IVec2(0x80000001,       0x7fffffff)
476                 };
477
478                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x235facu);
479                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
480                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
481                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
482
483                 if (glu::isDataTypeFloatOrVec(type))
484                         fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize);
485                 else
486                         fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
487         }
488
489         bool compare (const void* const* inputs, const void* const* outputs)
490         {
491                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
492                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
493                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
494
495                 if (glu::isDataTypeFloatOrVec(type))
496                 {
497                         const int               mantissaBits    = getMinMantissaBits(precision);
498                         const deUint32  maxUlpDiff              = (1u<<(23-mantissaBits))-1u;
499
500                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
501                         {
502                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
503                                 const float             out0            = ((const float*)outputs[0])[compNdx];
504                                 const float             ref0            = de::abs(in0);
505                                 const deUint32  ulpDiff0        = getUlpDiff(out0, ref0);
506
507                                 if (ulpDiff0 > maxUlpDiff)
508                                 {
509                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
510                                         return false;
511                                 }
512                         }
513                 }
514                 else
515                 {
516                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
517                         {
518                                 const int       in0             = ((const int*)inputs[0])[compNdx];
519                                 const int       out0    = ((const int*)outputs[0])[compNdx];
520                                 const int       ref0    = de::abs(in0);
521
522                                 if (out0 != ref0)
523                                 {
524                                         m_failMsg << "Expected [" << compNdx << "] = " << ref0;
525                                         return false;
526                                 }
527                         }
528                 }
529
530                 return true;
531         }
532 };
533
534 class SignCase : public CommonFunctionCase
535 {
536 public:
537         SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
538                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType)
539         {
540                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
541                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
542                 m_spec.source = "out0 = sign(in0);";
543         }
544
545         void getInputValues (int numValues, void* const* values) const
546         {
547                 const Vec2 floatRanges[] =
548                 {
549                         Vec2(-2.0f,             2.0f),  // lowp
550                         Vec2(-1e4f,             1e4f),  // mediump      - note: may end up as inf
551                         Vec2(-1e8f,             1e8f)   // highp        - note: may end up as inf
552                 };
553                 const IVec2 intRanges[] =
554                 {
555                         IVec2(-(1<<7),          (1<<7)-1),
556                         IVec2(-(1<<15),         (1<<15)-1),
557                         IVec2(0x80000000,       0x7fffffff)
558                 };
559
560                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x324u);
561                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
562                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
563                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
564
565                 if (glu::isDataTypeFloatOrVec(type))
566                 {
567                         // Special cases.
568                         std::fill((float*)values[0], (float*)values[0] + scalarSize, +1.0f);
569                         std::fill((float*)values[0], (float*)values[0] + scalarSize, -1.0f);
570                         std::fill((float*)values[0], (float*)values[0] + scalarSize,  0.0f);
571                         fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
572                 }
573                 else
574                 {
575                         std::fill((int*)values[0], (int*)values[0] + scalarSize, +1);
576                         std::fill((int*)values[0], (int*)values[0] + scalarSize, -1);
577                         std::fill((int*)values[0], (int*)values[0] + scalarSize,  0);
578                         fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
579                 }
580         }
581
582         bool compare (const void* const* inputs, const void* const* outputs)
583         {
584                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
585                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
586                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
587
588                 if (glu::isDataTypeFloatOrVec(type))
589                 {
590                         // Both highp and mediump should be able to represent -1, 0, and +1 exactly
591                         const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
592
593                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
594                         {
595                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
596                                 const float             out0            = ((const float*)outputs[0])[compNdx];
597                                 const float             ref0            = in0 < 0.0f ? -1.0f :
598                                                                                           in0 > 0.0f ? +1.0f : 0.0f;
599                                 const deUint32  ulpDiff0        = getUlpDiff(out0, ref0);
600
601                                 if (ulpDiff0 > maxUlpDiff)
602                                 {
603                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
604                                         return false;
605                                 }
606                         }
607                 }
608                 else
609                 {
610                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
611                         {
612                                 const int       in0             = ((const int*)inputs[0])[compNdx];
613                                 const int       out0    = ((const int*)outputs[0])[compNdx];
614                                 const int       ref0    = in0 < 0 ? -1 :
615                                                                           in0 > 0 ? +1 : 0;
616
617                                 if (out0 != ref0)
618                                 {
619                                         m_failMsg << "Expected [" << compNdx << "] = " << ref0;
620                                         return false;
621                                 }
622                         }
623                 }
624
625                 return true;
626         }
627 };
628
629 static float roundEven (float v)
630 {
631         const float             q                       = deFloatFrac(v);
632         const int               truncated       = int(v-q);
633         const int               rounded         = (q > 0.5f)                                                    ? (truncated + 1) :     // Rounded up
634                                                                         (q == 0.5f && (truncated % 2 != 0))     ? (truncated + 1) :     // Round to nearest even at 0.5
635                                                                         truncated;                                                                                              // Rounded down
636
637         return float(rounded);
638 }
639
640 class RoundEvenCase : public CommonFunctionCase
641 {
642 public:
643         RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
644                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType)
645         {
646                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
647                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
648                 m_spec.source = "out0 = roundEven(in0);";
649         }
650
651         void getInputValues (int numValues, void* const* values) const
652         {
653                 const Vec2 ranges[] =
654                 {
655                         Vec2(-2.0f,             2.0f),  // lowp
656                         Vec2(-1e3f,             1e3f),  // mediump
657                         Vec2(-1e7f,             1e7f)   // highp
658                 };
659
660                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
661                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
662                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
663                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
664                 int                                             numSpecialCases = 0;
665
666                 // Special cases.
667                 if (precision != glu::PRECISION_LOWP)
668                 {
669                         DE_ASSERT(numValues >= 20);
670                         for (int ndx = 0; ndx < 20; ndx++)
671                         {
672                                 const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
673                                 std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
674                                 numSpecialCases += 1;
675                         }
676                 }
677
678                 // Random cases.
679                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
680
681                 // If precision is mediump, make sure values can be represented in fp16 exactly
682                 if (precision == glu::PRECISION_MEDIUMP)
683                 {
684                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
685                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
686                 }
687         }
688
689         bool compare (const void* const* inputs, const void* const* outputs)
690         {
691                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
692                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
693                 const bool                              hasSignedZero   = supportsSignedZero(precision);
694                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
695
696                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
697                 {
698                         // Require exact rounding result.
699                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
700                         {
701                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
702                                 const float             out0            = ((const float*)outputs[0])[compNdx];
703                                 const float             ref                     = roundEven(in0);
704
705                                 const deUint32  ulpDiff         = hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
706
707                                 if (ulpDiff > 0)
708                                 {
709                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
710                                         return false;
711                                 }
712                         }
713                 }
714                 else
715                 {
716                         const int               mantissaBits    = getMinMantissaBits(precision);
717                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
718                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
719
720                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
721                         {
722                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
723                                 const float             out0            = ((const float*)outputs[0])[compNdx];
724                                 const int               minRes          = int(roundEven(in0-eps));
725                                 const int               maxRes          = int(roundEven(in0+eps));
726                                 bool                    anyOk           = false;
727
728                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
729                                 {
730                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
731
732                                         if (ulpDiff <= maxUlpDiff)
733                                         {
734                                                 anyOk = true;
735                                                 break;
736                                         }
737                                 }
738
739                                 if (!anyOk)
740                                 {
741                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
742                                         return false;
743                                 }
744                         }
745                 }
746
747                 return true;
748         }
749 };
750
751 class ModfCase : public CommonFunctionCase
752 {
753 public:
754         ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
755                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType)
756         {
757                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
758                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
759                 m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
760                 m_spec.source = "out0 = modf(in0, out1);";
761         }
762
763         void getInputValues (int numValues, void* const* values) const
764         {
765                 const Vec2 ranges[] =
766                 {
767                         Vec2(-2.0f,             2.0f),  // lowp
768                         Vec2(-1e3f,             1e3f),  // mediump
769                         Vec2(-1e7f,             1e7f)   // highp
770                 };
771
772                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xac23fu);
773                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
774                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
775                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
776
777                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
778         }
779
780         bool compare (const void* const* inputs, const void* const* outputs)
781         {
782                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
783                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
784                 const bool                              hasZeroSign             = supportsSignedZero(precision);
785                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
786
787                 const int                               mantissaBits    = getMinMantissaBits(precision);
788
789                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
790                 {
791                         const float             in0                     = ((const float*)inputs[0])[compNdx];
792                         const float             out0            = ((const float*)outputs[0])[compNdx];
793                         const float             out1            = ((const float*)outputs[1])[compNdx];
794
795                         const float             refOut1         = float(int(in0));
796                         const float             refOut0         = in0 - refOut1;
797
798                         const int               bitsLost        = precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
799                         const deUint32  maxUlpDiff      = getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
800
801                         const float             resSum          = out0 + out1;
802
803                         const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
804
805                         if (ulpDiff > maxUlpDiff)
806                         {
807                                 m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold "
808                                                         << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
809                                 return false;
810                         }
811                 }
812
813                 return true;
814         }
815 };
816
817 class IsnanCase : public CommonFunctionCase
818 {
819 public:
820         IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
821                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType)
822         {
823                 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
824
825                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
826                 const glu::DataType     boolType        = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
827
828                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
829                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
830                 m_spec.source = "out0 = isnan(in0);";
831         }
832
833         void getInputValues (int numValues, void* const* values) const
834         {
835                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xc2a39fu);
836                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
837                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
838                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
839                 const int                               mantissaBits    = getMinMantissaBits(precision);
840                 const deUint32                  mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
841
842                 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
843                 {
844                         const bool              isNan           = rnd.getFloat() > 0.3f;
845                         const bool              isInf           = !isNan && rnd.getFloat() > 0.4f;
846                         const deUint32  mantissa        = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
847                         const deUint32  exp                     = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
848                         const deUint32  sign            = rnd.getUint32() & 0x1u;
849                         const deUint32  value           = (sign << 31) | (exp << 23) | mantissa;
850
851                         DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
852
853                         ((deUint32*)values[0])[valNdx] = value;
854                 }
855         }
856
857         bool compare (const void* const* inputs, const void* const* outputs)
858         {
859                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
860                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
861                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
862
863                 if (precision == glu::PRECISION_HIGHP)
864                 {
865                         // Only highp is required to support inf/nan
866                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
867                         {
868                                 const float             in0             = ((const float*)inputs[0])[compNdx];
869                                 const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
870                                 const bool              ref             = tcu::Float32(in0).isNaN();
871
872                                 if (out0 != ref)
873                                 {
874                                         m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
875                                         return false;
876                                 }
877                         }
878                 }
879                 else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP)
880                 {
881                         // NaN support is optional, check that inputs that are not NaN don't result in true.
882                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
883                         {
884                                 const float             in0             = ((const float*)inputs[0])[compNdx];
885                                 const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
886                                 const bool              ref             = tcu::Float32(in0).isNaN();
887
888                                 if (!ref && out0)
889                                 {
890                                         m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
891                                         return false;
892                                 }
893                         }
894                 }
895
896                 return true;
897         }
898 };
899
900 class IsinfCase : public CommonFunctionCase
901 {
902 public:
903         IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
904                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType)
905         {
906                 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
907
908                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
909                 const glu::DataType     boolType        = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
910
911                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
912                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
913                 m_spec.source = "out0 = isinf(in0);";
914         }
915
916         void getInputValues (int numValues, void* const* values) const
917         {
918                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xc2a39fu);
919                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
920                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
921                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
922                 const int                               mantissaBits    = getMinMantissaBits(precision);
923                 const deUint32                  mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
924
925                 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
926                 {
927                         const bool              isInf           = rnd.getFloat() > 0.3f;
928                         const bool              isNan           = !isInf && rnd.getFloat() > 0.4f;
929                         const deUint32  mantissa        = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
930                         const deUint32  exp                     = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
931                         const deUint32  sign            = rnd.getUint32() & 0x1u;
932                         const deUint32  value           = (sign << 31) | (exp << 23) | mantissa;
933
934                         DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
935
936                         ((deUint32*)values[0])[valNdx] = value;
937                 }
938         }
939
940         bool compare (const void* const* inputs, const void* const* outputs)
941         {
942                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
943                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
944                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
945
946                 if (precision == glu::PRECISION_HIGHP)
947                 {
948                         // Only highp is required to support inf/nan
949                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
950                         {
951                                 const float             in0             = ((const float*)inputs[0])[compNdx];
952                                 const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
953                                 const bool              ref             = tcu::Float32(in0).isInf();
954
955                                 if (out0 != ref)
956                                 {
957                                         m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
958                                         return false;
959                                 }
960                         }
961                 }
962                 else if (precision == glu::PRECISION_MEDIUMP)
963                 {
964                         // Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
965                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
966                         {
967                                 const float             in0             = ((const float*)inputs[0])[compNdx];
968                                 const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
969                                 const bool              ref             = tcu::Float16(in0).isInf();
970
971                                 if (!ref && out0)
972                                 {
973                                         m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
974                                         return false;
975                                 }
976                         }
977                 }
978                 // else: no verification can be performed
979
980                 return true;
981         }
982 };
983
984 class FloatBitsToUintIntCase : public CommonFunctionCase
985 {
986 public:
987         FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned)
988                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
989         {
990                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
991                 const glu::DataType     intType         = outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
992                                                                                                           : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
993
994                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
995                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
996                 m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
997         }
998
999         void getInputValues (int numValues, void* const* values) const
1000         {
1001                 const Vec2 ranges[] =
1002                 {
1003                         Vec2(-2.0f,             2.0f),  // lowp
1004                         Vec2(-1e3f,             1e3f),  // mediump
1005                         Vec2(-1e7f,             1e7f)   // highp
1006                 };
1007
1008                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x2790au);
1009                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1010                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
1011                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1012
1013                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
1014         }
1015
1016         bool compare (const void* const* inputs, const void* const* outputs)
1017         {
1018                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1019                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1020                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1021
1022                 const int                               mantissaBits    = getMinMantissaBits(precision);
1023                 const int                               maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);
1024
1025                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1026                 {
1027                         const float             in0                     = ((const float*)inputs[0])[compNdx];
1028                         const deUint32  out0            = ((const deUint32*)outputs[0])[compNdx];
1029                         const deUint32  refOut0         = tcu::Float32(in0).bits();
1030                         const int               ulpDiff         = de::abs((int)out0 - (int)refOut0);
1031
1032                         if (ulpDiff > maxUlpDiff)
1033                         {
1034                                 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
1035                                                         << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1036                                 return false;
1037                         }
1038                 }
1039
1040                 return true;
1041         }
1042 };
1043
1044 class FloatBitsToIntCase : public FloatBitsToUintIntCase
1045 {
1046 public:
1047         FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1048                 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, true)
1049         {
1050         }
1051 };
1052
1053 class FloatBitsToUintCase : public FloatBitsToUintIntCase
1054 {
1055 public:
1056         FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1057                 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, false)
1058         {
1059         }
1060 };
1061
1062 class BitsToFloatCase : public CommonFunctionCase
1063 {
1064 public:
1065         BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType)
1066                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
1067         {
1068                 const bool                      inIsSigned      = glu::isDataTypeIntOrIVec(baseType);
1069                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
1070                 const glu::DataType     floatType       = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1071
1072                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1073                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
1074                 m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
1075         }
1076
1077         void getInputValues (int numValues, void* const* values) const
1078         {
1079                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xbbb225u);
1080                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1081                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1082                 const Vec2                              range           (-1e8f, +1e8f);
1083
1084                 // \note Filled as floats.
1085                 fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
1086         }
1087
1088         bool compare (const void* const* inputs, const void* const* outputs)
1089         {
1090                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1091                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1092                 const int                               maxUlpDiff              = 0;
1093
1094                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1095                 {
1096                         const float             in0                     = ((const float*)inputs[0])[compNdx];
1097                         const float             out0            = ((const float*)outputs[0])[compNdx];
1098                         const int               ulpDiff         = de::abs((int)in0 - (int)out0);
1099
1100                         if (ulpDiff > maxUlpDiff)
1101                         {
1102                                 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(in0) << " with ULP threshold "
1103                                                         << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
1104                                 return false;
1105                         }
1106                 }
1107
1108                 return true;
1109         }
1110 };
1111
1112 class FloorCase : public CommonFunctionCase
1113 {
1114 public:
1115         FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1116                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType)
1117         {
1118                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1119                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1120                 m_spec.source = "out0 = floor(in0);";
1121         }
1122
1123         void getInputValues (int numValues, void* const* values) const
1124         {
1125                 const Vec2 ranges[] =
1126                 {
1127                         Vec2(-2.0f,             2.0f),  // lowp
1128                         Vec2(-1e3f,             1e3f),  // mediump
1129                         Vec2(-1e7f,             1e7f)   // highp
1130                 };
1131
1132                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xac23fu);
1133                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1134                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
1135                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1136                 // Random cases.
1137                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1138
1139                 // If precision is mediump, make sure values can be represented in fp16 exactly
1140                 if (precision == glu::PRECISION_MEDIUMP)
1141                 {
1142                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1143                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1144                 }
1145         }
1146
1147         bool compare (const void* const* inputs, const void* const* outputs)
1148         {
1149                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1150                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1151                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1152
1153                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1154                 {
1155                         // Require exact result.
1156                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1157                         {
1158                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1159                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1160                                 const float             ref                     = deFloatFloor(in0);
1161
1162                                 const deUint32  ulpDiff         = getUlpDiff(out0, ref);
1163
1164                                 if (ulpDiff > 0)
1165                                 {
1166                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1167                                         return false;
1168                                 }
1169                         }
1170                 }
1171                 else
1172                 {
1173                         const int               mantissaBits    = getMinMantissaBits(precision);
1174                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1175                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1176
1177                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1178                         {
1179                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1180                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1181                                 const int               minRes          = int(deFloatFloor(in0-eps));
1182                                 const int               maxRes          = int(deFloatFloor(in0+eps));
1183                                 bool                    anyOk           = false;
1184
1185                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1186                                 {
1187                                         const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal));
1188
1189                                         if (ulpDiff <= maxUlpDiff)
1190                                         {
1191                                                 anyOk = true;
1192                                                 break;
1193                                         }
1194                                 }
1195
1196                                 if (!anyOk)
1197                                 {
1198                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1199                                         return false;
1200                                 }
1201                         }
1202                 }
1203
1204                 return true;
1205         }
1206 };
1207
1208 class TruncCase : public CommonFunctionCase
1209 {
1210 public:
1211         TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1212                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType)
1213         {
1214                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1215                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1216                 m_spec.source = "out0 = trunc(in0);";
1217         }
1218
1219         void getInputValues (int numValues, void* const* values) const
1220         {
1221                 const Vec2 ranges[] =
1222                 {
1223                         Vec2(-2.0f,             2.0f),  // lowp
1224                         Vec2(-1e3f,             1e3f),  // mediump
1225                         Vec2(-1e7f,             1e7f)   // highp
1226                 };
1227
1228                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
1229                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1230                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1231                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1232                 const float                             specialCases[]  = { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f };
1233                 const int                               numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases);
1234
1235                 // Special cases
1236                 for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
1237                 {
1238                         for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1239                                 ((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx];
1240                 }
1241
1242                 // Random cases.
1243                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize);
1244
1245                 // If precision is mediump, make sure values can be represented in fp16 exactly
1246                 if (precision == glu::PRECISION_MEDIUMP)
1247                 {
1248                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1249                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1250                 }
1251         }
1252
1253         bool compare (const void* const* inputs, const void* const* outputs)
1254         {
1255                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1256                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1257                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1258
1259                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1260                 {
1261                         // Require exact result.
1262                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1263                         {
1264                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1265                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1266                                 const bool              isNeg           = tcu::Float32(in0).sign() < 0;
1267                                 const float             ref                     = isNeg ? (-float(int(-in0))) : float(int(in0));
1268
1269                                 // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
1270                                 const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, ref);
1271
1272                                 if (ulpDiff > 0)
1273                                 {
1274                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1275                                         return false;
1276                                 }
1277                         }
1278                 }
1279                 else
1280                 {
1281                         const int               mantissaBits    = getMinMantissaBits(precision);
1282                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1283                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1284
1285                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1286                         {
1287                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1288                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1289                                 const int               minRes          = int(in0-eps);
1290                                 const int               maxRes          = int(in0+eps);
1291                                 bool                    anyOk           = false;
1292
1293                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1294                                 {
1295                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1296
1297                                         if (ulpDiff <= maxUlpDiff)
1298                                         {
1299                                                 anyOk = true;
1300                                                 break;
1301                                         }
1302                                 }
1303
1304                                 if (!anyOk)
1305                                 {
1306                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1307                                         return false;
1308                                 }
1309                         }
1310                 }
1311
1312                 return true;
1313         }
1314 };
1315
1316 class RoundCase : public CommonFunctionCase
1317 {
1318 public:
1319         RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1320                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType)
1321         {
1322                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1323                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1324                 m_spec.source = "out0 = round(in0);";
1325         }
1326
1327         void getInputValues (int numValues, void* const* values) const
1328         {
1329                 const Vec2 ranges[] =
1330                 {
1331                         Vec2(-2.0f,             2.0f),  // lowp
1332                         Vec2(-1e3f,             1e3f),  // mediump
1333                         Vec2(-1e7f,             1e7f)   // highp
1334                 };
1335
1336                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
1337                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1338                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1339                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1340                 int                                             numSpecialCases = 0;
1341
1342                 // Special cases.
1343                 if (precision != glu::PRECISION_LOWP)
1344                 {
1345                         DE_ASSERT(numValues >= 10);
1346                         for (int ndx = 0; ndx < 10; ndx++)
1347                         {
1348                                 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1349                                 std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1350                                 numSpecialCases += 1;
1351                         }
1352                 }
1353
1354                 // Random cases.
1355                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1356
1357                 // If precision is mediump, make sure values can be represented in fp16 exactly
1358                 if (precision == glu::PRECISION_MEDIUMP)
1359                 {
1360                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1361                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1362                 }
1363         }
1364
1365         bool compare (const void* const* inputs, const void* const* outputs)
1366         {
1367                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1368                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1369                 const bool                              hasZeroSign             = supportsSignedZero(precision);
1370                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1371
1372                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1373                 {
1374                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1375                         {
1376                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1377                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1378
1379                                 if (deFloatFrac(in0) == 0.5f)
1380                                 {
1381                                         // Allow both ceil(in) and floor(in)
1382                                         const float             ref0            = deFloatFloor(in0);
1383                                         const float             ref1            = deFloatCeil(in0);
1384                                         const deUint32  ulpDiff0        = hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
1385                                         const deUint32  ulpDiff1        = hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
1386
1387                                         if (ulpDiff0 > 0 && ulpDiff1 > 0)
1388                                         {
1389                                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
1390                                                 return false;
1391                                         }
1392                                 }
1393                                 else
1394                                 {
1395                                         // Require exact result
1396                                         const float             ref             = roundEven(in0);
1397                                         const deUint32  ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1398
1399                                         if (ulpDiff > 0)
1400                                         {
1401                                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1402                                                 return false;
1403                                         }
1404                                 }
1405                         }
1406                 }
1407                 else
1408                 {
1409                         const int               mantissaBits    = getMinMantissaBits(precision);
1410                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1411                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1412
1413                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1414                         {
1415                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1416                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1417                                 const int               minRes          = int(roundEven(in0-eps));
1418                                 const int               maxRes          = int(roundEven(in0+eps));
1419                                 bool                    anyOk           = false;
1420
1421                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1422                                 {
1423                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1424
1425                                         if (ulpDiff <= maxUlpDiff)
1426                                         {
1427                                                 anyOk = true;
1428                                                 break;
1429                                         }
1430                                 }
1431
1432                                 if (!anyOk)
1433                                 {
1434                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1435                                         return false;
1436                                 }
1437                         }
1438                 }
1439
1440                 return true;
1441         }
1442 };
1443
1444 class CeilCase : public CommonFunctionCase
1445 {
1446 public:
1447         CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1448                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType)
1449         {
1450                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1451                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1452                 m_spec.source = "out0 = ceil(in0);";
1453         }
1454
1455         void getInputValues (int numValues, void* const* values) const
1456         {
1457                 const Vec2 ranges[] =
1458                 {
1459                         Vec2(-2.0f,             2.0f),  // lowp
1460                         Vec2(-1e3f,             1e3f),  // mediump
1461                         Vec2(-1e7f,             1e7f)   // highp
1462                 };
1463
1464                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xac23fu);
1465                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1466                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
1467                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1468
1469                 // Random cases.
1470                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1471
1472                 // If precision is mediump, make sure values can be represented in fp16 exactly
1473                 if (precision == glu::PRECISION_MEDIUMP)
1474                 {
1475                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1476                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1477                 }
1478         }
1479
1480         bool compare (const void* const* inputs, const void* const* outputs)
1481         {
1482                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1483                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1484                 const bool                              hasZeroSign             = supportsSignedZero(precision);
1485                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1486
1487                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1488                 {
1489                         // Require exact result.
1490                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1491                         {
1492                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1493                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1494                                 const float             ref                     = deFloatCeil(in0);
1495
1496                                 const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1497
1498                                 if (ulpDiff > 0)
1499                                 {
1500                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1501                                         return false;
1502                                 }
1503                         }
1504                 }
1505                 else
1506                 {
1507                         const int               mantissaBits    = getMinMantissaBits(precision);
1508                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1509                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1510
1511                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1512                         {
1513                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1514                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1515                                 const int               minRes          = int(deFloatCeil(in0-eps));
1516                                 const int               maxRes          = int(deFloatCeil(in0+eps));
1517                                 bool                    anyOk           = false;
1518
1519                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1520                                 {
1521                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1522
1523                                         if (ulpDiff <= maxUlpDiff)
1524                                         {
1525                                                 anyOk = true;
1526                                                 break;
1527                                         }
1528                                 }
1529
1530                                 if (!anyOk && de::inRange(0, minRes, maxRes))
1531                                 {
1532                                         // Allow -0 as well.
1533                                         const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
1534                                         anyOk = ((deUint32)ulpDiff <= maxUlpDiff);
1535                                 }
1536
1537                                 if (!anyOk)
1538                                 {
1539                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1540                                         return false;
1541                                 }
1542                         }
1543                 }
1544
1545                 return true;
1546         }
1547 };
1548
1549 class FractCase : public CommonFunctionCase
1550 {
1551 public:
1552         FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1553                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType)
1554         {
1555                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1556                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1557                 m_spec.source = "out0 = fract(in0);";
1558         }
1559
1560         void getInputValues (int numValues, void* const* values) const
1561         {
1562                 const Vec2 ranges[] =
1563                 {
1564                         Vec2(-2.0f,             2.0f),  // lowp
1565                         Vec2(-1e3f,             1e3f),  // mediump
1566                         Vec2(-1e7f,             1e7f)   // highp
1567                 };
1568
1569                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
1570                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1571                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1572                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1573                 int                                             numSpecialCases = 0;
1574
1575                 // Special cases.
1576                 if (precision != glu::PRECISION_LOWP)
1577                 {
1578                         DE_ASSERT(numValues >= 10);
1579                         for (int ndx = 0; ndx < 10; ndx++)
1580                         {
1581                                 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1582                                 std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1583                                 numSpecialCases += 1;
1584                         }
1585                 }
1586
1587                 // Random cases.
1588                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1589
1590                 // If precision is mediump, make sure values can be represented in fp16 exactly
1591                 if (precision == glu::PRECISION_MEDIUMP)
1592                 {
1593                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1594                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1595                 }
1596         }
1597
1598         bool compare (const void* const* inputs, const void* const* outputs)
1599         {
1600                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1601                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1602                 const bool                              hasZeroSign             = supportsSignedZero(precision);
1603                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1604
1605                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1606                 {
1607                         // Require exact result.
1608                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1609                         {
1610                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1611                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1612                                 const float             ref                     = deFloatFrac(in0);
1613
1614                                 const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1615
1616                                 if (ulpDiff > 0)
1617                                 {
1618                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1619                                         return false;
1620                                 }
1621                         }
1622                 }
1623                 else
1624                 {
1625                         const int               mantissaBits    = getMinMantissaBits(precision);
1626                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1627
1628                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1629                         {
1630                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1631                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1632
1633                                 if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps)))
1634                                 {
1635                                         const float             ref                     = deFloatFrac(in0);
1636                                         const int               bitsLost        = numBitsLostInOp(in0, ref);
1637                                         const deUint32  maxUlpDiff      = getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost));     // ULP diff for rounded integer value.
1638                                         const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, ref);
1639
1640                                         if (ulpDiff > maxUlpDiff)
1641                                         {
1642                                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1643                                                 return false;
1644                                         }
1645                                 }
1646                                 else
1647                                 {
1648                                         if (out0 >= 1.0f)
1649                                         {
1650                                                 m_failMsg << "Expected [" << compNdx << "] < 1.0";
1651                                                 return false;
1652                                         }
1653                                 }
1654                         }
1655                 }
1656
1657                 return true;
1658         }
1659 };
1660
1661 static inline void frexp (float in, float* significand, int* exponent)
1662 {
1663         const tcu::Float32 fpValue(in);
1664
1665         if (!fpValue.isZero())
1666         {
1667                 // Construct float that has exactly the mantissa, and exponent of -1.
1668                 *significand    = tcu::Float32::construct(fpValue.sign(), -1, fpValue.mantissa()).asFloat();
1669                 *exponent               = fpValue.exponent()+1;
1670         }
1671         else
1672         {
1673                 *significand    = fpValue.sign() < 0 ? -0.0f : 0.0f;
1674                 *exponent               = 0;
1675         }
1676 }
1677
1678 static inline float ldexp (float significand, int exponent)
1679 {
1680         const tcu::Float32 mant(significand);
1681
1682         if (exponent == 0 && mant.isZero())
1683         {
1684                 return mant.sign() < 0 ? -0.0f : 0.0f;
1685         }
1686         else
1687         {
1688                 return tcu::Float32::construct(mant.sign(), exponent+mant.exponent(), mant.mantissa()).asFloat();
1689         }
1690 }
1691
1692 class FrexpCase : public CommonFunctionCase
1693 {
1694 public:
1695         FrexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1696                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "frexp", shaderType)
1697         {
1698                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
1699                 const glu::DataType     intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1700
1701                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1702                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1703                 m_spec.outputs.push_back(Symbol("out1", glu::VarType(intType, glu::PRECISION_HIGHP)));
1704                 m_spec.source = "out0 = frexp(in0, out1);";
1705         }
1706
1707         void getInputValues (int numValues, void* const* values) const
1708         {
1709                 const Vec2 ranges[] =
1710                 {
1711                         Vec2(-2.0f,             2.0f),  // lowp
1712                         Vec2(-1e3f,             1e3f),  // mediump
1713                         Vec2(-1e7f,             1e7f)   // highp
1714                 };
1715
1716                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x2790au);
1717                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1718                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
1719                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1720
1721                 // Special cases
1722                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1723                 {
1724                         ((float*)values[0])[scalarSize*0 + compNdx] = 0.0f;
1725                         ((float*)values[0])[scalarSize*1 + compNdx] = -0.0f;
1726                         ((float*)values[0])[scalarSize*2 + compNdx] = 0.5f;
1727                         ((float*)values[0])[scalarSize*3 + compNdx] = -0.5f;
1728                         ((float*)values[0])[scalarSize*4 + compNdx] = 1.0f;
1729                         ((float*)values[0])[scalarSize*5 + compNdx] = -1.0f;
1730                         ((float*)values[0])[scalarSize*6 + compNdx] = 2.0f;
1731                         ((float*)values[0])[scalarSize*7 + compNdx] = -2.0f;
1732                 }
1733
1734                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + 8*scalarSize, (numValues-8)*scalarSize);
1735         }
1736
1737         bool compare (const void* const* inputs, const void* const* outputs)
1738         {
1739                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1740                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1741                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1742                 const bool                              signedZero              = supportsSignedZero(precision);
1743
1744                 const int                               mantissaBits    = getMinMantissaBits(precision);
1745                 const deUint32                  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);
1746
1747                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1748                 {
1749                         const float             in0                     = ((const float*)inputs[0])[compNdx];
1750                         const float             out0            = ((const float*)outputs[0])[compNdx];
1751                         const int               out1            = ((const int*)outputs[1])[compNdx];
1752
1753                         float                   refOut0;
1754                         int                             refOut1;
1755
1756                         frexp(in0, &refOut0, &refOut1);
1757
1758                         const deUint32  ulpDiff0        = signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0);
1759
1760                         if (ulpDiff0 > maxUlpDiff || out1 != refOut1)
1761                         {
1762                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", " << refOut1 << " with ULP threshold "
1763                                                   << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff0);
1764                                 return false;
1765                         }
1766                 }
1767
1768                 return true;
1769         }
1770 };
1771
1772 class LdexpCase : public CommonFunctionCase
1773 {
1774 public:
1775         LdexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1776                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ldexp", shaderType)
1777         {
1778                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
1779                 const glu::DataType     intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1780
1781                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1782                 m_spec.inputs.push_back(Symbol("in1", glu::VarType(intType, glu::PRECISION_HIGHP)));
1783                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1784                 m_spec.source = "out0 = ldexp(in0, in1);";
1785         }
1786
1787         void getInputValues (int numValues, void* const* values) const
1788         {
1789                 const Vec2 ranges[] =
1790                 {
1791                         Vec2(-2.0f,             2.0f),  // lowp
1792                         Vec2(-1e3f,             1e3f),  // mediump
1793                         Vec2(-1e7f,             1e7f)   // highp
1794                 };
1795
1796                 de::Random                              rnd                                     (deStringHash(getName()) ^ 0x2790au);
1797                 const glu::DataType             type                            = m_spec.inputs[0].varType.getBasicType();
1798                 const glu::Precision    precision                       = m_spec.inputs[0].varType.getPrecision();
1799                 const int                               scalarSize                      = glu::getDataTypeScalarSize(type);
1800                 int                                             valueNdx                        = 0;
1801
1802                 {
1803                         const float easySpecialCases[] = { 0.0f, -0.0f, 0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f };
1804
1805                         DE_ASSERT(valueNdx + DE_LENGTH_OF_ARRAY(easySpecialCases) <= numValues);
1806                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(easySpecialCases); caseNdx++)
1807                         {
1808                                 float   in0;
1809                                 int             in1;
1810
1811                                 frexp(easySpecialCases[caseNdx], &in0, &in1);
1812
1813                                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1814                                 {
1815                                         ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
1816                                         ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
1817                                 }
1818
1819                                 valueNdx += 1;
1820                         }
1821                 }
1822
1823                 {
1824                         // \note lowp and mediump can not necessarily fit the values in hard cases, so we'll use only easy ones.
1825                         const int numEasyRandomCases = precision == glu::PRECISION_HIGHP ? 50 : (numValues-valueNdx);
1826
1827                         DE_ASSERT(valueNdx + numEasyRandomCases <= numValues);
1828                         for (int caseNdx = 0; caseNdx < numEasyRandomCases; caseNdx++)
1829                         {
1830                                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1831                                 {
1832                                         const float     in      = rnd.getFloat(ranges[precision].x(), ranges[precision].y());
1833                                         float           in0;
1834                                         int                     in1;
1835
1836                                         frexp(in, &in0, &in1);
1837
1838                                         ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
1839                                         ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
1840                                 }
1841
1842                                 valueNdx += 1;
1843                         }
1844                 }
1845
1846                 {
1847                         const int numHardRandomCases = numValues-valueNdx;
1848                         DE_ASSERT(numHardRandomCases >= 0 && valueNdx + numHardRandomCases <= numValues);
1849
1850                         for (int caseNdx = 0; caseNdx < numHardRandomCases; caseNdx++)
1851                         {
1852                                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1853                                 {
1854                                         const int               fpExp           = rnd.getInt(-126, 127);
1855                                         const int               sign            = rnd.getBool() ? -1 : +1;
1856                                         const deUint32  mantissa        = (1u<<23) | (rnd.getUint32() & ((1u<<23)-1));
1857                                         const int               in1                     = rnd.getInt(de::max(-126, -126-fpExp), de::min(127, 127-fpExp));
1858                                         const float             in0                     = tcu::Float32::construct(sign, fpExp, mantissa).asFloat();
1859
1860                                         DE_ASSERT(de::inRange(in1, -126, 127)); // See Khronos bug 11180
1861                                         DE_ASSERT(de::inRange(in1+fpExp, -126, 127));
1862
1863                                         const float             out                     = ldexp(in0, in1);
1864
1865                                         DE_ASSERT(!tcu::Float32(out).isInf() && !tcu::Float32(out).isDenorm());
1866                                         DE_UNREF(out);
1867
1868                                         ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
1869                                         ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
1870                                 }
1871
1872                                 valueNdx += 1;
1873                         }
1874                 }
1875         }
1876
1877         bool compare (const void* const* inputs, const void* const* outputs)
1878         {
1879                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1880                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1881                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1882                 const bool                              signedZero              = supportsSignedZero(precision);
1883
1884                 const int                               mantissaBits    = getMinMantissaBits(precision);
1885                 const deUint32                  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);
1886
1887                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1888                 {
1889                         const float             in0                     = ((const float*)inputs[0])[compNdx];
1890                         const int               in1                     = ((const int*)inputs[1])[compNdx];
1891                         const float             out0            = ((const float*)outputs[0])[compNdx];
1892                         const float             refOut0         = ldexp(in0, in1);
1893                         const deUint32  ulpDiff         = signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0);
1894
1895                         const int               inExp           = tcu::Float32(in0).exponent();
1896
1897                         if (ulpDiff > maxUlpDiff)
1898                         {
1899                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", (exp = " << inExp << ") with ULP threshold "
1900                                                   << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
1901                                 return false;
1902                         }
1903                 }
1904
1905                 return true;
1906         }
1907 };
1908
1909 class FmaCase : public CommonFunctionCase
1910 {
1911 public:
1912         FmaCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1913                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fma", shaderType)
1914         {
1915                 m_spec.inputs.push_back(Symbol("a", glu::VarType(baseType, precision)));
1916                 m_spec.inputs.push_back(Symbol("b", glu::VarType(baseType, precision)));
1917                 m_spec.inputs.push_back(Symbol("c", glu::VarType(baseType, precision)));
1918                 m_spec.outputs.push_back(Symbol("res", glu::VarType(baseType, precision)));
1919                 m_spec.source = "res = fma(a, b, c);";
1920                 m_spec.globalDeclarations = "#extension GL_EXT_gpu_shader5 : require\n";
1921         }
1922
1923         void init (void)
1924         {
1925                 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"))
1926                         throw tcu::NotSupportedError("GL_EXT_gpu_shader5 not supported");
1927
1928                 CommonFunctionCase::init();
1929         }
1930
1931         void getInputValues (int numValues, void* const* values) const
1932         {
1933                 const Vec2 ranges[] =
1934                 {
1935                         Vec2(-2.0f,             2.0f),  // lowp
1936                         Vec2(-127.f,    127.f), // mediump
1937                         Vec2(-1e7f,             1e7f)   // highp
1938                 };
1939
1940                 de::Random                              rnd                                                     (deStringHash(getName()) ^ 0xac23fu);
1941                 const glu::DataType             type                                            = m_spec.inputs[0].varType.getBasicType();
1942                 const glu::Precision    precision                                       = m_spec.inputs[0].varType.getPrecision();
1943                 const int                               scalarSize                                      = glu::getDataTypeScalarSize(type);
1944                 const int                               numMantissaBits                         = getMinMantissaBits(precision);
1945                 const int                               maxNormalizedValueExponent      = getMaxNormalizedValueExponent(precision);
1946                 const int                               minNormalizedValueExponent      = getMinNormalizedValueExponent(precision);
1947                 const deUint32                  representableMantissaMask       = ((deUint32(1) << numMantissaBits) - 1) << (23 - (deUint32)numMantissaBits);
1948                 const float                             specialCases[][3]                       =
1949                 {
1950                         // a            b               c
1951                         { 0.0f,         0.0f,   0.0f },
1952                         { 0.0f,         1.0f,   0.0f },
1953                         { 0.0f,         0.0f,   -1.0f },
1954                         { 1.0f,         1.0f,   0.0f },
1955                         { 1.0f,         1.0f,   1.0f },
1956                         { -1.0f,        1.0f,   0.0f },
1957                         { 1.0f,         -1.0f,  0.0f },
1958                         { -1.0f,        -1.0f,  0.0f },
1959                         { -0.0f,        1.0f,   0.0f },
1960                         { 1.0f,         -0.0f,  0.0f }
1961                 };
1962                 const int                               numSpecialCases                         = DE_LENGTH_OF_ARRAY(specialCases);
1963
1964                 // Special cases
1965                 for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
1966                 {
1967                         for (int inputNdx = 0; inputNdx < 3; inputNdx++)
1968                         {
1969                                 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1970                                         ((float*)values[inputNdx])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx][inputNdx];
1971                         }
1972                 }
1973
1974                 // Random cases.
1975                 {
1976                         const int       numScalars      = (numValues-numSpecialCases)*scalarSize;
1977                         const int       offs            = scalarSize*numSpecialCases;
1978
1979                         for (int inputNdx = 0; inputNdx < 3; inputNdx++)
1980                                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[inputNdx] + offs, numScalars);
1981                 }
1982
1983                 // Make sure the values are representable in the target format
1984                 if (precision != glu::PRECISION_HIGHP)
1985                 {
1986                         const float     largestRepresentableValue       = tcu::Float32::constructBits(+1, maxNormalizedValueExponent, ((1u << numMantissaBits) - 1u) << (23u - (deUint32)numMantissaBits)).asFloat();
1987
1988                         // zero is not required to be representable, use smallest positive non-subnormal value
1989                         const float zeroReplacement                             = tcu::Float32::constructBits(+1, minNormalizedValueExponent, 1).asFloat();
1990
1991                         for (int inputNdx = 0; inputNdx < 3; inputNdx++)
1992                         {
1993                                 for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
1994                                 {
1995                                         for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1996                                         {
1997                                                 float&                          value                                   = ((float*)values[inputNdx])[caseNdx * scalarSize + scalarNdx];
1998                                                 const tcu::Float32      float32Representation   (value);
1999
2000                                                 // flush too small values to zero
2001                                                 if (float32Representation.exponent() < minNormalizedValueExponent)
2002                                                 {
2003                                                         value = zeroReplacement;
2004                                                 }
2005                                                 // clamp too large values
2006                                                 else if (float32Representation.exponent() > maxNormalizedValueExponent)
2007                                                 {
2008                                                         value = (float32Representation.sign() == +1) ? (largestRepresentableValue) : (-largestRepresentableValue);
2009                                                 }
2010                                                 // remove unrepresentable mantissa bits
2011                                                 else
2012                                                 {
2013                                                         const tcu::Float32      targetRepresentation    (tcu::Float32::constructBits(float32Representation.sign(),
2014                                                                                                                                                                                                          float32Representation.exponent(),
2015                                                                                                                                                                                                          float32Representation.mantissaBits() & representableMantissaMask));
2016
2017                                                         value = targetRepresentation.asFloat();
2018                                                 }
2019                                         }
2020                                 }
2021                         }
2022                 }
2023         }
2024
2025         static tcu::Interval fma (glu::Precision precision, float a, float b, float c)
2026         {
2027                 const tcu::FloatFormat formats[] =
2028                 {
2029                         //                               minExp         maxExp          mantissa        exact,          subnormals      infinities      NaN
2030                         tcu::FloatFormat(0,                     0,                      7,                      false,          tcu::YES,       tcu::MAYBE,     tcu::MAYBE),
2031                         tcu::FloatFormat(-13,           13,                     9,                      false,          tcu::MAYBE,     tcu::MAYBE,     tcu::MAYBE),
2032                         tcu::FloatFormat(-126,          127,            23,                     true,           tcu::MAYBE, tcu::YES,   tcu::MAYBE)
2033                 };
2034                 const tcu::FloatFormat& format  = de::getSizedArrayElement<glu::PRECISION_LAST>(formats, precision);
2035                 const tcu::Interval             ia              = format.convert(a);
2036                 const tcu::Interval             ib              = format.convert(b);
2037                 const tcu::Interval             ic              = format.convert(c);
2038                 tcu::Interval                   prod0;
2039                 tcu::Interval                   prod1;
2040                 tcu::Interval                   prod2;
2041                 tcu::Interval                   prod3;
2042                 tcu::Interval                   prod;
2043                 tcu::Interval                   res;
2044
2045                 TCU_SET_INTERVAL(prod0, tmp, tmp = ia.lo() * ib.lo());
2046                 TCU_SET_INTERVAL(prod1, tmp, tmp = ia.lo() * ib.hi());
2047                 TCU_SET_INTERVAL(prod2, tmp, tmp = ia.hi() * ib.lo());
2048                 TCU_SET_INTERVAL(prod3, tmp, tmp = ia.hi() * ib.hi());
2049
2050                 prod = format.convert(format.roundOut(prod0 | prod1 | prod2 | prod3, ia.isFinite() && ib.isFinite()));
2051
2052                 TCU_SET_INTERVAL_BOUNDS(res, tmp,
2053                                                                 tmp = prod.lo() + ic.lo(),
2054                                                                 tmp = prod.hi() + ic.hi());
2055
2056                 return format.convert(format.roundOut(res, prod.isFinite() && ic.isFinite()));
2057         }
2058
2059         bool compare (const void* const* inputs, const void* const* outputs)
2060         {
2061                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
2062                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
2063                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
2064
2065                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
2066                 {
2067                         const float                     a                       = ((const float*)inputs[0])[compNdx];
2068                         const float                     b                       = ((const float*)inputs[1])[compNdx];
2069                         const float                     c                       = ((const float*)inputs[2])[compNdx];
2070                         const float                     res                     = ((const float*)outputs[0])[compNdx];
2071                         const tcu::Interval     ref                     = fma(precision, a, b, c);
2072
2073                         if (!ref.contains(res))
2074                         {
2075                                 m_failMsg << "Expected [" << compNdx << "] = " << ref;
2076                                 return false;
2077                         }
2078                 }
2079
2080                 return true;
2081         }
2082 };
2083
2084 ShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context)
2085         : TestCaseGroup(context, "common", "Common function tests")
2086 {
2087 }
2088
2089 ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
2090 {
2091 }
2092
2093 template<class TestClass>
2094 static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes, deUint32 shaderBits)
2095 {
2096         tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
2097         parent->addChild(group);
2098
2099         const glu::DataType scalarTypes[] =
2100         {
2101                 glu::TYPE_FLOAT,
2102                 glu::TYPE_INT,
2103                 glu::TYPE_UINT
2104         };
2105
2106         for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
2107         {
2108                 const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
2109
2110                 if ((!floatTypes && scalarType == glu::TYPE_FLOAT)      ||
2111                         (!intTypes && scalarType == glu::TYPE_INT)              ||
2112                         (!uintTypes && scalarType == glu::TYPE_UINT))
2113                         continue;
2114
2115                 for (int vecSize = 1; vecSize <= 4; vecSize++)
2116                 {
2117                         for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
2118                         {
2119                                 for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
2120                                 {
2121                                         if (shaderBits & (1<<shaderTypeNdx))
2122                                                 group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
2123                                 }
2124                         }
2125                 }
2126         }
2127 }
2128
2129 void ShaderCommonFunctionTests::init (void)
2130 {
2131         enum
2132         {
2133                 VS = (1<<glu::SHADERTYPE_VERTEX),
2134                 TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
2135                 TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
2136                 GS = (1<<glu::SHADERTYPE_GEOMETRY),
2137                 FS = (1<<glu::SHADERTYPE_FRAGMENT),
2138                 CS = (1<<glu::SHADERTYPE_COMPUTE),
2139
2140                 ALL_SHADERS = VS|TC|TE|GS|FS|CS,
2141                 NEW_SHADERS = TC|TE|GS|CS,
2142         };
2143
2144         //                                                                                                                                      Float?  Int?    Uint?   Shaders
2145         addFunctionCases<AbsCase>                               (this,  "abs",                          true,   true,   false,  NEW_SHADERS);
2146         addFunctionCases<SignCase>                              (this,  "sign",                         true,   true,   false,  NEW_SHADERS);
2147         addFunctionCases<FloorCase>                             (this,  "floor",                        true,   false,  false,  NEW_SHADERS);
2148         addFunctionCases<TruncCase>                             (this,  "trunc",                        true,   false,  false,  NEW_SHADERS);
2149         addFunctionCases<RoundCase>                             (this,  "round",                        true,   false,  false,  NEW_SHADERS);
2150         addFunctionCases<RoundEvenCase>                 (this,  "roundeven",            true,   false,  false,  NEW_SHADERS);
2151         addFunctionCases<CeilCase>                              (this,  "ceil",                         true,   false,  false,  NEW_SHADERS);
2152         addFunctionCases<FractCase>                             (this,  "fract",                        true,   false,  false,  NEW_SHADERS);
2153         // mod
2154         addFunctionCases<ModfCase>                              (this,  "modf",                         true,   false,  false,  NEW_SHADERS);
2155         // min
2156         // max
2157         // clamp
2158         // mix
2159         // step
2160         // smoothstep
2161         addFunctionCases<IsnanCase>                             (this,  "isnan",                        true,   false,  false,  NEW_SHADERS);
2162         addFunctionCases<IsinfCase>                             (this,  "isinf",                        true,   false,  false,  NEW_SHADERS);
2163         addFunctionCases<FloatBitsToIntCase>    (this,  "floatbitstoint",       true,   false,  false,  NEW_SHADERS);
2164         addFunctionCases<FloatBitsToUintCase>   (this,  "floatbitstouint",      true,   false,  false,  NEW_SHADERS);
2165
2166         addFunctionCases<FrexpCase>                             (this,  "frexp",                        true,   false,  false,  ALL_SHADERS);
2167         addFunctionCases<LdexpCase>                             (this,  "ldexp",                        true,   false,  false,  ALL_SHADERS);
2168         addFunctionCases<FmaCase>                               (this,  "fma",                          true,   false,  false,  ALL_SHADERS);
2169
2170         // (u)intBitsToFloat()
2171         {
2172                 const deUint32          shaderBits      = NEW_SHADERS;
2173                 tcu::TestCaseGroup* intGroup    = new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",   "intBitsToFloat() Tests");
2174                 tcu::TestCaseGroup* uintGroup   = new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",  "uintBitsToFloat() Tests");
2175
2176                 addChild(intGroup);
2177                 addChild(uintGroup);
2178
2179                 for (int vecSize = 1; vecSize < 4; vecSize++)
2180                 {
2181                         const glu::DataType             intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
2182                         const glu::DataType             uintType        = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
2183
2184                         for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
2185                         {
2186                                 if (shaderBits & (1<<shaderType))
2187                                 {
2188                                         intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType)));
2189                                         uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType)));
2190                                 }
2191                         }
2192                 }
2193         }
2194 }
2195
2196 } // Functional
2197 } // gles31
2198 } // deqp