Commit d10cf69e by Olli Etuaho Committed by Commit Bot

Remove repeated "success" check from compileTreeImpl

This refactoring simplifies the compilation code by putting AST checks and simplification into a separate function. This function will immediately return false when an error is encountered. This is easier to maintain than repeated checking of a "success" boolean. BUG=angleproject:2068 TEST=WebGL conformance tests, angle_unittests, angle_end2end_tests Change-Id: I1ae1c8def3625ada1482104a6babe605405229ef Reviewed-on: https://chromium-review.googlesource.com/750085Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 58f67be0
...@@ -335,21 +335,38 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -335,21 +335,38 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
// Parse shader. // Parse shader.
bool success = (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr,
&parseContext) == 0) && &parseContext) != 0)
(parseContext.getTreeRoot() != nullptr); {
return nullptr;
}
shaderVersion = parseContext.getShaderVersion(); if (parseContext.getTreeRoot() == nullptr)
if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
{ {
mDiagnostics.globalError("unsupported shader version"); return nullptr;
success = false;
} }
TIntermBlock *root = nullptr; setASTMetadata(parseContext);
if (success) if (MapSpecToShaderVersion(shaderSpec) < shaderVersion)
{ {
mDiagnostics.globalError("unsupported shader version");
return nullptr;
}
TIntermBlock *root = parseContext.getTreeRoot();
if (!checkAndSimplifyAST(root, parseContext, compileOptions))
{
return nullptr;
}
return root;
}
void TCompiler::setASTMetadata(const TParseContext &parseContext)
{
shaderVersion = parseContext.getShaderVersion();
mPragma = parseContext.pragma(); mPragma = parseContext.pragma();
symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll); symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
...@@ -358,23 +375,27 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -358,23 +375,27 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mNumViews = parseContext.getNumViews(); mNumViews = parseContext.getNumViews();
root = parseContext.getTreeRoot();
// Highp might have been auto-enabled based on shader version // Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
if (success && shaderType == GL_GEOMETRY_SHADER_OES) if (shaderType == GL_GEOMETRY_SHADER_OES)
{ {
mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType(); mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType();
mGeometryShaderOutputPrimitiveType = mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType();
parseContext.getGeometryShaderOutputPrimitiveType();
mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices(); mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices();
mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations(); mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations();
} }
}
bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
const TParseContext &parseContext,
ShCompileOptions compileOptions)
{
// Disallow expressions deemed too complex. // Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) if ((compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY) && !limitExpressionComplexity(root))
success = limitExpressionComplexity(root); {
return false;
}
// We prune no-ops to work around driver bugs and to keep AST processing and output simple. // We prune no-ops to work around driver bugs and to keep AST processing and output simple.
// The following kinds of no-ops are pruned: // The following kinds of no-ops are pruned:
...@@ -383,7 +404,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -383,7 +404,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
// for float, so float literal statements would end up with no precision which is // for float, so float literal statements would end up with no precision which is
// invalid ESSL. // invalid ESSL.
// After this empty declarations are not allowed in the AST. // After this empty declarations are not allowed in the AST.
if (success)
PruneNoOps(root); PruneNoOps(root);
// In case the last case inside a switch statement is a certain type of no-op, GLSL // In case the last case inside a switch statement is a certain type of no-op, GLSL
...@@ -391,72 +411,75 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -391,72 +411,75 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
// end of switch statements. This is also required because PruneNoOps may have left switch // end of switch statements. This is also required because PruneNoOps may have left switch
// statements that only contained an empty declaration inside the final case in an invalid // statements that only contained an empty declaration inside the final case in an invalid
// state. Relies on that PruneNoOps has already been run. // state. Relies on that PruneNoOps has already been run.
if (success)
RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable); RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable);
// Remove empty switch statements - this makes output simpler. // Remove empty switch statements - this makes output simpler.
if (success)
RemoveEmptySwitchStatements(root); RemoveEmptySwitchStatements(root);
// Create the function DAG and check there is no recursion // Create the function DAG and check there is no recursion
if (success) if (!initCallDag(root))
success = initCallDag(root); {
return false;
}
if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH)) if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth())
success = checkCallDepth(); {
return false;
}
// Checks which functions are used and if "main" exists // Checks which functions are used and if "main" exists
if (success)
{
functionMetadata.clear(); functionMetadata.clear();
functionMetadata.resize(mCallDag.size()); functionMetadata.resize(mCallDag.size());
success = tagUsedFunctions(); if (!tagUsedFunctions())
{
return false;
} }
if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
success = pruneUnusedFunctions(root); {
pruneUnusedFunctions(root);
}
if (success && shaderVersion >= 310) if (shaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, shaderType))
{ {
success = ValidateVaryingLocations(root, &mDiagnostics, shaderType); return false;
} }
if (success && shaderVersion >= 300 && shaderType == GL_FRAGMENT_SHADER) if (shaderVersion >= 300 && shaderType == GL_FRAGMENT_SHADER &&
!ValidateOutputs(root, getExtensionBehavior(), compileResources.MaxDrawBuffers,
&mDiagnostics))
{ {
success = ValidateOutputs(root, getExtensionBehavior(), compileResources.MaxDrawBuffers, return false;
&mDiagnostics);
} }
if (success && shouldRunLoopAndIndexingValidation(compileOptions)) if (shouldRunLoopAndIndexingValidation(compileOptions) &&
success = !ValidateLimitations(root, shaderType, &symbolTable, shaderVersion, &mDiagnostics))
ValidateLimitations(root, shaderType, &symbolTable, shaderVersion, &mDiagnostics); {
return false;
}
// Fail compilation if precision emulation not supported. // Fail compilation if precision emulation not supported.
if (success && getResources().WEBGL_debug_shader_precision && if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision &&
getPragma().debugShaderPrecision) !EmulatePrecision::SupportedInLanguage(outputType))
{
if (!EmulatePrecision::SupportedInLanguage(outputType))
{ {
mDiagnostics.globalError("Precision emulation not supported for this output type."); mDiagnostics.globalError("Precision emulation not supported for this output type.");
success = false; return false;
}
} }
// Built-in function emulation needs to happen after validateLimitations pass. // Built-in function emulation needs to happen after validateLimitations pass.
if (success)
{
// TODO(jmadill): Remove global pool allocator. // TODO(jmadill): Remove global pool allocator.
GetGlobalPoolAllocator()->lock(); GetGlobalPoolAllocator()->lock();
initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
GetGlobalPoolAllocator()->unlock(); GetGlobalPoolAllocator()->unlock();
builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root); builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root);
}
// Clamping uniform array bounds needs to happen after validateLimitations pass. // Clamping uniform array bounds needs to happen after validateLimitations pass.
if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)
{
arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
}
if (success && (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) && if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
parseContext.isExtensionEnabled(TExtension::OVR_multiview) && parseContext.isExtensionEnabled(TExtension::OVR_multiview) &&
getShaderType() != GL_COMPUTE_SHADER) getShaderType() != GL_COMPUTE_SHADER)
{ {
...@@ -465,31 +488,30 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -465,31 +488,30 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
} }
// This pass might emit short circuits so keep it before the short circuit unfolding // This pass might emit short circuits so keep it before the short circuit unfolding
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)) if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)
RewriteDoWhile(root, &symbolTable); RewriteDoWhile(root, &symbolTable);
if (success && (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION)) if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION)
sh::AddAndTrueToLoopCondition(root); sh::AddAndTrueToLoopCondition(root);
if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)
{ {
UnfoldShortCircuitAST unfoldShortCircuit; UnfoldShortCircuitAST unfoldShortCircuit;
root->traverse(&unfoldShortCircuit); root->traverse(&unfoldShortCircuit);
unfoldShortCircuit.updateTree(); unfoldShortCircuit.updateTree();
} }
if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)) if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)
{ {
RemovePow(root); RemovePow(root);
} }
if (success && shouldCollectVariables(compileOptions)) if (shouldCollectVariables(compileOptions))
{ {
ASSERT(!variablesCollected); ASSERT(!variablesCollected);
CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings, CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings,
&outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks, &outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks,
hashFunction, &symbolTable, shaderVersion, shaderType, hashFunction, &symbolTable, shaderVersion, shaderType, extensionBehavior);
extensionBehavior);
collectInterfaceBlocks(); collectInterfaceBlocks();
variablesCollected = true; variablesCollected = true;
if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS) if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
...@@ -500,13 +522,13 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -500,13 +522,13 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
{ {
// Returns true if, after applying the packing rules in the GLSL ES 1.00.17 spec // Returns true if, after applying the packing rules in the GLSL ES 1.00.17 spec
// Appendix A, section 7, the shader does not use too many uniforms. // Appendix A, section 7, the shader does not use too many uniforms.
success = CheckVariablesInPackingLimits(maxUniformVectors, uniforms); if (!CheckVariablesInPackingLimits(maxUniformVectors, uniforms))
if (!success)
{ {
mDiagnostics.globalError("too many uniforms"); mDiagnostics.globalError("too many uniforms");
return false;
} }
} }
if (success && (compileOptions & SH_INIT_OUTPUT_VARIABLES)) if (compileOptions & SH_INIT_OUTPUT_VARIABLES)
{ {
initializeOutputVariables(root); initializeOutputVariables(root);
} }
...@@ -515,9 +537,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -515,9 +537,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
// gl_Position is always written in compatibility output mode. // gl_Position is always written in compatibility output mode.
// It may have been already initialized among other output variables, in that case we don't // It may have been already initialized among other output variables, in that case we don't
// need to initialize it twice. // need to initialize it twice.
if (success && shaderType == GL_VERTEX_SHADER && !mGLPositionInitialized && if (shaderType == GL_VERTEX_SHADER && !mGLPositionInitialized &&
((compileOptions & SH_INIT_GL_POSITION) || ((compileOptions & SH_INIT_GL_POSITION) || (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
(outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
{ {
initializeGLPosition(root); initializeGLPosition(root);
mGLPositionInitialized = true; mGLPositionInitialized = true;
...@@ -525,22 +546,23 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -525,22 +546,23 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
// Removing invariant declarations must be done after collecting variables. // Removing invariant declarations must be done after collecting variables.
// Otherwise, built-in invariant declarations don't apply. // Otherwise, built-in invariant declarations don't apply.
if (success && RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions)) if (RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions))
{
sh::RemoveInvariantDeclaration(root); sh::RemoveInvariantDeclaration(root);
}
if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
{ {
ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, &symbolTable);
&symbolTable);
} }
if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES)) if (compileOptions & SH_REGENERATE_STRUCT_NAMES)
{ {
RegenerateStructNames gen(&symbolTable, shaderVersion); RegenerateStructNames gen(&symbolTable, shaderVersion);
root->traverse(&gen); root->traverse(&gen);
} }
if (success && shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 && if (shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 &&
compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 && compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 &&
IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers)) IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers))
{ {
...@@ -548,32 +570,26 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -548,32 +570,26 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
&symbolTable, shaderVersion); &symbolTable, shaderVersion);
} }
if (success)
{
DeferGlobalInitializers(root, needToInitializeGlobalsInAST(), &symbolTable); DeferGlobalInitializers(root, needToInitializeGlobalsInAST(), &symbolTable);
}
// Split multi declarations and remove calls to array length(). // Split multi declarations and remove calls to array length().
if (success)
{
// Note that SimplifyLoopConditions needs to be run before any other AST transformations // Note that SimplifyLoopConditions needs to be run before any other AST transformations
// that may need to generate new statements from loop conditions or loop expressions. // that may need to generate new statements from loop conditions or loop expressions.
SimplifyLoopConditions(root, SimplifyLoopConditions(
IntermNodePatternMatcher::kMultiDeclaration | root,
IntermNodePatternMatcher::kArrayLengthMethod, IntermNodePatternMatcher::kMultiDeclaration | IntermNodePatternMatcher::kArrayLengthMethod,
&getSymbolTable(), getShaderVersion()); &getSymbolTable(), getShaderVersion());
// Note that separate declarations need to be run before other AST transformations that // Note that separate declarations need to be run before other AST transformations that
// generate new statements from expressions. // generate new statements from expressions.
SeparateDeclarations(root); SeparateDeclarations(root);
SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod, SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod, &getSymbolTable(),
&getSymbolTable(), getShaderVersion()); getShaderVersion());
RemoveArrayLengthMethod(root); RemoveArrayLengthMethod(root);
}
if (success && (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType()) if ((compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType())
{ {
// Initialize uninitialized local variables. // Initialize uninitialized local variables.
// In some cases initializing can generate extra statements in the parent block, such as // In some cases initializing can generate extra statements in the parent block, such as
...@@ -593,17 +609,12 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -593,17 +609,12 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
InitializeUninitializedLocals(root, getShaderVersion()); InitializeUninitializedLocals(root, getShaderVersion());
} }
if (success && getShaderType() == GL_VERTEX_SHADER && if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE))
(compileOptions & SH_CLAMP_POINT_SIZE))
{ {
ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable()); ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable());
} }
}
if (success)
return root;
return nullptr; return true;
} }
bool TCompiler::compile(const char *const shaderStrings[], bool TCompiler::compile(const char *const shaderStrings[],
...@@ -985,7 +996,7 @@ class TCompiler::UnusedPredicate ...@@ -985,7 +996,7 @@ class TCompiler::UnusedPredicate
const std::vector<FunctionMetadata> *mMetadatas; const std::vector<FunctionMetadata> *mMetadatas;
}; };
bool TCompiler::pruneUnusedFunctions(TIntermBlock *root) void TCompiler::pruneUnusedFunctions(TIntermBlock *root)
{ {
UnusedPredicate isUnused(&mCallDag, &functionMetadata); UnusedPredicate isUnused(&mCallDag, &functionMetadata);
TIntermSequence *sequence = root->getSequence(); TIntermSequence *sequence = root->getSequence();
...@@ -995,8 +1006,6 @@ bool TCompiler::pruneUnusedFunctions(TIntermBlock *root) ...@@ -995,8 +1006,6 @@ bool TCompiler::pruneUnusedFunctions(TIntermBlock *root)
sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused),
sequence->end()); sequence->end());
} }
return true;
} }
bool TCompiler::limitExpressionComplexity(TIntermBlock *root) bool TCompiler::limitExpressionComplexity(TIntermBlock *root)
......
...@@ -30,6 +30,7 @@ namespace sh ...@@ -30,6 +30,7 @@ namespace sh
{ {
class TCompiler; class TCompiler;
class TParseContext;
#ifdef ANGLE_ENABLE_HLSL #ifdef ANGLE_ENABLE_HLSL
class TranslatorHLSL; class TranslatorHLSL;
#endif // ANGLE_ENABLE_HLSL #endif // ANGLE_ENABLE_HLSL
...@@ -218,12 +219,21 @@ class TCompiler : public TShHandleBase ...@@ -218,12 +219,21 @@ class TCompiler : public TShHandleBase
// Removes unused function declarations and prototypes from the AST // Removes unused function declarations and prototypes from the AST
class UnusedPredicate; class UnusedPredicate;
bool pruneUnusedFunctions(TIntermBlock *root); void pruneUnusedFunctions(TIntermBlock *root);
TIntermBlock *compileTreeImpl(const char *const shaderStrings[], TIntermBlock *compileTreeImpl(const char *const shaderStrings[],
size_t numStrings, size_t numStrings,
const ShCompileOptions compileOptions); const ShCompileOptions compileOptions);
// Fetches and stores shader metadata that is not stored within the AST itself, such as shader
// version.
void setASTMetadata(const TParseContext &parseContext);
// Does checks that need to be run after parsing is complete and returns true if they pass.
bool checkAndSimplifyAST(TIntermBlock *root,
const TParseContext &parseContext,
ShCompileOptions compileOptions);
sh::GLenum shaderType; sh::GLenum shaderType;
ShShaderSpec shaderSpec; ShShaderSpec shaderSpec;
ShShaderOutput outputType; ShShaderOutput outputType;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment