1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Integer built-in function tests.
24 *//*--------------------------------------------------------------------*/
25
26#include "vktShaderIntegerFunctionTests.hpp"
27#include "vktShaderExecutor.hpp"
28#include "tcuTestLog.hpp"
29#include "tcuFormatUtil.hpp"
30#include "tcuFloat.hpp"
31#include "deRandom.hpp"
32#include "deMath.h"
33#include "deString.h"
34#include "deInt32.h"
35#include "deSharedPtr.hpp"
36
37#include <iostream>
38
39namespace vkt
40{
41namespace shaderexecutor
42{
43
44using std::vector;
45using std::string;
46using tcu::TestLog;
47
48using tcu::IVec2;
49using tcu::IVec3;
50using tcu::IVec4;
51using tcu::UVec2;
52using tcu::UVec3;
53using tcu::UVec4;
54
55// Utilities
56
57namespace
58{
59
60struct HexFloat
61{
62	const float value;
63	HexFloat (const float value_) : value(value_) {}
64};
65
66std::ostream& operator<< (std::ostream& str, const HexFloat& v)
67{
68	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
69}
70
71struct VarValue
72{
73	const glu::VarType&	type;
74	const void*			value;
75
76	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
77};
78
79std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
80{
81	DE_ASSERT(varValue.type.isBasicType());
82
83	const glu::DataType		basicType		= varValue.type.getBasicType();
84	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
85	const int				numComponents	= glu::getDataTypeScalarSize(basicType);
86
87	if (numComponents > 1)
88		str << glu::getDataTypeName(basicType) << "(";
89
90	for (int compNdx = 0; compNdx < numComponents; compNdx++)
91	{
92		if (compNdx != 0)
93			str << ", ";
94
95		switch (scalarType)
96		{
97			case glu::TYPE_FLOAT:	str << HexFloat(((const float*)varValue.value)[compNdx]);						break;
98			case glu::TYPE_INT:		str << ((const deInt32*)varValue.value)[compNdx];								break;
99			case glu::TYPE_UINT:	str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);					break;
100			case glu::TYPE_BOOL:	str << (((const deUint32*)varValue.value)[compNdx] != 0 ? "true" : "false");	break;
101
102			default:
103				DE_ASSERT(false);
104		}
105	}
106
107	if (numComponents > 1)
108		str << ")";
109
110	return str;
111}
112
113inline int getShaderUintBitCount (glu::ShaderType shaderType, glu::Precision precision)
114{
115	// \todo [2013-10-31 pyry] Query from GL for vertex and fragment shaders.
116	DE_UNREF(shaderType);
117	const int bitCounts[] = { 9, 16, 32 };
118	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bitCounts) == glu::PRECISION_LAST);
119	return bitCounts[precision];
120}
121
122static inline deUint32 extendSignTo32 (deUint32 integer, deUint32 integerLength)
123{
124	DE_ASSERT(integerLength > 0 && integerLength <= 32);
125
126	return deUint32(0 - deInt32((integer & (1 << (integerLength - 1))) << 1)) | integer;
127}
128
129static inline deUint32 getLowBitMask (int integerLength)
130{
131	DE_ASSERT(integerLength >= 0 && integerLength <= 32);
132
133	// \note: shifting more or equal to 32 => undefined behavior. Avoid it by shifting in two parts (1 << (num-1) << 1)
134	if (integerLength == 0u)
135		return 0u;
136	return ((1u << ((deUint32)integerLength - 1u)) << 1u) - 1u;
137}
138
139static void generateRandomInputData (de::Random& rnd, glu::ShaderType shaderType, glu::DataType dataType, glu::Precision precision, deUint32* dst, int numValues)
140{
141	const int				scalarSize		= glu::getDataTypeScalarSize(dataType);
142	const deUint32			integerLength	= (deUint32)getShaderUintBitCount(shaderType, precision);
143	const deUint32			integerMask		= getLowBitMask(integerLength);
144	const bool				isUnsigned		= glu::isDataTypeUintOrUVec(dataType);
145
146	if (isUnsigned)
147	{
148		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
149			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
150				dst[valueNdx*scalarSize + compNdx] = rnd.getUint32() & integerMask;
151	}
152	else
153	{
154		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
155			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
156				dst[valueNdx*scalarSize + compNdx] = extendSignTo32(rnd.getUint32() & integerMask, integerLength);
157	}
158}
159
160static vector<int> getScalarSizes (const vector<Symbol>& symbols)
161{
162	vector<int> sizes(symbols.size());
163	for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
164		sizes[ndx] = symbols[ndx].varType.getScalarSize();
165	return sizes;
166}
167
168static int computeTotalScalarSize (const vector<Symbol>& symbols)
169{
170	int totalSize = 0;
171	for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
172		totalSize += sym->varType.getScalarSize();
173	return totalSize;
174}
175
176static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
177{
178	vector<void*>	pointers		(symbols.size());
179	int				curScalarOffset	= 0;
180
181	for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
182	{
183		const Symbol&	var				= symbols[varNdx];
184		const int		scalarSize		= var.varType.getScalarSize();
185
186		// Uses planar layout as input/output specs do not support strides.
187		pointers[varNdx] = &data[curScalarOffset];
188		curScalarOffset += scalarSize*numValues;
189	}
190
191	DE_ASSERT(curScalarOffset == (int)data.size());
192
193	return pointers;
194}
195
196static const char* getPrecisionPostfix (glu::Precision precision)
197{
198	static const char* s_postfix[] =
199	{
200		"_lowp",
201		"_mediump",
202		"_highp"
203	};
204	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
205	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
206	return s_postfix[precision];
207}
208
209static const char* getShaderTypePostfix (glu::ShaderType shaderType)
210{
211	static const char* s_postfix[] =
212	{
213		"_vertex",
214		"_fragment",
215		"_geometry",
216		"_tess_control",
217		"_tess_eval",
218		"_compute"
219	};
220	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
221	return s_postfix[shaderType];
222}
223
224static std::string getIntegerFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
225{
226	return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
227}
228
229static inline deUint32 reverseBits (deUint32 v)
230{
231	v = (((v & 0xaaaaaaaa) >> 1) | ((v & 0x55555555) << 1));
232	v = (((v & 0xcccccccc) >> 2) | ((v & 0x33333333) << 2));
233	v = (((v & 0xf0f0f0f0) >> 4) | ((v & 0x0f0f0f0f) << 4));
234	v = (((v & 0xff00ff00) >> 8) | ((v & 0x00ff00ff) << 8));
235	return((v >> 16) | (v << 16));
236}
237
238static int findLSB (deUint32 value)
239{
240	for (int i = 0; i < 32; i++)
241	{
242		if (value & (1u<<i))
243			return i;
244	}
245	return -1;
246}
247
248static int findMSB (deInt32 value)
249{
250	if (value > 0)
251		return 31 - deClz32((deUint32)value);
252	else if (value < 0)
253		return 31 - deClz32(~(deUint32)value);
254	else
255		return -1;
256}
257
258static int findMSB (deUint32 value)
259{
260	if (value > 0)
261		return 31 - deClz32(value);
262	else
263		return -1;
264}
265
266static deUint32 toPrecision (deUint32 value, int numIntegerBits)
267{
268	return value & getLowBitMask(numIntegerBits);
269}
270
271static deInt32 toPrecision (deInt32 value, int numIntegerBits)
272{
273	return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
274}
275
276template<class TestClass>
277static void addFunctionCases (tcu::TestCaseGroup* parent, const char* functionName, bool intTypes, bool uintTypes, bool allPrec, deUint32 shaderBits)
278{
279	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
280
281	parent->addChild(group);
282	const glu::DataType scalarTypes[] =
283	{
284		glu::TYPE_INT,
285		glu::TYPE_UINT
286	};
287
288	for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
289	{
290		const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
291
292		if ((!intTypes && scalarType == glu::TYPE_INT) || (!uintTypes && scalarType == glu::TYPE_UINT))
293			continue;
294
295		for (int vecSize = 1; vecSize <= 4; vecSize++)
296		{
297			for (int prec = glu::PRECISION_MEDIUMP; prec <= glu::PRECISION_HIGHP; prec++)
298			{
299				if (prec != glu::PRECISION_HIGHP && !allPrec)
300					continue;
301
302				for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
303				{
304					if (shaderBits & (1<<shaderTypeNdx))
305						group->addChild(new TestClass(parent->getTestContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
306				}
307			}
308		}
309	}
310}
311
312} // anonymous
313
314// IntegerFunctionCase
315
316class IntegerFunctionCase : public TestCase
317{
318public:
319										IntegerFunctionCase		(tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
320										~IntegerFunctionCase	(void);
321
322	virtual	void						initPrograms			(vk::SourceCollections& programCollection) const
323										{
324											generateSources(m_shaderType, m_spec, programCollection);
325										}
326
327	virtual TestInstance*				createInstance			(Context& context) const = 0;
328
329protected:
330										IntegerFunctionCase		(const IntegerFunctionCase& other);
331	IntegerFunctionCase&				operator=				(const IntegerFunctionCase& other);
332
333	const glu::ShaderType				m_shaderType;
334
335	ShaderSpec							m_spec;
336
337	const int							m_numValues;
338};
339
340IntegerFunctionCase::IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
341	: TestCase		(testCtx, name, description)
342	, m_shaderType	(shaderType)
343	, m_numValues	(100)
344{
345}
346
347IntegerFunctionCase::~IntegerFunctionCase (void)
348{
349}
350
351// IntegerFunctionTestInstance
352
353class IntegerFunctionTestInstance : public TestInstance
354{
355public:
356								IntegerFunctionTestInstance		(Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
357									: TestInstance	(context)
358									, m_shaderType	(shaderType)
359									, m_spec		(spec)
360									, m_numValues	(numValues)
361									, m_name		(name)
362									, m_executor	(createExecutor(context, m_shaderType, m_spec))
363								{
364								}
365	virtual tcu::TestStatus		iterate							(void);
366protected:
367	virtual bool						compare					(const void* const* inputs, const void* const* outputs) = 0;
368
369	virtual void						getInputValues			(int numValues, void* const* values) const = 0;
370
371	const glu::ShaderType				m_shaderType;
372
373	ShaderSpec							m_spec;
374
375	const int							m_numValues;
376
377	const char*							m_name;
378
379	std::ostringstream					m_failMsg;				//!< Comparison failure help message.
380
381	de::UniquePtr<ShaderExecutor>		m_executor;
382};
383
384tcu::TestStatus IntegerFunctionTestInstance::iterate (void)
385{
386	const int				numInputScalars			= computeTotalScalarSize(m_spec.inputs);
387	const int				numOutputScalars		= computeTotalScalarSize(m_spec.outputs);
388	vector<deUint32>		inputData				(numInputScalars * m_numValues);
389	vector<deUint32>		outputData				(numOutputScalars * m_numValues);
390	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
391	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
392
393	// Initialize input data.
394	getInputValues(m_numValues, &inputPointers[0]);
395
396	// Execute shader.
397	m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
398
399	// Compare results.
400	{
401		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
402		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
403		vector<void*>			curInputPtr			(inputPointers.size());
404		vector<void*>			curOutputPtr		(outputPointers.size());
405		int						numFailed			= 0;
406		tcu::TestContext&		testCtx				= m_context.getTestContext();
407		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
408		{
409			// Set up pointers for comparison.
410			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
411				curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
412
413			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
414				curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
415
416			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
417			{
418				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
419
420				testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
421
422				testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
423				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
424					testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
425														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
426									   << TestLog::EndMessage;
427
428				testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
429				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
430					testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
431														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
432									   << TestLog::EndMessage;
433
434				m_failMsg.str("");
435				m_failMsg.clear();
436				numFailed += 1;
437			}
438		}
439
440		testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
441
442		if (numFailed == 0)
443			return tcu::TestStatus::pass("Pass");
444		else
445			return tcu::TestStatus::fail("Result comparison failed");
446	}
447}
448
449// Test cases
450
451class UaddCarryCaseInstance : public IntegerFunctionTestInstance
452{
453public:
454	UaddCarryCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
455		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
456	{
457	}
458
459	void getInputValues (int numValues, void* const* values) const
460	{
461		de::Random				rnd				(deStringHash(m_name) ^ 0x235facu);
462		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
463		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
464		const int				scalarSize		= glu::getDataTypeScalarSize(type);
465		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
466		const deUint32			integerMask		= getLowBitMask(integerLength);
467		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
468		deUint32*				in0				= (deUint32*)values[0];
469		deUint32*				in1				= (deUint32*)values[1];
470
471		const struct
472		{
473			deUint32	x;
474			deUint32	y;
475		} easyCases[] =
476		{
477			{ 0x00000000u,	0x00000000u },
478			{ 0xfffffffeu,	0x00000001u },
479			{ 0x00000001u,	0xfffffffeu },
480			{ 0xffffffffu,	0x00000001u },
481			{ 0x00000001u,	0xffffffffu },
482			{ 0xfffffffeu,	0x00000002u },
483			{ 0x00000002u,	0xfffffffeu },
484			{ 0xffffffffu,	0xffffffffu }
485		};
486
487		// generate integers with proper bit count
488		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
489		{
490			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
491			{
492				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
493				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
494			}
495		}
496
497		// convert to signed
498		if (isSigned)
499		{
500			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
501			{
502				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
503				{
504					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
505					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
506				}
507			}
508		}
509
510		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
511		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
512	}
513
514	bool compare (const void* const* inputs, const void* const* outputs)
515	{
516		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
517		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
518		const int				scalarSize		= glu::getDataTypeScalarSize(type);
519		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
520		const deUint32			mask0			= getLowBitMask(integerLength);
521
522		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
523		{
524			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
525			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
526			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
527			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
528			const deUint32	ref0	= in0+in1;
529			const deUint32	ref1	= (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
530
531			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
532			{
533				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
534				return false;
535			}
536		}
537
538		return true;
539	}
540};
541
542class UaddCarryCase : public IntegerFunctionCase
543{
544public:
545	UaddCarryCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
546		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
547	{
548		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
549		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
550		m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
551		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
552		m_spec.source = "sum = uaddCarry(x, y, carry);";
553	}
554
555	TestInstance* createInstance (Context& ctx) const
556	{
557		return new UaddCarryCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
558	}
559};
560
561class UsubBorrowCaseInstance : public IntegerFunctionTestInstance
562{
563public:
564	UsubBorrowCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
565		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
566	{
567	}
568
569	void getInputValues (int numValues, void* const* values) const
570	{
571		de::Random				rnd				(deStringHash(m_name) ^ 0x235facu);
572		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
573		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
574		const int				scalarSize		= glu::getDataTypeScalarSize(type);
575		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
576		const deUint32			integerMask		= getLowBitMask(integerLength);
577		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
578		deUint32*				in0				= (deUint32*)values[0];
579		deUint32*				in1				= (deUint32*)values[1];
580
581		const struct
582		{
583			deUint32	x;
584			deUint32	y;
585		} easyCases[] =
586		{
587			{ 0x00000000u,	0x00000000u },
588			{ 0x00000001u,	0x00000001u },
589			{ 0x00000001u,	0x00000002u },
590			{ 0x00000001u,	0xffffffffu },
591			{ 0xfffffffeu,	0xffffffffu },
592			{ 0xffffffffu,	0xffffffffu },
593		};
594
595		// generate integers with proper bit count
596		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
597		{
598			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
599			{
600				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
601				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
602			}
603		}
604
605		// convert to signed
606		if (isSigned)
607		{
608			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
609			{
610				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
611				{
612					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
613					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
614				}
615			}
616		}
617
618		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
619		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
620	}
621
622	bool compare (const void* const* inputs, const void* const* outputs)
623	{
624		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
625		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
626		const int				scalarSize		= glu::getDataTypeScalarSize(type);
627		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
628		const deUint32			mask0			= getLowBitMask(integerLength);
629
630		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
631		{
632			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
633			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
634			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
635			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
636			const deUint32	ref0	= in0-in1;
637			const deUint32	ref1	= in0 >= in1 ? 0u : 1u;
638
639			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
640			{
641				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
642				return false;
643			}
644		}
645
646		return true;
647	}
648};
649
650class UsubBorrowCase : public IntegerFunctionCase
651{
652public:
653	UsubBorrowCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
654		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
655	{
656		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
657		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
658		m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
659		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
660		m_spec.source = "diff = usubBorrow(x, y, carry);";
661	}
662
663	TestInstance* createInstance (Context& ctx) const
664	{
665		return new UsubBorrowCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
666	}
667};
668
669class UmulExtendedCaseInstance : public IntegerFunctionTestInstance
670{
671public:
672	UmulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
673		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
674	{
675	}
676
677	void getInputValues (int numValues, void* const* values) const
678	{
679		de::Random				rnd			(deStringHash(m_name) ^ 0x235facu);
680		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
681//		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
682		const int				scalarSize	= glu::getDataTypeScalarSize(type);
683		deUint32*				in0			= (deUint32*)values[0];
684		deUint32*				in1			= (deUint32*)values[1];
685		int						valueNdx	= 0;
686
687		const struct
688		{
689			deUint32	x;
690			deUint32	y;
691		} easyCases[] =
692		{
693			{ 0x00000000u,	0x00000000u },
694			{ 0xffffffffu,	0x00000001u },
695			{ 0xffffffffu,	0x00000002u },
696			{ 0x00000001u,	0xffffffffu },
697			{ 0x00000002u,	0xffffffffu },
698			{ 0xffffffffu,	0xffffffffu },
699		};
700
701		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
702		{
703			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
704			{
705				in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
706				in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
707			}
708
709			valueNdx += 1;
710		}
711
712		while (valueNdx < numValues)
713		{
714			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
715			{
716				const deUint32	base0	= rnd.getUint32();
717				const deUint32	base1	= rnd.getUint32();
718				const int		adj0	= rnd.getInt(0, 20);
719				const int		adj1	= rnd.getInt(0, 20);
720				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
721				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
722			}
723
724			valueNdx += 1;
725		}
726	}
727
728	bool compare (const void* const* inputs, const void* const* outputs)
729	{
730		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
731		const int				scalarSize		= glu::getDataTypeScalarSize(type);
732
733		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
734		{
735			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
736			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
737			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
738			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
739			const deUint64	mul64	= deUint64(in0)*deUint64(in1);
740			const deUint32	ref0	= deUint32(mul64 >> 32);
741			const deUint32	ref1	= deUint32(mul64 & 0xffffffffu);
742
743			if (out0 != ref0 || out1 != ref1)
744			{
745				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
746				return false;
747			}
748		}
749
750		return true;
751	}
752};
753
754class UmulExtendedCase : public IntegerFunctionCase
755{
756public:
757	UmulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
758		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
759	{
760		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
761		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
762		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
763		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
764		m_spec.source = "umulExtended(x, y, msb, lsb);";
765	}
766
767	TestInstance* createInstance (Context& ctx) const
768	{
769		return new UmulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
770	}
771};
772
773class ImulExtendedCaseInstance : public IntegerFunctionTestInstance
774{
775public:
776	ImulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
777		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
778	{
779	}
780
781	void getInputValues (int numValues, void* const* values) const
782	{
783		de::Random				rnd			(deStringHash(m_name) ^ 0x224fa1u);
784		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
785//		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
786		const int				scalarSize	= glu::getDataTypeScalarSize(type);
787		deUint32*				in0			= (deUint32*)values[0];
788		deUint32*				in1			= (deUint32*)values[1];
789		int						valueNdx	= 0;
790
791		const struct
792		{
793			deUint32	x;
794			deUint32	y;
795		} easyCases[] =
796		{
797			{ 0x00000000u,	0x00000000u },
798			{ 0xffffffffu,	0x00000002u },
799			{ 0x7fffffffu,	0x00000001u },
800			{ 0x7fffffffu,	0x00000002u },
801			{ 0x7fffffffu,	0x7fffffffu },
802			{ 0xffffffffu,	0xffffffffu },
803			{ 0x7fffffffu,	0xfffffffeu },
804		};
805
806		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
807		{
808			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
809			{
810				in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
811				in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
812			}
813
814			valueNdx += 1;
815		}
816
817		while (valueNdx < numValues)
818		{
819			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
820			{
821				const deInt32	base0	= (deInt32)rnd.getUint32();
822				const deInt32	base1	= (deInt32)rnd.getUint32();
823				const int		adj0	= rnd.getInt(0, 20);
824				const int		adj1	= rnd.getInt(0, 20);
825				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
826				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
827			}
828
829			valueNdx += 1;
830		}
831	}
832
833	bool compare (const void* const* inputs, const void* const* outputs)
834	{
835		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
836		const int				scalarSize		= glu::getDataTypeScalarSize(type);
837
838		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
839		{
840			const deInt32	in0		= ((const deInt32*)inputs[0])[compNdx];
841			const deInt32	in1		= ((const deInt32*)inputs[1])[compNdx];
842			const deInt32	out0	= ((const deInt32*)outputs[0])[compNdx];
843			const deInt32	out1	= ((const deInt32*)outputs[1])[compNdx];
844			const deInt64	mul64	= deInt64(in0)*deInt64(in1);
845			const deInt32	ref0	= deInt32(mul64 >> 32);
846			const deInt32	ref1	= deInt32(mul64 & 0xffffffffu);
847
848			if (out0 != ref0 || out1 != ref1)
849			{
850				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
851				return false;
852			}
853		}
854
855		return true;
856	}
857};
858
859class ImulExtendedCase : public IntegerFunctionCase
860{
861public:
862	ImulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
863		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
864	{
865		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
866		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
867		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
868		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
869		m_spec.source = "imulExtended(x, y, msb, lsb);";
870	}
871
872	TestInstance* createInstance (Context& ctx) const
873	{
874		return new ImulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
875	}
876};
877
878class BitfieldExtractCaseInstance : public IntegerFunctionTestInstance
879{
880public:
881	BitfieldExtractCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
882		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
883	{
884	}
885
886	void getInputValues (int numValues, void* const* values) const
887	{
888		de::Random				rnd			(deStringHash(m_name) ^ 0xa113fca2u);
889		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
890		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
891		const bool				ignoreSign	= precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
892		const int				numBits		= getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
893		deUint32*				inValue		= (deUint32*)values[0];
894		int*					inOffset	= (int*)values[1];
895		int*					inBits		= (int*)values[2];
896
897		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
898		{
899			const int		bits	= rnd.getInt(0, numBits);
900			const int		offset	= rnd.getInt(0, numBits-bits);
901
902			inOffset[valueNdx]	= offset;
903			inBits[valueNdx]	= bits;
904		}
905
906		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
907	}
908
909	bool compare (const void* const* inputs, const void* const* outputs)
910	{
911		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
912		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
913		const int				scalarSize		= glu::getDataTypeScalarSize(type);
914		const int				offset			= *((const int*)inputs[1]);
915		const int				bits			= *((const int*)inputs[2]);
916
917		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
918		{
919			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
920			const deUint32	out		= ((const deUint32*)outputs[0])[compNdx];
921			const deUint32	valMask	= (bits == 32 ? ~0u : ((1u<<bits)-1u));
922			const deUint32	baseVal	= (offset == 32) ? (0) : ((value >> offset) & valMask);
923			const deUint32	ref		= baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
924
925			if (out != ref)
926			{
927				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
928				return false;
929			}
930		}
931
932		return true;
933	}
934};
935
936class BitfieldExtractCase : public IntegerFunctionCase
937{
938public:
939	BitfieldExtractCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
940		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
941	{
942		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
943		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
944		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
945		m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
946		m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
947	}
948
949	TestInstance* createInstance (Context& ctx) const
950	{
951		return new BitfieldExtractCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
952	}
953};
954
955class BitfieldInsertCaseInstance : public IntegerFunctionTestInstance
956{
957public:
958	BitfieldInsertCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
959		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
960	{
961	}
962
963	void getInputValues (int numValues, void* const* values) const
964	{
965		de::Random				rnd			(deStringHash(m_name) ^ 0x12c2acff);
966		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
967		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
968		const int				numBits		= getShaderUintBitCount(m_shaderType, precision);
969		deUint32*				inBase		= (deUint32*)values[0];
970		deUint32*				inInsert	= (deUint32*)values[1];
971		int*					inOffset	= (int*)values[2];
972		int*					inBits		= (int*)values[3];
973
974		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
975		{
976			const int bits		= rnd.getInt(0, numBits);
977			const int offset	= rnd.getInt(0, numBits-bits);
978
979			inOffset[valueNdx]	= offset;
980			inBits[valueNdx]	= bits;
981		}
982
983		generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
984		generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
985	}
986
987	bool compare (const void* const* inputs, const void* const* outputs)
988	{
989		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
990		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
991		const int				scalarSize		= glu::getDataTypeScalarSize(type);
992		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
993		const deUint32			cmpMask			= getLowBitMask(integerLength);
994		const int				offset			= *((const int*)inputs[2]);
995		const int				bits			= *((const int*)inputs[3]);
996
997		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
998		{
999			const deUint32	base	= ((const deUint32*)inputs[0])[compNdx];
1000			const deUint32	insert	= ((const deUint32*)inputs[1])[compNdx];
1001			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
1002
1003			const deUint32	mask	= bits == 32 ? ~0u : (1u<<bits)-1;
1004			const deUint32	ref		= (base & ~(mask<<offset)) | ((insert & mask)<<offset);
1005
1006			if ((out&cmpMask) != (ref&cmpMask))
1007			{
1008				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1009				return false;
1010			}
1011		}
1012
1013		return true;
1014	}
1015};
1016
1017class BitfieldInsertCase : public IntegerFunctionCase
1018{
1019public:
1020	BitfieldInsertCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1021		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
1022	{
1023		m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
1024		m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
1025		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
1026		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
1027		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
1028		m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
1029	}
1030
1031	TestInstance* createInstance (Context& ctx) const
1032	{
1033		return new BitfieldInsertCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1034	}
1035};
1036
1037class BitfieldReverseCaseInstance : public IntegerFunctionTestInstance
1038{
1039public:
1040	BitfieldReverseCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1041		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1042	{
1043	}
1044
1045	void getInputValues (int numValues, void* const* values) const
1046	{
1047		de::Random				rnd			(deStringHash(m_name) ^ 0xff23a4);
1048		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1049		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1050		deUint32*				inValue		= (deUint32*)values[0];
1051
1052		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1053	}
1054
1055	bool compare (const void* const* inputs, const void* const* outputs)
1056	{
1057		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1058		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1059		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1060		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1061		const deUint32			cmpMask			= reverseBits(getLowBitMask(integerLength));
1062
1063		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1064		{
1065			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1066			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
1067			const deUint32	ref		= reverseBits(value);
1068
1069			if ((out&cmpMask) != (ref&cmpMask))
1070			{
1071				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1072				return false;
1073			}
1074		}
1075
1076		return true;
1077	}
1078};
1079
1080class BitfieldReverseCase : public IntegerFunctionCase
1081{
1082public:
1083	BitfieldReverseCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1084		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
1085	{
1086		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1087		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1088		m_spec.source = "result = bitfieldReverse(value);";
1089	}
1090
1091	TestInstance* createInstance (Context& ctx) const
1092	{
1093		return new BitfieldReverseCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1094	}
1095};
1096
1097class BitCountCaseInstance : public IntegerFunctionTestInstance
1098{
1099public:
1100	BitCountCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1101		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1102	{
1103	}
1104
1105	void getInputValues (int numValues, void* const* values) const
1106	{
1107		de::Random				rnd			(deStringHash(m_name) ^ 0xab2cca4);
1108		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1109		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1110		deUint32*				inValue		= (deUint32*)values[0];
1111
1112		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1113	}
1114
1115	bool compare (const void* const* inputs, const void* const* outputs)
1116	{
1117		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1118		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1119		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1120		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1121		const deUint32			countMask		= getLowBitMask(integerLength);
1122
1123		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1124		{
1125			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1126			const int		out		= ((const int*)outputs[0])[compNdx];
1127			const int		minRef	= dePop32(value&countMask);
1128			const int		maxRef	= dePop32(value);
1129
1130			if (!de::inRange(out, minRef, maxRef))
1131			{
1132				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1133				return false;
1134			}
1135		}
1136
1137		return true;
1138	}
1139};
1140
1141class BitCountCase : public IntegerFunctionCase
1142{
1143public:
1144	BitCountCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1145		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
1146	{
1147		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1148		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1149
1150		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1151		m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_MEDIUMP)));
1152		m_spec.source = "count = bitCount(value);";
1153	}
1154
1155	TestInstance* createInstance (Context& ctx) const
1156	{
1157		return new BitCountCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1158	}
1159};
1160
1161class FindLSBCaseInstance : public IntegerFunctionTestInstance
1162{
1163public:
1164	FindLSBCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1165		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1166	{
1167	}
1168
1169	void getInputValues (int numValues, void* const* values) const
1170	{
1171		de::Random				rnd			(deStringHash(m_name) ^ 0x9923c2af);
1172		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1173		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1174		deUint32*				inValue		= (deUint32*)values[0];
1175
1176		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1177	}
1178
1179	bool compare (const void* const* inputs, const void* const* outputs)
1180	{
1181		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1182		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1183		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1184		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1185		const deUint32			mask			= getLowBitMask(integerLength);
1186
1187		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1188		{
1189			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1190			const int		out		= ((const int*)outputs[0])[compNdx];
1191			const int		minRef	= findLSB(value&mask);
1192			const int		maxRef	= findLSB(value);
1193
1194			if (!de::inRange(out, minRef, maxRef))
1195			{
1196				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1197				return false;
1198			}
1199		}
1200
1201		return true;
1202	}
1203};
1204
1205class FindLSBCase : public IntegerFunctionCase
1206{
1207public:
1208	FindLSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1209		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
1210	{
1211		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1212		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1213
1214		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1215		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
1216		m_spec.source = "lsb = findLSB(value);";
1217	}
1218
1219	TestInstance* createInstance (Context& ctx) const
1220	{
1221		return new FindLSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1222	}
1223};
1224
1225class findMSBCaseInstance : public IntegerFunctionTestInstance
1226{
1227public:
1228	findMSBCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1229		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1230	{
1231	}
1232
1233	void getInputValues (int numValues, void* const* values) const
1234	{
1235		de::Random				rnd			(deStringHash(m_name) ^ 0x742ac4e);
1236		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1237		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1238		deUint32*				inValue		= (deUint32*)values[0];
1239
1240		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1241	}
1242
1243	bool compare (const void* const* inputs, const void* const* outputs)
1244	{
1245		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1246		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1247		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
1248		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1249		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1250
1251		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1252		{
1253			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1254			const int		out		= ((const deInt32*)outputs[0])[compNdx];
1255			const int		minRef	= isSigned ? findMSB(toPrecision(deInt32(value), integerLength))	: findMSB(toPrecision(value, integerLength));
1256			const int		maxRef	= isSigned ? findMSB(deInt32(value))								: findMSB(value);
1257
1258			if (!de::inRange(out, minRef, maxRef))
1259			{
1260				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1261				return false;
1262			}
1263		}
1264
1265		return true;
1266	}
1267};
1268
1269class findMSBCase : public IntegerFunctionCase
1270{
1271public:
1272	findMSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1273		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
1274	{
1275		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1276		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1277
1278		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1279		m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
1280		m_spec.source = "msb = findMSB(value);";
1281	}
1282
1283	TestInstance* createInstance (Context& ctx) const
1284	{
1285		return new findMSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1286	}
1287};
1288
1289ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (tcu::TestContext& testCtx)
1290	: tcu::TestCaseGroup	(testCtx, "integer", "Integer function tests")
1291{
1292}
1293
1294ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1295{
1296}
1297
1298void ShaderIntegerFunctionTests::init (void)
1299{
1300	enum
1301	{
1302		VS = (1<<glu::SHADERTYPE_VERTEX),
1303		FS = (1<<glu::SHADERTYPE_FRAGMENT),
1304		CS = (1<<glu::SHADERTYPE_COMPUTE),
1305		GS = (1<<glu::SHADERTYPE_GEOMETRY),
1306		TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
1307		TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
1308
1309		ALL_SHADERS = VS|TC|TE|GS|FS|CS
1310	};
1311
1312	//																		Int?	Uint?	AllPrec?	Shaders
1313	addFunctionCases<UaddCarryCase>				(this,	"uaddcarry",		false,	true,	true,		ALL_SHADERS);
1314	addFunctionCases<UsubBorrowCase>			(this,	"usubborrow",		false,	true,	true,		ALL_SHADERS);
1315	addFunctionCases<UmulExtendedCase>			(this,	"umulextended",		false,	true,	false,		ALL_SHADERS);
1316	addFunctionCases<ImulExtendedCase>			(this,	"imulextended",		true,	false,	false,		ALL_SHADERS);
1317	addFunctionCases<BitfieldExtractCase>		(this,	"bitfieldextract",	true,	true,	true,		ALL_SHADERS);
1318	addFunctionCases<BitfieldInsertCase>		(this,	"bitfieldinsert",	true,	true,	true,		ALL_SHADERS);
1319	addFunctionCases<BitfieldReverseCase>		(this,	"bitfieldreverse",	true,	true,	true,		ALL_SHADERS);
1320	addFunctionCases<BitCountCase>				(this,	"bitcount",			true,	true,	true,		ALL_SHADERS);
1321	addFunctionCases<FindLSBCase>				(this,	"findlsb",			true,	true,	true,		ALL_SHADERS);
1322	addFunctionCases<findMSBCase>				(this,	"findMSB",			true,	true,	true,		ALL_SHADERS);
1323}
1324
1325} // shaderexecutor
1326} // vkt
1327