1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 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 Optimized vs unoptimized shader performance tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2pShaderOptimizationTests.hpp"
25#include "glsShaderPerformanceMeasurer.hpp"
26#include "gluRenderContext.hpp"
27#include "gluShaderProgram.hpp"
28#include "tcuTestLog.hpp"
29#include "tcuVector.hpp"
30#include "tcuStringTemplate.hpp"
31#include "deSharedPtr.hpp"
32#include "deStringUtil.hpp"
33#include "deMath.h"
34
35#include "glwFunctions.hpp"
36
37#include <vector>
38#include <string>
39#include <map>
40
41using glu::ShaderProgram;
42using tcu::TestLog;
43using tcu::Vec4;
44using de::SharedPtr;
45using de::toString;
46
47using std::vector;
48using std::string;
49
50namespace deqp
51{
52
53using gls::ShaderPerformanceMeasurer;
54
55namespace gles2
56{
57namespace Performance
58{
59
60static inline std::map<string, string> singleMap (const string& key, const string& value)
61{
62	std::map<string, string> res;
63	res[key] = value;
64	return res;
65}
66
67static inline string repeat (const string& str, int numRepeats, const string& delim = "")
68{
69	string result = str;
70	for (int i = 1; i < numRepeats; i++)
71		result += delim + str;
72	return result;
73}
74
75static inline string repeatIndexedTemplate (const string& strTempl, int numRepeats, const string& delim = "", int ndxStart = 0)
76{
77	const tcu::StringTemplate	templ(strTempl);
78	string						result;
79	std::map<string, string>	params;
80
81	for (int i = 0; i < numRepeats; i++)
82	{
83		params["PREV_NDX"]	= toString(i + ndxStart - 1);
84		params["NDX"]		= toString(i + ndxStart);
85
86		result += (i > 0 ? delim : "") + templ.specialize(params);
87	}
88
89	return result;
90}
91
92namespace
93{
94
95enum CaseShaderType
96{
97	CASESHADERTYPE_VERTEX = 0,
98	CASESHADERTYPE_FRAGMENT,
99
100	CASESHADERTYPE_LAST
101};
102
103static inline string getShaderPrecision (CaseShaderType shaderType)
104{
105	switch (shaderType)
106	{
107		case CASESHADERTYPE_VERTEX:		return "highp";
108		case CASESHADERTYPE_FRAGMENT:	return "mediump";
109		default:
110			DE_ASSERT(false);
111			return DE_NULL;
112	}
113}
114
115struct ProgramData
116{
117	glu::ProgramSources			sources;
118	vector<gls::AttribSpec>		attributes; //!< \note Shouldn't contain a_position; that one is set by gls::ShaderPerformanceMeasurer.
119
120	ProgramData (void) {}
121	ProgramData (const glu::ProgramSources& sources_, const vector<gls::AttribSpec>& attributes_ = vector<gls::AttribSpec>())	: sources(sources_), attributes(attributes_)	{}
122	ProgramData (const glu::ProgramSources& sources_, const gls::AttribSpec& attribute)											: sources(sources_), attributes(1, attribute)	{}
123};
124
125//! Shader boilerplate helper; most cases have similar basic shader structure.
126static inline ProgramData defaultProgramData (CaseShaderType shaderType, const string& funcDefs, const string& mainStatements)
127{
128	const bool		isVertexCase	= shaderType == CASESHADERTYPE_VERTEX;
129	const bool		isFragmentCase	= shaderType == CASESHADERTYPE_FRAGMENT;
130	const string	vtxPrec			= getShaderPrecision(CASESHADERTYPE_VERTEX);
131	const string	fragPrec		= getShaderPrecision(CASESHADERTYPE_FRAGMENT);
132
133	return ProgramData(glu::ProgramSources() << glu::VertexSource(		"attribute " + vtxPrec + " vec4 a_position;\n"
134																		"attribute " + vtxPrec + " vec4 a_value;\n"
135																		"varying " + fragPrec + " vec4 v_value;\n"
136																		+ (isVertexCase ? funcDefs : "") +
137																		"void main (void)\n"
138																		"{\n"
139																		"	gl_Position = a_position;\n"
140																		"	" + vtxPrec + " vec4 value = a_value;\n"
141																		+ (isVertexCase ? mainStatements : "") +
142																		"	v_value = value;\n"
143																		"}\n")
144
145											 << glu::FragmentSource(	"varying " + fragPrec + " vec4 v_value;\n"
146																		+ (isFragmentCase ? funcDefs : "") +
147																		"void main (void)\n"
148																		"{\n"
149																		"	" + fragPrec + " vec4 value = v_value;\n"
150																		+ (isFragmentCase ? mainStatements : "") +
151																		"	gl_FragColor = value;\n"
152																		"}\n"),
153					  gls::AttribSpec("a_value",
154									  Vec4(1.0f, 0.0f, 0.0f, 0.0f),
155									  Vec4(0.0f, 1.0f, 0.0f, 0.0f),
156									  Vec4(0.0f, 0.0f, 1.0f, 0.0f),
157									  Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
158}
159
160static inline ProgramData defaultProgramData (CaseShaderType shaderType, const string& mainStatements)
161{
162	return defaultProgramData(shaderType, "", mainStatements);
163}
164
165class ShaderOptimizationCase : public TestCase
166{
167public:
168	ShaderOptimizationCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType)
169		: TestCase				(context, tcu::NODETYPE_PERFORMANCE, name, description)
170		, m_caseShaderType		(caseShaderType)
171		, m_state				(STATE_LAST)
172		, m_measurer			(context.getRenderContext(), caseShaderType == CASESHADERTYPE_VERTEX	? gls::CASETYPE_VERTEX
173														   : caseShaderType == CASESHADERTYPE_FRAGMENT	? gls::CASETYPE_FRAGMENT
174														   : gls::CASETYPE_LAST)
175		, m_unoptimizedResult	(-1.0f, -1.0f)
176		, m_optimizedResult		(-1.0f, -1.0f)
177	{
178	}
179
180	virtual ~ShaderOptimizationCase (void) {}
181
182	void			init		(void);
183	IterateResult	iterate		(void);
184
185protected:
186	virtual ProgramData		generateProgramData (bool optimized) const = 0;
187
188	const CaseShaderType	m_caseShaderType;
189
190private:
191	enum State
192	{
193		STATE_INIT_UNOPTIMIZED = 0,
194		STATE_MEASURE_UNOPTIMIZED,
195		STATE_INIT_OPTIMIZED,
196		STATE_MEASURE_OPTIMIZED,
197		STATE_FINISHED,
198
199		STATE_LAST
200	};
201
202	ProgramData&						programData		(bool optimized) { return optimized ? m_optimizedData		: m_unoptimizedData;		}
203	SharedPtr<const ShaderProgram>&		program			(bool optimized) { return optimized ? m_optimizedProgram	: m_unoptimizedProgram;		}
204	ShaderPerformanceMeasurer::Result&	result			(bool optimized) { return optimized ? m_optimizedResult		: m_unoptimizedResult;		}
205
206	State								m_state;
207	ShaderPerformanceMeasurer			m_measurer;
208
209	ProgramData							m_unoptimizedData;
210	ProgramData							m_optimizedData;
211	SharedPtr<const ShaderProgram>		m_unoptimizedProgram;
212	SharedPtr<const ShaderProgram>		m_optimizedProgram;
213	ShaderPerformanceMeasurer::Result	m_unoptimizedResult;
214	ShaderPerformanceMeasurer::Result	m_optimizedResult;
215};
216
217void ShaderOptimizationCase::init (void)
218{
219	const glu::RenderContext&	renderCtx	= m_context.getRenderContext();
220	TestLog&					log			= m_testCtx.getLog();
221
222	m_measurer.logParameters(log);
223
224	for (int ndx = 0; ndx < 2; ndx++)
225	{
226		const bool optimized = ndx == 1;
227
228		programData(optimized) = generateProgramData(optimized);
229
230		for (int i = 0; i < (int)programData(optimized).attributes.size(); i++)
231			DE_ASSERT(programData(optimized).attributes[i].name != "a_position"); // \note Position attribute is set by m_measurer.
232
233		program(optimized) = SharedPtr<const ShaderProgram>(new ShaderProgram(renderCtx, programData(optimized).sources));
234
235		{
236			const tcu::ScopedLogSection section(log, optimized ? "OptimizedProgram"			: "UnoptimizedProgram",
237													 optimized ? "Hand-optimized program"	: "Unoptimized program");
238			log << *program(optimized);
239		}
240
241		if (!program(optimized)->isOk())
242			TCU_FAIL("Shader compilation failed");
243	}
244
245	m_state = STATE_INIT_UNOPTIMIZED;
246}
247
248ShaderOptimizationCase::IterateResult ShaderOptimizationCase::iterate (void)
249{
250	TestLog& log = m_testCtx.getLog();
251
252	if (m_state == STATE_INIT_UNOPTIMIZED || m_state == STATE_INIT_OPTIMIZED)
253	{
254		const bool optimized = m_state == STATE_INIT_OPTIMIZED;
255		m_measurer.init(program(optimized)->getProgram(), programData(optimized).attributes, 1);
256		m_state = optimized ? STATE_MEASURE_OPTIMIZED : STATE_MEASURE_UNOPTIMIZED;
257
258		return CONTINUE;
259	}
260	else if (m_state == STATE_MEASURE_UNOPTIMIZED || m_state == STATE_MEASURE_OPTIMIZED)
261	{
262		m_measurer.iterate();
263
264		if (m_measurer.isFinished())
265		{
266			const bool						optimized	= m_state == STATE_MEASURE_OPTIMIZED;
267			const tcu::ScopedLogSection		section		(log, optimized ? "OptimizedResult"									: "UnoptimizedResult",
268															  optimized ? "Measurement results for hand-optimized program"	: "Measurement result for unoptimized program");
269			m_measurer.logMeasurementInfo(log);
270			result(optimized) = m_measurer.getResult();
271			m_measurer.deinit();
272			m_state = optimized ? STATE_FINISHED : STATE_INIT_OPTIMIZED;
273		}
274
275		return CONTINUE;
276	}
277	else
278	{
279		DE_ASSERT(m_state == STATE_FINISHED);
280
281		const float			unoptimizedRelevantResult	= m_caseShaderType == CASESHADERTYPE_VERTEX ? m_unoptimizedResult.megaVertPerSec	: m_unoptimizedResult.megaFragPerSec;
282		const float			optimizedRelevantResult		= m_caseShaderType == CASESHADERTYPE_VERTEX ? m_optimizedResult.megaVertPerSec		: m_optimizedResult.megaFragPerSec;
283		const char* const	relevantResultName			= m_caseShaderType == CASESHADERTYPE_VERTEX ? "vertex"								: "fragment";
284		const float			ratio						= unoptimizedRelevantResult / optimizedRelevantResult;
285		const int			handOptimizationGain		= (int)deFloatRound(100.0f/ratio) - 100;
286
287		log << TestLog::Message << "Unoptimized / optimized " << relevantResultName << " performance ratio: " << ratio << TestLog::EndMessage;
288
289		if (handOptimizationGain >= 0)
290			log << TestLog::Message << "Note: " << handOptimizationGain << "% performance gain was achieved with hand-optimized version" << TestLog::EndMessage;
291		else
292			log << TestLog::Message << "Note: hand-optimization degraded performance by " << -handOptimizationGain << "%" << TestLog::EndMessage;
293
294		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(ratio, 2).c_str());
295
296		return STOP;
297	}
298}
299
300class LoopUnrollCase : public ShaderOptimizationCase
301{
302public:
303	enum CaseType
304	{
305		CASETYPE_INDEPENDENT = 0,
306		CASETYPE_DEPENDENT,
307
308		CASETYPE_LAST
309	};
310
311	LoopUnrollCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType, int numRepetitions)
312		: ShaderOptimizationCase	(context, name, description, caseShaderType)
313		, m_numRepetitions			(numRepetitions)
314		, m_caseType				(caseType)
315	{
316	}
317
318protected:
319	ProgramData generateProgramData (bool optimized) const
320	{
321		const string repetition = optimized ? repeatIndexedTemplate("\t" + expressionTemplate(m_caseType) + ";\n", m_numRepetitions)
322											: loop(m_numRepetitions, expressionTemplate(m_caseType));
323
324		return defaultProgramData(m_caseShaderType, "\t" + getShaderPrecision(m_caseShaderType) + " vec4 valueOrig = value;\n" + repetition);
325	}
326
327private:
328	const int		m_numRepetitions;
329	const CaseType	m_caseType;
330
331	static inline string expressionTemplate (CaseType caseType)
332	{
333		switch (caseType)
334		{
335			case CASETYPE_INDEPENDENT:	return "value += sin(float(${NDX}+1)*valueOrig)";
336			case CASETYPE_DEPENDENT:	return "value = sin(value)";
337			default:
338				DE_ASSERT(false);
339				return DE_NULL;
340		}
341	}
342
343	static inline string loop (int iterations, const string& innerExpr)
344	{
345		return "\tfor (int i = 0; i < " + toString(iterations) + "; i++)\n\t\t" + tcu::StringTemplate(innerExpr).specialize(singleMap("NDX", "i")) + ";\n";
346	}
347};
348
349class LoopInvariantCodeMotionCase : public ShaderOptimizationCase
350{
351public:
352	LoopInvariantCodeMotionCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, int numLoopIterations)
353		: ShaderOptimizationCase	(context, name, description, caseShaderType)
354		, m_numLoopIterations		(numLoopIterations)
355	{
356	}
357
358protected:
359	ProgramData generateProgramData (bool optimized) const
360	{
361		float scale = 0.0f;
362		for (int i = 0; i < m_numLoopIterations; i++)
363			scale += 3.2f*(float)i + 4.6f;
364		scale = 1.0f / scale;
365
366		const string precision		= getShaderPrecision(m_caseShaderType);
367		const string statements		= optimized ?	"	" + precision + " vec4 valueOrig = value;\n"
368													"	" + precision + " vec4 y = sin(cos(sin(valueOrig)));\n"
369													"	for (int i = 0; i < " + toString(m_numLoopIterations) + "; i++)\n"
370													"	{\n"
371													"		" + precision + " float x = 3.2*float(i) + 4.6;\n"
372													"		value += x*y;\n"
373													"	}\n"
374													"	value *= " + toString(scale) + ";\n"
375
376												:	"	" + precision + " vec4 valueOrig = value;\n"
377													"	for (int i = 0; i < " + toString(m_numLoopIterations) + "; i++)\n"
378													"	{\n"
379													"		" + precision + " float x = 3.2*float(i) + 4.6;\n"
380													"		" + precision + " vec4 y = sin(cos(sin(valueOrig)));\n"
381													"		value += x*y;\n"
382													"	}\n"
383													"	value *= " + toString(scale) + ";\n";
384
385		return defaultProgramData(m_caseShaderType, statements);
386	}
387
388private:
389	const int m_numLoopIterations;
390};
391
392class FunctionInliningCase : public ShaderOptimizationCase
393{
394public:
395	FunctionInliningCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, int callNestingDepth)
396		: ShaderOptimizationCase	(context, name, description, caseShaderType)
397		, m_callNestingDepth		(callNestingDepth)
398	{
399	}
400
401protected:
402	ProgramData generateProgramData (bool optimized) const
403	{
404		const string precision				= getShaderPrecision(m_caseShaderType);
405		const string expression				= "value*vec4(0.8, 0.7, 0.6, 0.9)";
406		const string maybeFuncDefs			= optimized ? "" : funcDefinitions(m_callNestingDepth, precision, expression);
407		const string mainValueStatement		= (optimized ? "\tvalue = " + expression : "\tvalue = func" + toString(m_callNestingDepth-1) + "(value)") + ";\n";
408
409		return defaultProgramData(m_caseShaderType, maybeFuncDefs, mainValueStatement);
410	}
411
412private:
413	const int m_callNestingDepth;
414
415	static inline string funcDefinitions (int callNestingDepth, const string& precision, const string& expression)
416	{
417		string result = precision + " vec4 func0 (" + precision + " vec4 value) { return " + expression + "; }\n";
418
419		for (int i = 1; i < callNestingDepth; i++)
420			result += precision + " vec4 func" + toString(i) + " (" + precision + " vec4 v) { return func" + toString(i-1) + "(v); }\n";
421
422		return result;
423	}
424};
425
426class ConstantPropagationCase : public ShaderOptimizationCase
427{
428public:
429	enum CaseType
430	{
431		CASETYPE_BUILT_IN_FUNCTIONS = 0,
432		CASETYPE_ARRAY,
433		CASETYPE_STRUCT,
434
435		CASETYPE_LAST
436	};
437
438	ConstantPropagationCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType, bool useConstantExpressionsOnly)
439		: ShaderOptimizationCase			(context, name, description, caseShaderType)
440		, m_caseType						(caseType)
441		, m_useConstantExpressionsOnly		(useConstantExpressionsOnly)
442	{
443		DE_ASSERT(!(m_caseType == CASETYPE_ARRAY && m_useConstantExpressionsOnly)); // \note Would need array constructors, which GLSL ES 1 doesn't have.
444	}
445
446protected:
447	ProgramData generateProgramData (bool optimized) const
448	{
449		const bool		isVertexCase	= m_caseShaderType == CASESHADERTYPE_VERTEX;
450		const string	precision		= getShaderPrecision(m_caseShaderType);
451		const string	statements		= m_caseType == CASETYPE_BUILT_IN_FUNCTIONS		? builtinFunctionsCaseStatements	(optimized, m_useConstantExpressionsOnly, precision, isVertexCase)
452										: m_caseType == CASETYPE_ARRAY					? arrayCaseStatements				(optimized, precision, isVertexCase)
453										: m_caseType == CASETYPE_STRUCT					? structCaseStatements				(optimized, m_useConstantExpressionsOnly, precision, isVertexCase)
454										: DE_NULL;
455
456		return defaultProgramData(m_caseShaderType, statements);
457	}
458
459private:
460	const CaseType	m_caseType;
461	const bool		m_useConstantExpressionsOnly;
462
463	static inline string builtinFunctionsCaseStatements (bool optimized, bool constantExpressionsOnly, const string& precision, bool useHeavierWorkload)
464	{
465		const string	constMaybe = constantExpressionsOnly ? "const " : "";
466		const int		numSinRows = useHeavierWorkload ? 12 : 1;
467
468		return optimized ?	"	value = vec4(0.4, 0.5, 0.6, 0.7) * value; // NOTE: factor doesn't necessarily match the one in unoptimized shader, but shouldn't make a difference performance-wise\n"
469
470						 :	"	" + constMaybe + precision + " vec4 a = vec4(sin(0.7), cos(0.2), sin(0.9), abs(-0.5));\n"
471							"	" + constMaybe + precision + " vec4 b = cos(a) + fract(3.0*a.xzzw);\n"
472							"	" + constMaybe + "bvec4 c = bvec4(true, false, true, true);\n"
473							"	" + constMaybe + precision + " vec4 d = exp(b + vec4(c));\n"
474							"	" + constMaybe + precision + " vec4 e0 = inversesqrt(mix(d+a, d+b, a));\n"
475							+ repeatIndexedTemplate("	" + constMaybe + precision + " vec4 e${NDX} = sin(sin(sin(sin(e${PREV_NDX}))));\n", numSinRows, "", 1) +
476							"	" + constMaybe + precision + " vec4 f = abs(e" + toString(numSinRows) + ");\n" +
477							"	value = f*value;\n";
478	}
479
480	static inline string arrayCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
481	{
482		const int numSinRows = useHeavierWorkload ? 12 : 1;
483
484		return optimized ?	"	value = vec4(0.4, 0.5, 0.6, 0.7) * value; // NOTE: factor doesn't necessarily match the one in unoptimized shader, but shouldn't make a difference performance-wise\n"
485
486						 :	"	const int arrLen = 4;\n"
487							"	" + precision + " vec4 arr[arrLen];\n"
488							"	arr[0] = vec4(0.1, 0.5, 0.9, 1.3);\n"
489							"	arr[1] = vec4(0.2, 0.6, 1.0, 1.4);\n"
490							"	arr[2] = vec4(0.3, 0.7, 1.1, 1.5);\n"
491							"	arr[3] = vec4(0.4, 0.8, 1.2, 1.6);\n"
492							"	" + precision + " vec4 a = (arr[0] + arr[1] + arr[2] + arr[3]) * 0.25;\n"
493							"	" + precision + " vec4 b0 = cos(sin(a));\n"
494							+ repeatIndexedTemplate("	" + precision + " vec4 b${NDX} = sin(sin(sin(sin(b${PREV_NDX}))));\n", numSinRows, "", 1) +
495							"	" + precision + " vec4 c = abs(b" + toString(numSinRows) + ");\n" +
496							"	value = c*value;\n";
497	}
498
499	static inline string structCaseStatements (bool optimized, bool constantExpressionsOnly, const string& precision, bool useHeavierWorkload)
500	{
501		const string	constMaybe = constantExpressionsOnly ? "const " : "";
502		const int		numSinRows = useHeavierWorkload ? 12 : 1;
503
504		return optimized ?	"	value = vec4(0.4, 0.5, 0.6, 0.7) * value; // NOTE: factor doesn't necessarily match the one in unoptimized shader, but shouldn't make a difference performance-wise\n"
505
506						 :	"	struct S\n"
507							"	{\n"
508							"		" + precision + " vec4 a;\n"
509							"		" + precision + " vec4 b;\n"
510							"		" + precision + " vec4 c;\n"
511							"		" + precision + " vec4 d;\n"
512							"	};\n"
513							"\n"
514							"	" + constMaybe + "S s =\n"
515							"		S(vec4(0.1, 0.5, 0.9, 1.3),\n"
516							"		  vec4(0.2, 0.6, 1.0, 1.4),\n"
517							"		  vec4(0.3, 0.7, 1.1, 1.5),\n"
518							"		  vec4(0.4, 0.8, 1.2, 1.6));\n"
519							"	" + constMaybe + precision + " vec4 a = (s.a + s.b + s.c + s.d) * 0.25;\n"
520							"	" + constMaybe + precision + " vec4 b0 = cos(sin(a));\n"
521							+ repeatIndexedTemplate("	" + constMaybe + precision + " vec4 b${NDX} = sin(sin(sin(sin(b${PREV_NDX}))));\n", numSinRows, "", 1) +
522							"	" + constMaybe + precision + " vec4 c = abs(b" + toString(numSinRows) + ");\n" +
523							"	value = c*value;\n";
524	}
525};
526
527class CommonSubexpressionCase : public ShaderOptimizationCase
528{
529public:
530	enum CaseType
531	{
532		CASETYPE_SINGLE_STATEMENT = 0,
533		CASETYPE_MULTIPLE_STATEMENTS,
534		CASETYPE_STATIC_BRANCH,
535		CASETYPE_LOOP,
536
537		CASETYPE_LAST
538	};
539
540	CommonSubexpressionCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType)
541		: ShaderOptimizationCase	(context, name, description, caseShaderType)
542		, m_caseType				(caseType)
543	{
544	}
545
546protected:
547	ProgramData generateProgramData (bool optimized) const
548	{
549		const bool		isVertexCase	= m_caseShaderType == CASESHADERTYPE_VERTEX;
550		const string	precision		= getShaderPrecision(m_caseShaderType);
551		const string	statements		= m_caseType == CASETYPE_SINGLE_STATEMENT		? singleStatementCaseStatements		(optimized, precision, isVertexCase)
552										: m_caseType == CASETYPE_MULTIPLE_STATEMENTS	? multipleStatementsCaseStatements	(optimized, precision, isVertexCase)
553										: m_caseType == CASETYPE_STATIC_BRANCH			? staticBranchCaseStatements		(optimized, precision, isVertexCase)
554										: m_caseType == CASETYPE_LOOP					? loopCaseStatements				(optimized, precision, isVertexCase)
555										: DE_NULL;
556
557		return defaultProgramData(m_caseShaderType, statements);
558	}
559
560private:
561	const CaseType m_caseType;
562
563	static inline string singleStatementCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
564	{
565		const int numTopLevelRepeats = useHeavierWorkload ? 4 : 1;
566
567		return optimized ?	"	" + precision + " vec4 s = sin(value);\n"
568							"	" + precision + " vec4 cs = cos(s);\n"
569							"	" + precision + " vec4 d = fract(s + cs) + sqrt(s + exp(cs));\n"
570							"	value = " + repeat("d", numTopLevelRepeats, "+") + ";\n"
571
572						 :	"	value = " + repeat("fract(sin(value) + cos(sin(value))) + sqrt(sin(value) + exp(cos(sin(value))))", numTopLevelRepeats, "\n\t      + ") + ";\n";
573	}
574
575	static inline string multipleStatementsCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
576	{
577		const int numTopLevelRepeats = useHeavierWorkload ? 4 : 2;
578		DE_ASSERT(numTopLevelRepeats >= 2);
579
580		return optimized ?	"	" + precision + " vec4 a = sin(value) + cos(exp(value));\n"
581							"	" + precision + " vec4 b = cos(cos(a));\n"
582							"	a = fract(exp(sqrt(b)));\n"
583							"\n"
584							+ repeat("\tvalue += a*b;\n", numTopLevelRepeats)
585
586						 :	repeatIndexedTemplate(	"	" + precision + " vec4 a${NDX} = sin(value) + cos(exp(value));\n"
587													"	" + precision + " vec4 b${NDX} = cos(cos(a${NDX}));\n"
588													"	a${NDX} = fract(exp(sqrt(b${NDX})));\n"
589													"\n",
590													numTopLevelRepeats) +
591
592							repeatIndexedTemplate(	"	value += a${NDX}*b${NDX};\n", numTopLevelRepeats);
593	}
594
595	static inline string staticBranchCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
596	{
597		const int numTopLevelRepeats = useHeavierWorkload ? 4 : 2;
598		DE_ASSERT(numTopLevelRepeats >= 2);
599
600		if (optimized)
601		{
602			return "	" + precision + " vec4 a = sin(value) + cos(exp(value));\n"
603				   "	" + precision + " vec4 b = cos(a);\n"
604				   "	b = cos(b);\n"
605				   "	a = fract(exp(sqrt(b)));\n"
606				   "\n"
607				   + repeat("	value += a*b;\n", numTopLevelRepeats);
608		}
609		else
610		{
611			string result;
612
613			for (int i = 0; i < numTopLevelRepeats; i++)
614			{
615				result +=	"	" + precision + " vec4 a" + toString(i) + " = sin(value) + cos(exp(value));\n"
616							"	" + precision + " vec4 b" + toString(i) + " = cos(a" + toString(i) + ");\n";
617
618				if (i % 3 == 0)
619					result +=	"	if (1 < 2)\n"
620								"		b" + toString(i) + " = cos(b" + toString(i) + ");\n";
621				else if (i % 3 == 1)
622					result +=	"	b" + toString(i) + " = cos(b" + toString(i) + ");\n";
623				else if (i % 3 == 2)
624					result +=	"	if (2 < 1);\n"
625								"	else\n"
626								"		b" + toString(i) + " = cos(b" + toString(i) + ");\n";
627				else
628					DE_ASSERT(false);
629
630				result +=	"	a" + toString(i) + " = fract(exp(sqrt(b" + toString(i) + ")));\n\n";
631			}
632
633			result += repeatIndexedTemplate("	value += a${NDX}*b${NDX};\n", numTopLevelRepeats);
634
635			return result;
636		}
637	}
638
639	static inline string loopCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
640	{
641		const int numLoopIterations = useHeavierWorkload ? 32 : 4;
642
643		return optimized ?	"	" + precision + " vec4 acc = value;\n"
644							"	for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
645							"		acc = sin(acc);\n"
646							"\n"
647							"	value += acc;\n"
648							"	value += acc;\n"
649
650						 :	"	" + precision + " vec4 acc0 = value;\n"
651							"	for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
652							"		acc0 = sin(acc0);\n"
653							"\n"
654							"	" + precision + " vec4 acc1 = value;\n"
655							"	for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
656							"		acc1 = sin(acc1);\n"
657							"\n"
658							"	value += acc0;\n"
659							"	value += acc1;\n";
660	}
661};
662
663class DeadCodeEliminationCase : public ShaderOptimizationCase
664{
665public:
666	enum CaseType
667	{
668		CASETYPE_DEAD_BRANCH_SIMPLE = 0,
669		CASETYPE_DEAD_BRANCH_COMPLEX,
670		CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST,
671		CASETYPE_DEAD_BRANCH_FUNC_CALL,
672		CASETYPE_UNUSED_VALUE_BASIC,
673		CASETYPE_UNUSED_VALUE_LOOP,
674		CASETYPE_UNUSED_VALUE_DEAD_BRANCH,
675		CASETYPE_UNUSED_VALUE_AFTER_RETURN,
676		CASETYPE_UNUSED_VALUE_MUL_ZERO,
677
678		CASETYPE_LAST
679	};
680
681	DeadCodeEliminationCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType)
682		: ShaderOptimizationCase	(context, name, description, caseShaderType)
683		, m_caseType				(caseType)
684	{
685	}
686
687protected:
688	ProgramData generateProgramData (bool optimized) const
689	{
690		const bool		isVertexCase	= m_caseShaderType == CASESHADERTYPE_VERTEX;
691		const string	precision		= getShaderPrecision(m_caseShaderType);
692		const string	funcDefs		= m_caseType == CASETYPE_DEAD_BRANCH_FUNC_CALL		? deadBranchFuncCallCaseFuncDefs		(optimized, precision)
693										: m_caseType == CASETYPE_UNUSED_VALUE_AFTER_RETURN	? unusedValueAfterReturnCaseFuncDefs	(optimized, precision, isVertexCase)
694										: "";
695
696		const string	statements		= m_caseType == CASETYPE_DEAD_BRANCH_SIMPLE				? deadBranchSimpleCaseStatements			(optimized, isVertexCase)
697										: m_caseType == CASETYPE_DEAD_BRANCH_COMPLEX			? deadBranchComplexCaseStatements			(optimized, precision, true,	isVertexCase)
698										: m_caseType == CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST	? deadBranchComplexCaseStatements			(optimized, precision, false,	isVertexCase)
699										: m_caseType == CASETYPE_DEAD_BRANCH_FUNC_CALL			? deadBranchFuncCallCaseStatements			(optimized, isVertexCase)
700										: m_caseType == CASETYPE_UNUSED_VALUE_BASIC				? unusedValueBasicCaseStatements			(optimized, precision, isVertexCase)
701										: m_caseType == CASETYPE_UNUSED_VALUE_LOOP				? unusedValueLoopCaseStatements				(optimized, precision, isVertexCase)
702										: m_caseType == CASETYPE_UNUSED_VALUE_DEAD_BRANCH		? unusedValueDeadBranchCaseStatements		(optimized, precision, isVertexCase)
703										: m_caseType == CASETYPE_UNUSED_VALUE_AFTER_RETURN		? unusedValueAfterReturnCaseStatements		()
704										: m_caseType == CASETYPE_UNUSED_VALUE_MUL_ZERO			? unusedValueMulZeroCaseStatements			(optimized, precision, isVertexCase)
705										: DE_NULL;
706
707		return defaultProgramData(m_caseShaderType, funcDefs, statements);
708	}
709
710private:
711	const CaseType m_caseType;
712
713	static inline string deadBranchSimpleCaseStatements (bool optimized, bool useHeavierWorkload)
714	{
715		const int numLoopIterations = useHeavierWorkload ? 16 : 4;
716
717		return optimized ?	"	value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
718
719						 :	"	value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
720							"	if (2 < 1)\n"
721							"	{\n"
722							"		value = cos(exp(sin(value))*log(sqrt(value)));\n"
723							"		for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
724							"			value = sin(value);\n"
725							"	}\n";
726	}
727
728	static inline string deadBranchComplexCaseStatements (bool optimized, const string& precision, bool useConst, bool useHeavierWorkload)
729	{
730		const string	constMaybe			= useConst ? "const " : "";
731		const int		numLoopIterations	= useHeavierWorkload ? 16 : 4;
732
733		return optimized ?	"	value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
734
735						 :	"	value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
736							"	" + constMaybe + precision + " vec4 a = vec4(sin(0.7), cos(0.2), sin(0.9), abs(-0.5));\n"
737							"	" + constMaybe + precision + " vec4 b = cos(a) + fract(3.0*a.xzzw);\n"
738							"	" + constMaybe + "bvec4 c = bvec4(true, false, true, true);\n"
739							"	" + constMaybe + precision + " vec4 d = exp(b + vec4(c));\n"
740							"	" + constMaybe + precision + " vec4 e = 1.8*abs(sin(sin(inversesqrt(mix(d+a, d+b, a)))));\n"
741							"	if (e.x > 1.0)\n"
742							"	{\n"
743							"		value = cos(exp(sin(value))*log(sqrt(value)));\n"
744							"		for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
745							"			value = sin(value);\n"
746							"	}\n";
747	}
748
749	static inline string deadBranchFuncCallCaseFuncDefs (bool optimized, const string& precision)
750	{
751		return optimized ? "" : precision + " float func (" + precision + " float x) { return 2.0*x; }\n";
752	}
753
754	static inline string deadBranchFuncCallCaseStatements (bool optimized, bool useHeavierWorkload)
755	{
756		const int numLoopIterations = useHeavierWorkload ? 16 : 4;
757
758		return optimized ?	"	value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
759
760						 :	"	value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
761							"	if (func(0.3) > 1.0)\n"
762							"	{\n"
763							"		value = cos(exp(sin(value))*log(sqrt(value)));\n"
764							"		for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
765							"			value = sin(value);\n"
766							"	}\n";
767	}
768
769	static inline string unusedValueBasicCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
770	{
771		const int numSinRows = useHeavierWorkload ? 12 : 1;
772
773		return optimized ?	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
774							"	value = used;\n"
775
776						 :	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
777							"	" + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value))) + used;\n"
778							+ repeat("	unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
779							"	value = used;\n";
780	}
781
782	static inline string unusedValueLoopCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
783	{
784		const int numLoopIterations = useHeavierWorkload ? 16 : 4;
785
786		return optimized ?	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
787							"	value = used;\n"
788
789						 :	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
790							"	" + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value)));\n"
791							"	for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
792							"		unused = sin(unused + used);\n"
793							"	value = used;\n";
794	}
795
796	static inline string unusedValueAfterReturnCaseFuncDefs (bool optimized, const string& precision, bool useHeavierWorkload)
797	{
798		const int numSinRows = useHeavierWorkload ? 12 : 1;
799
800		return optimized ?	precision + " vec4 func (" + precision + " vec4 v)\n"
801							"{\n"
802							"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * v;\n"
803							"	return used;\n"
804							"}\n"
805
806						 :	precision + " vec4 func (" + precision + " vec4 v)\n"
807							"{\n"
808							"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * v;\n"
809							"	" + precision + " vec4 unused = cos(exp(sin(v))*log(sqrt(v)));\n"
810							+ repeat("	unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
811							"	return used;\n"
812							"	used = used*unused;"
813							"	return used;\n"
814							"}\n";
815	}
816
817	static inline string unusedValueAfterReturnCaseStatements (void)
818	{
819		return "	value = func(value);\n";
820	}
821
822	static inline string unusedValueDeadBranchCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
823	{
824		const int numSinRows = useHeavierWorkload ? 12 : 1;
825
826		return optimized ?	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
827							"	value = used;\n"
828
829						 :	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
830							"	" + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value)));\n"
831							+ repeat("	unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
832							"	if (2 < 1)\n"
833							"		used = used*unused;\n"
834							"	value = used;\n";
835	}
836
837	static inline string unusedValueMulZeroCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
838	{
839		const int numSinRows = useHeavierWorkload ? 12 : 1;
840
841		return optimized ?	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
842							"	value = used;\n"
843
844						 :	"	" + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
845							"	" + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value)));\n"
846							+ repeat("	unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
847							"	value = used + unused*float(1-1);\n";
848	}
849};
850
851} // anonymous
852
853ShaderOptimizationTests::ShaderOptimizationTests (Context& context)
854	: TestCaseGroup(context, "optimization", "Shader Optimization Performance Tests")
855{
856}
857
858ShaderOptimizationTests::~ShaderOptimizationTests (void)
859{
860}
861
862void ShaderOptimizationTests::init (void)
863{
864	TestCaseGroup* const unrollGroup					= new TestCaseGroup(m_context, "loop_unrolling",					"Loop Unrolling Cases");
865	TestCaseGroup* const loopInvariantCodeMotionGroup	= new TestCaseGroup(m_context, "loop_invariant_code_motion",		"Loop-Invariant Code Motion Cases");
866	TestCaseGroup* const inlineGroup					= new TestCaseGroup(m_context, "function_inlining",					"Function Inlining Cases");
867	TestCaseGroup* const constantPropagationGroup		= new TestCaseGroup(m_context, "constant_propagation",				"Constant Propagation Cases");
868	TestCaseGroup* const commonSubexpressionGroup		= new TestCaseGroup(m_context, "common_subexpression_elimination",	"Common Subexpression Elimination Cases");
869	TestCaseGroup* const deadCodeEliminationGroup		= new TestCaseGroup(m_context, "dead_code_elimination",				"Dead Code Elimination Cases");
870	addChild(unrollGroup);
871	addChild(loopInvariantCodeMotionGroup);
872	addChild(inlineGroup);
873	addChild(constantPropagationGroup);
874	addChild(commonSubexpressionGroup);
875	addChild(deadCodeEliminationGroup);
876
877	for (int caseShaderTypeI = 0; caseShaderTypeI < CASESHADERTYPE_LAST; caseShaderTypeI++)
878	{
879		const CaseShaderType	caseShaderType			= (CaseShaderType)caseShaderTypeI;
880		const char* const		caseShaderTypeSuffix	= caseShaderType == CASESHADERTYPE_VERTEX		? "_vertex"
881														: caseShaderType == CASESHADERTYPE_FRAGMENT		? "_fragment"
882														: DE_NULL;
883
884		// Loop unrolling cases.
885
886		{
887			static const int loopIterationCounts[] = { 4, 8, 32 };
888
889			for (int caseTypeI = 0; caseTypeI < LoopUnrollCase::CASETYPE_LAST; caseTypeI++)
890			{
891				const LoopUnrollCase::CaseType	caseType		= (LoopUnrollCase::CaseType)caseTypeI;
892				const string					caseTypeName	= caseType == LoopUnrollCase::CASETYPE_INDEPENDENT	? "independent_iterations"
893																: caseType == LoopUnrollCase::CASETYPE_DEPENDENT	? "dependent_iterations"
894																: DE_NULL;
895				const string					caseTypeDesc	= caseType == LoopUnrollCase::CASETYPE_INDEPENDENT	? "loop iterations don't depend on each other"
896																: caseType == LoopUnrollCase::CASETYPE_DEPENDENT	? "loop iterations depend on each other"
897																: DE_NULL;
898
899				for (int loopIterNdx = 0; loopIterNdx < DE_LENGTH_OF_ARRAY(loopIterationCounts); loopIterNdx++)
900				{
901					const int			loopIterations	= loopIterationCounts[loopIterNdx];
902					const string		name			= caseTypeName + "_" + toString(loopIterations) + caseShaderTypeSuffix;
903					const string		description		= toString(loopIterations) + " iterations; " + caseTypeDesc;
904
905					unrollGroup->addChild(new LoopUnrollCase(m_context, name.c_str(), description.c_str(), caseShaderType, caseType, loopIterations));
906				}
907			}
908		}
909
910		// Loop-invariant code motion cases.
911
912		{
913			static const int loopIterationCounts[] = { 4, 8, 32 };
914
915			for (int loopIterNdx = 0; loopIterNdx < DE_LENGTH_OF_ARRAY(loopIterationCounts); loopIterNdx++)
916			{
917				const int		loopIterations	= loopIterationCounts[loopIterNdx];
918				const string	name			= toString(loopIterations) + "_iterations" + caseShaderTypeSuffix;
919
920				loopInvariantCodeMotionGroup->addChild(new LoopInvariantCodeMotionCase(m_context, name.c_str(), "", caseShaderType, loopIterations));
921			}
922		}
923
924		// Function inlining cases.
925
926		{
927			static const int callNestingDepths[] = { 4, 8, 32 };
928
929			for (int nestDepthNdx = 0; nestDepthNdx < DE_LENGTH_OF_ARRAY(callNestingDepths); nestDepthNdx++)
930			{
931				const int		nestingDepth	= callNestingDepths[nestDepthNdx];
932				const string	name			= toString(nestingDepth) + "_nested" + caseShaderTypeSuffix;
933
934				inlineGroup->addChild(new FunctionInliningCase(m_context, name.c_str(), "", caseShaderType, nestingDepth));
935			}
936		}
937
938		// Constant propagation cases.
939
940		for (int caseTypeI = 0; caseTypeI < ConstantPropagationCase::CASETYPE_LAST; caseTypeI++)
941		{
942			const ConstantPropagationCase::CaseType		caseType		= (ConstantPropagationCase::CaseType)caseTypeI;
943			const string								caseTypeName	= caseType == ConstantPropagationCase::CASETYPE_BUILT_IN_FUNCTIONS		? "built_in_functions"
944																		: caseType == ConstantPropagationCase::CASETYPE_ARRAY					? "array"
945																		: caseType == ConstantPropagationCase::CASETYPE_STRUCT					? "struct"
946																		: DE_NULL;
947
948			for (int constantExpressionsOnlyI = 0; constantExpressionsOnlyI <= 1; constantExpressionsOnlyI++)
949			{
950				const bool		constantExpressionsOnly		= constantExpressionsOnlyI != 0;
951				const string	name						= caseTypeName + (constantExpressionsOnly ? "" : "_no_const") + caseShaderTypeSuffix;
952
953				if (caseType == ConstantPropagationCase::CASETYPE_ARRAY && constantExpressionsOnly) // \note See ConstantPropagationCase's constructor for explanation.
954					continue;
955
956				constantPropagationGroup->addChild(new ConstantPropagationCase(m_context, name.c_str(), "", caseShaderType, caseType, constantExpressionsOnly));
957			}
958		}
959
960		// Common subexpression cases.
961
962		for (int caseTypeI = 0; caseTypeI < CommonSubexpressionCase::CASETYPE_LAST; caseTypeI++)
963		{
964			const CommonSubexpressionCase::CaseType		caseType		= (CommonSubexpressionCase::CaseType)caseTypeI;
965
966			const string								caseTypeName	= caseType == CommonSubexpressionCase::CASETYPE_SINGLE_STATEMENT		? "single_statement"
967																		: caseType == CommonSubexpressionCase::CASETYPE_MULTIPLE_STATEMENTS		? "multiple_statements"
968																		: caseType == CommonSubexpressionCase::CASETYPE_STATIC_BRANCH			? "static_branch"
969																		: caseType == CommonSubexpressionCase::CASETYPE_LOOP					? "loop"
970																		: DE_NULL;
971
972			const string								description		= caseType == CommonSubexpressionCase::CASETYPE_SINGLE_STATEMENT		? "A single statement containing multiple uses of same subexpression"
973																		: caseType == CommonSubexpressionCase::CASETYPE_MULTIPLE_STATEMENTS		? "Multiple statements performing same computations"
974																		: caseType == CommonSubexpressionCase::CASETYPE_STATIC_BRANCH			? "Multiple statements including a static conditional"
975																		: caseType == CommonSubexpressionCase::CASETYPE_LOOP					? "Multiple loops performing the same computations"
976																		: DE_NULL;
977
978			commonSubexpressionGroup->addChild(new CommonSubexpressionCase(m_context, (caseTypeName + caseShaderTypeSuffix).c_str(), description.c_str(), caseShaderType, caseType));
979		}
980
981		// Dead code elimination cases.
982
983		for (int caseTypeI = 0; caseTypeI < DeadCodeEliminationCase::CASETYPE_LAST; caseTypeI++)
984		{
985			const DeadCodeEliminationCase::CaseType		caseType				= (DeadCodeEliminationCase::CaseType)caseTypeI;
986			const char* const							caseTypeName			= caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_SIMPLE				? "dead_branch_simple"
987																				: caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX				? "dead_branch_complex"
988																				: caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST	? "dead_branch_complex_no_const"
989																				: caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_FUNC_CALL			? "dead_branch_func_call"
990																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_BASIC				? "unused_value_basic"
991																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_LOOP				? "unused_value_loop"
992																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_DEAD_BRANCH		? "unused_value_dead_branch"
993																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_AFTER_RETURN		? "unused_value_after_return"
994																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_MUL_ZERO			? "unused_value_mul_zero"
995																				: DE_NULL;
996
997			const char* const							caseTypeDescription		= caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_SIMPLE				? "Do computation inside a branch that is never taken (condition is simple false constant expression)"
998																				: caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX				? "Do computation inside a branch that is never taken (condition is complex false constant expression)"
999																				: caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST	? "Do computation inside a branch that is never taken (condition is complex false expression, not constant expression but still compile-time computable)"
1000																				: caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_FUNC_CALL			? "Do computation inside a branch that is never taken (condition is compile-time computable false expression containing function call to a simple inlineable function)"
1001																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_BASIC				? "Compute a value that is never used even statically"
1002																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_LOOP				? "Compute a value, using a loop, that is never used even statically"
1003																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_DEAD_BRANCH		? "Compute a value that is used only inside a statically dead branch"
1004																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_AFTER_RETURN		? "Compute a value that is used only after a return statement"
1005																				: caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_MUL_ZERO			? "Compute a value that is used but multiplied by a zero constant expression"
1006																				: DE_NULL;
1007
1008			deadCodeEliminationGroup->addChild(new DeadCodeEliminationCase(m_context, (string() + caseTypeName + caseShaderTypeSuffix).c_str(), caseTypeDescription, caseShaderType, caseType));
1009		}
1010	}
1011}
1012
1013} // Performance
1014} // gles2
1015} // deqp
1016