Merge changes I5f7e56e3,I7f88e1da into oreo-cts-dev am: 67694b5635 -s ours am: f0c5b...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / performance / es3pShaderOptimizationTests.cpp
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