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