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