Home | History | Annotate | Download | only in performance
      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 
     41 using glu::ShaderProgram;
     42 using tcu::TestLog;
     43 using tcu::Vec4;
     44 using de::SharedPtr;
     45 using de::toString;
     46 
     47 using std::vector;
     48 using std::string;
     49 
     50 namespace deqp
     51 {
     52 
     53 using gls::ShaderPerformanceMeasurer;
     54 
     55 namespace gles3
     56 {
     57 namespace Performance
     58 {
     59 
     60 static 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 
     67 static 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 
     75 static 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 
     92 namespace
     93 {
     94 
     95 enum CaseShaderType
     96 {
     97 	CASESHADERTYPE_VERTEX = 0,
     98 	CASESHADERTYPE_FRAGMENT,
     99 
    100 	CASESHADERTYPE_LAST
    101 };
    102 
    103 static 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 
    115 struct 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.
    126 static 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 
    163 static inline ProgramData defaultProgramData (CaseShaderType shaderType, const string& mainStatements)
    164 {
    165 	return defaultProgramData(shaderType, "", mainStatements);
    166 }
    167 
    168 class ShaderOptimizationCase : public TestCase
    169 {
    170 public:
    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 
    188 protected:
    189 	virtual ProgramData		generateProgramData (bool optimized) const = 0;
    190 
    191 	const CaseShaderType	m_caseShaderType;
    192 
    193 private:
    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 
    220 void 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 
    251 ShaderOptimizationCase::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 
    303 class LoopUnrollCase : public ShaderOptimizationCase
    304 {
    305 public:
    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 
    321 protected:
    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 
    330 private:
    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 
    352 class LoopInvariantCodeMotionCase : public ShaderOptimizationCase
    353 {
    354 public:
    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 
    361 protected:
    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 
    391 private:
    392 	const int m_numLoopIterations;
    393 };
    394 
    395 class FunctionInliningCase : public ShaderOptimizationCase
    396 {
    397 public:
    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 
    404 protected:
    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 
    415 private:
    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 
    429 class ConstantPropagationCase : public ShaderOptimizationCase
    430 {
    431 public:
    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 
    448 protected:
    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 
    461 private:
    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 
    538 class CommonSubexpressionCase : public ShaderOptimizationCase
    539 {
    540 public:
    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 
    557 protected:
    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 
    571 private:
    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 
    674 class DeadCodeEliminationCase : public ShaderOptimizationCase
    675 {
    676 public:
    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 
    698 protected:
    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 
    721 private:
    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 
    864 ShaderOptimizationTests::ShaderOptimizationTests (Context& context)
    865 	: TestCaseGroup(context, "optimization", "Shader Optimization Performance Tests")
    866 {
    867 }
    868 
    869 ShaderOptimizationTests::~ShaderOptimizationTests (void)
    870 {
    871 }
    872 
    873 void 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