diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/Compiler.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/Compiler.cpp | 1111 |
1 files changed, 711 insertions, 400 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp index 18524ce569..2f411cb58c 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp @@ -4,91 +4,193 @@ // found in the LICENSE file. // -#include "compiler/translator/Cache.h" #include "compiler/translator/Compiler.h" + +#include <sstream> + +#include "angle_gl.h" +#include "common/utilities.h" +#include "compiler/translator/AddAndTrueToLoopCondition.h" +#include "compiler/translator/Cache.h" #include "compiler/translator/CallDAG.h" -#include "compiler/translator/ForLoopUnroll.h" +#include "compiler/translator/ClampPointSize.h" +#include "compiler/translator/CollectVariables.h" +#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h" +#include "compiler/translator/DeferGlobalInitializers.h" +#include "compiler/translator/EmulateGLFragColorBroadcast.h" +#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/Initialize.h" -#include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IsASTDepthBelowLimit.h" +#include "compiler/translator/OutputTree.h" #include "compiler/translator/ParseContext.h" -#include "compiler/translator/PruneEmptyDeclarations.h" +#include "compiler/translator/PruneNoOps.h" #include "compiler/translator/RegenerateStructNames.h" +#include "compiler/translator/RemoveArrayLengthMethod.h" +#include "compiler/translator/RemoveEmptySwitchStatements.h" +#include "compiler/translator/RemoveInvariantDeclaration.h" +#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h" #include "compiler/translator/RemovePow.h" -#include "compiler/translator/RenameFunction.h" +#include "compiler/translator/RemoveUnreferencedVariables.h" #include "compiler/translator/RewriteDoWhile.h" #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" +#include "compiler/translator/SeparateDeclarations.h" +#include "compiler/translator/SimplifyLoopConditions.h" +#include "compiler/translator/SplitSequenceOperator.h" #include "compiler/translator/UnfoldShortCircuitAST.h" +#include "compiler/translator/UseInterfaceBlockFields.h" #include "compiler/translator/ValidateLimitations.h" +#include "compiler/translator/ValidateMaxParameters.h" #include "compiler/translator/ValidateOutputs.h" +#include "compiler/translator/ValidateVaryingLocations.h" #include "compiler/translator/VariablePacker.h" -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/depgraph/DependencyGraphOutput.h" -#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" -#include "compiler/translator/timing/RestrictVertexShaderTiming.h" +#include "compiler/translator/VectorizeVectorScalarArithmetic.h" +#include "compiler/translator/util.h" #include "third_party/compiler/ArrayBoundsClamper.h" -#include "angle_gl.h" -#include "common/utilities.h" + +namespace sh +{ + +namespace +{ + +#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) +void DumpFuzzerCase(char const *const *shaderStrings, + size_t numStrings, + uint32_t type, + uint32_t spec, + uint32_t output, + uint64_t options) +{ + static int fileIndex = 0; + + std::ostringstream o; + o << "corpus/" << fileIndex++ << ".sample"; + std::string s = o.str(); + + // Must match the input format of the fuzzer + FILE *f = fopen(s.c_str(), "w"); + fwrite(&type, sizeof(type), 1, f); + fwrite(&spec, sizeof(spec), 1, f); + fwrite(&output, sizeof(output), 1, f); + fwrite(&options, sizeof(options), 1, f); + + char zero[128 - 20] = {0}; + fwrite(&zero, 128 - 20, 1, f); + + for (size_t i = 0; i < numStrings; i++) + { + fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f); + } + fwrite(&zero, 1, 1, f); + + fclose(f); +} +#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) +} // anonymous namespace bool IsWebGLBasedSpec(ShShaderSpec spec) { - return (spec == SH_WEBGL_SPEC || - spec == SH_CSS_SHADERS_SPEC || - spec == SH_WEBGL2_SPEC); + return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC); } bool IsGLSL130OrNewer(ShShaderOutput output) { - return (output == SH_GLSL_130_OUTPUT || - output == SH_GLSL_140_OUTPUT || - output == SH_GLSL_150_CORE_OUTPUT || - output == SH_GLSL_330_CORE_OUTPUT || - output == SH_GLSL_400_CORE_OUTPUT || - output == SH_GLSL_410_CORE_OUTPUT || - output == SH_GLSL_420_CORE_OUTPUT || - output == SH_GLSL_430_CORE_OUTPUT || - output == SH_GLSL_440_CORE_OUTPUT || - output == SH_GLSL_450_CORE_OUTPUT); + return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT || + output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT || + output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT || + output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT || + output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT); +} + +bool IsGLSL420OrNewer(ShShaderOutput output) +{ + return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT || + output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT); +} + +bool IsGLSL410OrOlder(ShShaderOutput output) +{ + return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT || + output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT || + output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT); +} + +bool RemoveInvariant(sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput outputType, + ShCompileOptions compileOptions) +{ + if ((compileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT) == 0 && + shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType)) + return true; + + if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 && + shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER) + return true; + + return false; } size_t GetGlobalMaxTokenSize(ShShaderSpec spec) { - // WebGL defines a max token legnth of 256, while ES2 leaves max token + // WebGL defines a max token length of 256, while ES2 leaves max token // size undefined. ES3 defines a max size of 1024 characters. switch (spec) { - case SH_WEBGL_SPEC: - case SH_CSS_SHADERS_SPEC: - return 256; - default: - return 1024; + case SH_WEBGL_SPEC: + return 256; + default: + return 1024; } } -namespace { +int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResources &resources) +{ + switch (shaderType) + { + case GL_VERTEX_SHADER: + return resources.MaxVertexUniformVectors; + case GL_FRAGMENT_SHADER: + return resources.MaxFragmentUniformVectors; + + // TODO (jiawei.shao@intel.com): check if we need finer-grained component counting + case GL_COMPUTE_SHADER: + return resources.MaxComputeUniformComponents / 4; + case GL_GEOMETRY_SHADER_OES: + return resources.MaxGeometryUniformComponents / 4; + default: + UNREACHABLE(); + return -1; + } +} + +namespace +{ class TScopedPoolAllocator { public: - TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) + TScopedPoolAllocator(TPoolAllocator *allocator) : mAllocator(allocator) { mAllocator->push(); SetGlobalPoolAllocator(mAllocator); } ~TScopedPoolAllocator() { - SetGlobalPoolAllocator(NULL); + SetGlobalPoolAllocator(nullptr); mAllocator->pop(); } private: - TPoolAllocator* mAllocator; + TPoolAllocator *mAllocator; }; class TScopedSymbolTableLevel { public: - TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) + TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table) { ASSERT(mTable->atBuiltInLevel()); mTable->push(); @@ -100,23 +202,25 @@ class TScopedSymbolTableLevel } private: - TSymbolTable* mTable; + TSymbolTable *mTable; }; int MapSpecToShaderVersion(ShShaderSpec spec) { switch (spec) { - case SH_GLES2_SPEC: - case SH_WEBGL_SPEC: - case SH_CSS_SHADERS_SPEC: - return 100; - case SH_GLES3_SPEC: - case SH_WEBGL2_SPEC: - return 300; - default: - UNREACHABLE(); - return 0; + case SH_GLES2_SPEC: + case SH_WEBGL_SPEC: + return 100; + case SH_GLES3_SPEC: + case SH_WEBGL2_SPEC: + return 300; + case SH_GLES3_1_SPEC: + case SH_WEBGL3_SPEC: + return 310; + default: + UNREACHABLE(); + return 0; } } @@ -130,22 +234,31 @@ TShHandleBase::TShHandleBase() TShHandleBase::~TShHandleBase() { - SetGlobalPoolAllocator(NULL); + SetGlobalPoolAllocator(nullptr); allocator.popAll(); } TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) - : shaderType(type), + : variablesCollected(false), + mGLPositionInitialized(false), + shaderType(type), shaderSpec(spec), outputType(output), maxUniformVectors(0), maxExpressionComplexity(0), maxCallStackDepth(0), + maxFunctionParameters(0), fragmentPrecisionHigh(false), clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), builtInFunctionEmulator(), - mSourcePath(NULL), - mTemporaryIndex(0) + mDiagnostics(infoSink.info), + mSourcePath(nullptr), + mComputeShaderLocalSizeDeclared(false), + mComputeShaderLocalSize(1), + mGeometryShaderMaxVertices(-1), + mGeometryShaderInvocations(0), + mGeometryShaderInputPrimitiveType(EptUndefined), + mGeometryShaderOutputPrimitiveType(EptUndefined) { } @@ -153,7 +266,7 @@ TCompiler::~TCompiler() { } -bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const +bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const { // If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API, // validate loop and indexing as well (to verify that the shader only uses minimal functionality @@ -162,14 +275,15 @@ bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const (compileOptions & SH_VALIDATE_LOOP_INDEXING); } -bool TCompiler::Init(const ShBuiltInResources& resources) +bool TCompiler::Init(const ShBuiltInResources &resources) { shaderVersion = 100; - maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ? - resources.MaxVertexUniformVectors : - resources.MaxFragmentUniformVectors; + + maxUniformVectors = GetMaxUniformVectorsForShaderType(shaderType, resources); + maxExpressionComplexity = resources.MaxExpressionComplexity; - maxCallStackDepth = resources.MaxCallStackDepth; + maxCallStackDepth = resources.MaxCallStackDepth; + maxFunctionParameters = resources.MaxFunctionParameters; SetGlobalPoolAllocator(&allocator); @@ -187,15 +301,16 @@ bool TCompiler::Init(const ShBuiltInResources& resources) return true; } -TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[], - size_t numStrings, int compileOptions) +TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) { return compileTreeImpl(shaderStrings, numStrings, compileOptions); } -TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], - size_t numStrings, - const int compileOptions) +TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], + size_t numStrings, + const ShCompileOptions compileOptions) { clearResults(); @@ -213,191 +328,347 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], ++firstSource; } - TIntermediate intermediate(infoSink); - TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, - compileOptions, true, infoSink, getResources()); + TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec, + compileOptions, true, &mDiagnostics, getResources()); parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh); - SetGlobalParseContext(&parseContext); // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); // Parse shader. - bool success = - (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) && - (parseContext.getTreeRoot() != nullptr); + if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, + &parseContext) != 0) + { + return nullptr; + } + + if (parseContext.getTreeRoot() == nullptr) + { + return nullptr; + } + + setASTMetadata(parseContext); + + 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(); - if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion) + + mPragma = parseContext.pragma(); + symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll); + + mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared(); + mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize(); + + mNumViews = parseContext.getNumViews(); + + // Highp might have been auto-enabled based on shader version + fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); + + if (shaderType == GL_GEOMETRY_SHADER_OES) { - infoSink.info.prefix(EPrefixError); - infoSink.info << "unsupported shader version"; - success = false; + mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType(); + mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType(); + mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices(); + mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations(); } +} - TIntermNode *root = nullptr; +bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, + const TParseContext &parseContext, + ShCompileOptions compileOptions) +{ + // Disallow expressions deemed too complex. + if ((compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY) && !limitExpressionComplexity(root)) + { + return false; + } - if (success) + // 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: + // 1. Empty declarations "int;". + // 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision + // for float, so float literal statements would end up with no precision which is + // invalid ESSL. + // After this empty declarations are not allowed in the AST. + PruneNoOps(root); + + // In case the last case inside a switch statement is a certain type of no-op, GLSL + // compilers in drivers may not accept it. In this case we clean up the dead code from the + // 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 + // state. Relies on that PruneNoOps has already been run. + RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable); + + // Remove empty switch statements - this makes output simpler. + RemoveEmptySwitchStatements(root); + + // Create the function DAG and check there is no recursion + if (!initCallDag(root)) { - mPragma = parseContext.pragma(); - if (mPragma.stdgl.invariantAll) - { - symbolTable.setGlobalInvariant(); - } + return false; + } - root = parseContext.getTreeRoot(); - root = intermediate.postProcess(root); + if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth()) + { + return false; + } - // Highp might have been auto-enabled based on shader version - fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); + // Checks which functions are used and if "main" exists + functionMetadata.clear(); + functionMetadata.resize(mCallDag.size()); + if (!tagUsedFunctions()) + { + return false; + } - // Disallow expressions deemed too complex. - if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) - success = limitExpressionComplexity(root); + if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) + { + pruneUnusedFunctions(root); + } - // Create the function DAG and check there is no recursion - if (success) - success = initCallDag(root); + if (shaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, shaderType)) + { + return false; + } - if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH)) - success = checkCallDepth(); + if (shaderVersion >= 300 && shaderType == GL_FRAGMENT_SHADER && + !ValidateOutputs(root, getExtensionBehavior(), compileResources.MaxDrawBuffers, + &mDiagnostics)) + { + return false; + } - // Checks which functions are used and if "main" exists - if (success) - { - functionMetadata.clear(); - functionMetadata.resize(mCallDag.size()); - success = tagUsedFunctions(); - } + if (shouldRunLoopAndIndexingValidation(compileOptions) && + !ValidateLimitations(root, shaderType, &symbolTable, shaderVersion, &mDiagnostics)) + { + return false; + } - if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) - success = pruneUnusedFunctions(root); + // Fail compilation if precision emulation not supported. + if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision && + !EmulatePrecision::SupportedInLanguage(outputType)) + { + mDiagnostics.globalError("Precision emulation not supported for this output type."); + return false; + } - // Prune empty declarations to work around driver bugs and to keep declaration output simple. - if (success) - PruneEmptyDeclarations(root); + // Clamping uniform array bounds needs to happen after validateLimitations pass. + if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS) + { + arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); + } - if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER) - success = validateOutputs(root); + if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) && + parseContext.isExtensionEnabled(TExtension::OVR_multiview) && + getShaderType() != GL_COMPUTE_SHADER) + { + DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, shaderType, compileOptions, + outputType, &symbolTable); + } - if (success && shouldRunLoopAndIndexingValidation(compileOptions)) - success = validateLimitations(root); + // This pass might emit short circuits so keep it before the short circuit unfolding + if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS) + RewriteDoWhile(root, &symbolTable); - if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) - success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); + if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) + sh::AddAndTrueToLoopCondition(root); - if (success && shaderSpec == SH_CSS_SHADERS_SPEC) - rewriteCSSShader(root); + if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT) + { + UnfoldShortCircuitAST unfoldShortCircuit; + root->traverse(&unfoldShortCircuit); + unfoldShortCircuit.updateTree(); + } - // Unroll for-loop markup needs to happen after validateLimitations pass. - if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) - { - ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex, - shouldRunLoopAndIndexingValidation(compileOptions)); - root->traverse(&marker); - } - if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) - { - ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex, - shouldRunLoopAndIndexingValidation(compileOptions)); - root->traverse(&marker); - if (marker.samplerArrayIndexIsFloatLoopIndex()) - { - infoSink.info.prefix(EPrefixError); - infoSink.info << "sampler array index is float loop index"; - success = false; - } - } + if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT) + { + RemovePow(root); + } - // Built-in function emulation needs to happen after validateLimitations pass. - if (success) - { - initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); - builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); - } + if (compileOptions & SH_REGENERATE_STRUCT_NAMES) + { + RegenerateStructNames gen(&symbolTable, shaderVersion); + root->traverse(&gen); + } - // Clamping uniform array bounds needs to happen after validateLimitations pass. - if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) - arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); + if (shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 && + compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 && + IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers)) + { + EmulateGLFragColorBroadcast(root, compileResources.MaxDrawBuffers, &outputVariables, + &symbolTable, shaderVersion); + } - // gl_Position is always written in compatibility output mode - if (success && shaderType == GL_VERTEX_SHADER && - ((compileOptions & SH_INIT_GL_POSITION) || - (outputType == SH_GLSL_COMPATIBILITY_OUTPUT))) - initializeGLPosition(root); + // Split multi declarations and remove calls to array length(). + // 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. + SimplifyLoopConditions( + root, + IntermNodePatternMatcher::kMultiDeclaration | IntermNodePatternMatcher::kArrayLengthMethod, + &getSymbolTable(), getShaderVersion()); - // This pass might emit short circuits so keep it before the short circuit unfolding - if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)) - RewriteDoWhile(root, getTemporaryIndex()); + // Note that separate declarations need to be run before other AST transformations that + // generate new statements from expressions. + SeparateDeclarations(root); - if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) - { - UnfoldShortCircuitAST unfoldShortCircuit; - root->traverse(&unfoldShortCircuit); - unfoldShortCircuit.updateTree(); - } + SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod, &getSymbolTable(), + getShaderVersion()); + + RemoveArrayLengthMethod(root); + + RemoveUnreferencedVariables(root, &symbolTable); - if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)) + // Built-in function emulation needs to happen after validateLimitations pass. + // TODO(jmadill): Remove global pool allocator. + GetGlobalPoolAllocator()->lock(); + initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); + GetGlobalPoolAllocator()->unlock(); + builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root); + + if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS) + { + ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, &symbolTable); + } + + if (shouldCollectVariables(compileOptions)) + { + ASSERT(!variablesCollected); + CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings, + &outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks, + hashFunction, &symbolTable, shaderVersion, shaderType, extensionBehavior); + collectInterfaceBlocks(); + variablesCollected = true; + if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS) { - RemovePow(root); + useAllMembersInUnusedStandardAndSharedBlocks(root); } - - if (success && shouldCollectVariables(compileOptions)) + if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { - collectVariables(root); - if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) + // 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. + if (!CheckVariablesInPackingLimits(maxUniformVectors, uniforms)) { - success = enforcePackingRestrictions(); - if (!success) - { - infoSink.info.prefix(EPrefixError); - infoSink.info << "too many uniforms"; - } + mDiagnostics.globalError("too many uniforms"); + return false; } - if (success && shaderType == GL_VERTEX_SHADER && - (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) - initializeVaryingsWithoutStaticUse(root); } - - if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) + if (compileOptions & SH_INIT_OUTPUT_VARIABLES) { - ScalarizeVecAndMatConstructorArgs scalarizer( - shaderType, fragmentPrecisionHigh); - root->traverse(&scalarizer); + initializeOutputVariables(root); } + } + + // Removing invariant declarations must be done after collecting variables. + // Otherwise, built-in invariant declarations don't apply. + if (RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions)) + { + RemoveInvariantDeclaration(root); + } + + // 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 + // need to initialize it twice. + if (shaderType == GL_VERTEX_SHADER && !mGLPositionInitialized && + ((compileOptions & SH_INIT_GL_POSITION) || (outputType == SH_GLSL_COMPATIBILITY_OUTPUT))) + { + initializeGLPosition(root); + mGLPositionInitialized = true; + } + + // DeferGlobalInitializers needs to be run before other AST transformations that generate new + // statements from expressions. But it's fine to run DeferGlobalInitializers after the above + // SplitSequenceOperator and RemoveArrayLengthMethod since they only have an effect on the AST + // on ESSL >= 3.00, and the initializers that need to be deferred can only exist in ESSL < 3.00. + bool initializeLocalsAndGlobals = + (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && !IsOutputHLSL(getOutputType()); + bool canUseLoopsToInitialize = !(compileOptions & SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES); + DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize, &symbolTable); - if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES)) + if (initializeLocalsAndGlobals) + { + // Initialize uninitialized local variables. + // In some cases initializing can generate extra statements in the parent block, such as + // when initializing nameless structs or initializing arrays in ESSL 1.00. In that case + // we need to first simplify loop conditions. We've already separated declarations + // earlier, which is also required. If we don't follow the Appendix A limitations, loop + // init statements can declare arrays or nameless structs and have multiple + // declarations. + + if (!shouldRunLoopAndIndexingValidation(compileOptions)) { - RegenerateStructNames gen(symbolTable, shaderVersion); - root->traverse(&gen); + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kArrayDeclaration | + IntermNodePatternMatcher::kNamelessStructDeclaration, + &getSymbolTable(), getShaderVersion()); } + + InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize, + &getSymbolTable()); } - SetGlobalParseContext(NULL); - if (success) - return root; + if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE)) + { + ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable()); + } - return NULL; + if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC) + { + VectorizeVectorScalarArithmetic(root, &getSymbolTable()); + } + + return true; } -bool TCompiler::compile(const char* const shaderStrings[], - size_t numStrings, int compileOptions) +bool TCompiler::compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptionsIn) { +#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) + DumpFuzzerCase(shaderStrings, numStrings, shaderType, shaderSpec, outputType, compileOptionsIn); +#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) + if (numStrings == 0) return true; + ShCompileOptions compileOptions = compileOptionsIn; + + // Apply key workarounds. + if (shouldFlattenPragmaStdglInvariantAll()) + { + // This should be harmless to do in all cases, but for the moment, do it only conditionally. + compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL; + } + TScopedPoolAllocator scopedAlloc(&allocator); - TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); + TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); if (root) { if (compileOptions & SH_INTERMEDIATE_TREE) - TIntermediate::outputTree(root, infoSink.info); + OutputTree(root, infoSink.info); if (compileOptions & SH_OBJECT_CODE) - translate(root, compileOptions); + { + PerformanceDiagnostics perfDiagnostics(&mDiagnostics); + translate(root, compileOptions, &perfDiagnostics); + } // The IntermNode tree doesn't need to be deleted here, since the // memory will be freed in a big chunk by the PoolAllocator. @@ -408,37 +679,38 @@ bool TCompiler::compile(const char* const shaderStrings[], bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) { + if (resources.MaxDrawBuffers < 1) + { + return false; + } + if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1) + { + return false; + } + compileResources = resources; setResourceString(); - assert(symbolTable.isEmpty()); - symbolTable.push(); // COMMON_BUILTINS - symbolTable.push(); // ESSL1_BUILTINS - symbolTable.push(); // ESSL3_BUILTINS - - TPublicType integer; - integer.type = EbtInt; - integer.primarySize = 1; - integer.secondarySize = 1; - integer.array = false; - - TPublicType floatingPoint; - floatingPoint.type = EbtFloat; - floatingPoint.primarySize = 1; - floatingPoint.secondarySize = 1; - floatingPoint.array = false; - - switch(shaderType) - { - case GL_FRAGMENT_SHADER: - symbolTable.setDefaultPrecision(integer, EbpMedium); - break; - case GL_VERTEX_SHADER: - symbolTable.setDefaultPrecision(integer, EbpHigh); - symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); - break; - default: - assert(false && "Language not supported"); + ASSERT(symbolTable.isEmpty()); + symbolTable.push(); // COMMON_BUILTINS + symbolTable.push(); // ESSL1_BUILTINS + symbolTable.push(); // ESSL3_BUILTINS + symbolTable.push(); // ESSL3_1_BUILTINS + symbolTable.push(); // GLSL_BUILTINS + + switch (shaderType) + { + case GL_FRAGMENT_SHADER: + symbolTable.setDefaultPrecision(EbtInt, EbpMedium); + break; + case GL_VERTEX_SHADER: + case GL_COMPUTE_SHADER: + case GL_GEOMETRY_SHADER_OES: + symbolTable.setDefaultPrecision(EbtInt, EbpHigh); + symbolTable.setDefaultPrecision(EbtFloat, EbpHigh); + break; + default: + UNREACHABLE(); } // Set defaults for sampler types that have default precision, even those that are // only available if an extension exists. @@ -447,9 +719,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) initSamplerDefaultPrecision(EbtSamplerCube); // SamplerExternalOES is specified in the extension to have default precision. initSamplerDefaultPrecision(EbtSamplerExternalOES); + // SamplerExternal2DY2YEXT is specified in the extension to have default precision. + initSamplerDefaultPrecision(EbtSamplerExternal2DY2YEXT); // It isn't specified whether Sampler2DRect has default precision. initSamplerDefaultPrecision(EbtSampler2DRect); + symbolTable.setDefaultPrecision(EbtAtomicCounter, EbpHigh); + InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable); IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable); @@ -460,87 +736,149 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType) { ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd); - TPublicType sampler; - sampler.primarySize = 1; - sampler.secondarySize = 1; - sampler.array = false; - sampler.type = samplerType; - symbolTable.setDefaultPrecision(sampler, EbpLow); + symbolTable.setDefaultPrecision(samplerType, EbpLow); } void TCompiler::setResourceString() { std::ostringstream strstream; + + // clang-format off strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs - << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors - << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors - << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits - << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits - << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits - << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors - << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers - << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives - << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external - << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle - << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers - << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh - << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity - << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth - << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended - << ":EXT_frag_depth:" << compileResources.EXT_frag_depth - << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod - << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch - << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch - << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch - << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors - << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors - << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset - << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset - << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers - << ":NV_draw_buffers:" << compileResources.NV_draw_buffers - << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision; + << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors + << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors + << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits + << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits + << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits + << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors + << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers + << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives + << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external + << ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3 + << ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external + << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle + << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers + << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh + << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity + << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth + << ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters + << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended + << ":EXT_frag_depth:" << compileResources.EXT_frag_depth + << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod + << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch + << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch + << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch + << ":OVR_multiview:" << compileResources.OVR_multiview + << ":EXT_YUV_target:" << compileResources.EXT_YUV_target + << ":OES_geometry_shader:" << compileResources.OES_geometry_shader + << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors + << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors + << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset + << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset + << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers + << ":MaxViewsOVR:" << compileResources.MaxViewsOVR + << ":NV_draw_buffers:" << compileResources.NV_draw_buffers + << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision + << ":MinProgramTextureGatherOffset:" << compileResources.MinProgramTextureGatherOffset + << ":MaxProgramTextureGatherOffset:" << compileResources.MaxProgramTextureGatherOffset + << ":MaxImageUnits:" << compileResources.MaxImageUnits + << ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms + << ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms + << ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms + << ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms + << ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources + << ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0] + << ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1] + << ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2] + << ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0] + << ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1] + << ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2] + << ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents + << ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits + << ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters + << ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers + << ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters + << ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters + << ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters + << ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings + << ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers + << ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers + << ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers + << ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize + << ":MaxGeometryUniformComponents:" << compileResources.MaxGeometryUniformComponents + << ":MaxGeometryUniformBlocks:" << compileResources.MaxGeometryUniformBlocks + << ":MaxGeometryInputComponents:" << compileResources.MaxGeometryInputComponents + << ":MaxGeometryOutputComponents:" << compileResources.MaxGeometryOutputComponents + << ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices + << ":MaxGeometryTotalOutputComponents:" << compileResources.MaxGeometryTotalOutputComponents + << ":MaxGeometryTextureImageUnits:" << compileResources.MaxGeometryTextureImageUnits + << ":MaxGeometryAtomicCounterBuffers:" << compileResources.MaxGeometryAtomicCounterBuffers + << ":MaxGeometryAtomicCounters:" << compileResources.MaxGeometryAtomicCounters + << ":MaxGeometryShaderStorageBlocks:" << compileResources.MaxGeometryShaderStorageBlocks + << ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations + << ":MaxGeometryImageUniforms:" << compileResources.MaxGeometryImageUniforms; + // clang-format on builtInResourcesString = strstream.str(); } +void TCompiler::collectInterfaceBlocks() +{ + ASSERT(interfaceBlocks.empty()); + interfaceBlocks.reserve(uniformBlocks.size() + shaderStorageBlocks.size() + inBlocks.size()); + interfaceBlocks.insert(interfaceBlocks.end(), uniformBlocks.begin(), uniformBlocks.end()); + interfaceBlocks.insert(interfaceBlocks.end(), shaderStorageBlocks.begin(), + shaderStorageBlocks.end()); + interfaceBlocks.insert(interfaceBlocks.end(), inBlocks.begin(), inBlocks.end()); +} + void TCompiler::clearResults() { arrayBoundsClamper.Cleanup(); infoSink.info.erase(); infoSink.obj.erase(); infoSink.debug.erase(); + mDiagnostics.resetErrorCount(); attributes.clear(); outputVariables.clear(); uniforms.clear(); - expandedUniforms.clear(); - varyings.clear(); + inputVaryings.clear(); + outputVaryings.clear(); interfaceBlocks.clear(); + uniformBlocks.clear(); + shaderStorageBlocks.clear(); + inBlocks.clear(); + variablesCollected = false; + mGLPositionInitialized = false; + + mNumViews = -1; - builtInFunctionEmulator.Cleanup(); + mGeometryShaderInputPrimitiveType = EptUndefined; + mGeometryShaderOutputPrimitiveType = EptUndefined; + mGeometryShaderInvocations = 0; + mGeometryShaderMaxVertices = -1; + + builtInFunctionEmulator.cleanup(); nameMap.clear(); - mSourcePath = NULL; - mTemporaryIndex = 0; + mSourcePath = nullptr; } bool TCompiler::initCallDag(TIntermNode *root) { mCallDag.clear(); - switch (mCallDag.init(root, &infoSink.info)) + switch (mCallDag.init(root, &mDiagnostics)) { - case CallDAG::INITDAG_SUCCESS: - return true; - case CallDAG::INITDAG_RECURSION: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Function recursion detected"; - return false; - case CallDAG::INITDAG_UNDEFINED: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Unimplemented function detected"; - return false; + case CallDAG::INITDAG_SUCCESS: + return true; + case CallDAG::INITDAG_RECURSION: + case CallDAG::INITDAG_UNDEFINED: + // Error message has already been written out. + ASSERT(mDiagnostics.numErrors() > 0); + return false; } UNREACHABLE(); @@ -553,7 +891,7 @@ bool TCompiler::checkCallDepth() for (size_t i = 0; i < mCallDag.size(); i++) { - int depth = 0; + int depth = 0; auto &record = mCallDag.getRecordFromIndex(i); for (auto &calleeIndex : record.callees) @@ -566,19 +904,19 @@ bool TCompiler::checkCallDepth() if (depth >= maxCallStackDepth) { // Trace back the function chain to have a meaningful info log. - infoSink.info.prefix(EPrefixError); - infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth - << ") with the following call chain: " << record.name; + std::stringstream errorStream; + errorStream << "Call stack too deep (larger than " << maxCallStackDepth + << ") with the following call chain: " << record.name; int currentFunction = static_cast<int>(i); - int currentDepth = depth; + int currentDepth = depth; while (currentFunction != -1) { - infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name; + errorStream << " -> " << mCallDag.getRecordFromIndex(currentFunction).name; int nextFunction = -1; - for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees) + for (auto &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees) { if (depths[calleeIndex] == currentDepth - 1) { @@ -590,6 +928,9 @@ bool TCompiler::checkCallDepth() currentFunction = nextFunction; } + std::string errorStr = errorStream.str(); + mDiagnostics.globalError(errorStr.c_str()); + return false; } } @@ -602,15 +943,14 @@ bool TCompiler::tagUsedFunctions() // Search from main, starting from the end of the DAG as it usually is the root. for (size_t i = mCallDag.size(); i-- > 0;) { - if (mCallDag.getRecordFromIndex(i).name == "main(") + if (mCallDag.getRecordFromIndex(i).name == "main") { internalTagUsedFunction(i); return true; } } - infoSink.info.prefix(EPrefixError); - infoSink.info << "Missing main()\n"; + mDiagnostics.globalError("Missing main()"); return false; } @@ -634,30 +974,35 @@ class TCompiler::UnusedPredicate { public: UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas) - : mCallDag(callDag), - mMetadatas(metadatas) + : mCallDag(callDag), mMetadatas(metadatas) { } - bool operator ()(TIntermNode *node) + bool operator()(TIntermNode *node) { - const TIntermAggregate *asAggregate = node->getAsAggregate(); + const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode(); + const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition(); + + const TFunctionSymbolInfo *functionInfo = nullptr; - if (asAggregate == nullptr) + if (asFunctionDefinition) { - return false; + functionInfo = asFunctionDefinition->getFunctionSymbolInfo(); } - - if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype)) + else if (asFunctionPrototype) + { + functionInfo = asFunctionPrototype->getFunctionSymbolInfo(); + } + if (functionInfo == nullptr) { return false; } - size_t callDagIndex = mCallDag->findIndex(asAggregate); + size_t callDagIndex = mCallDag->findIndex(functionInfo); if (callDagIndex == CallDAG::InvalidIndex) { // This happens only for unimplemented prototypes which are thus unused - ASSERT(asAggregate->getOp() == EOpPrototype); + ASSERT(asFunctionPrototype); return true; } @@ -670,157 +1015,97 @@ class TCompiler::UnusedPredicate const std::vector<FunctionMetadata> *mMetadatas; }; -bool TCompiler::pruneUnusedFunctions(TIntermNode *root) +void TCompiler::pruneUnusedFunctions(TIntermBlock *root) { - TIntermAggregate *rootNode = root->getAsAggregate(); - ASSERT(rootNode != nullptr); - UnusedPredicate isUnused(&mCallDag, &functionMetadata); - TIntermSequence *sequence = rootNode->getSequence(); + TIntermSequence *sequence = root->getSequence(); if (!sequence->empty()) { - sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end()); + sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), + sequence->end()); } - - return true; -} - -bool TCompiler::validateOutputs(TIntermNode* root) -{ - ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers); - root->traverse(&validateOutputs); - return (validateOutputs.validateAndCountErrors(infoSink.info) == 0); -} - -void TCompiler::rewriteCSSShader(TIntermNode* root) -{ - RenameFunction renamer("main(", "css_main("); - root->traverse(&renamer); } -bool TCompiler::validateLimitations(TIntermNode* root) +bool TCompiler::limitExpressionComplexity(TIntermBlock *root) { - ValidateLimitations validate(shaderType, &infoSink.info); - root->traverse(&validate); - return validate.numErrors() == 0; -} - -bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) -{ - if (shaderSpec != SH_WEBGL_SPEC) + if (!IsASTDepthBelowLimit(root, maxExpressionComplexity)) { - infoSink.info << "Timing restrictions must be enforced under the WebGL spec."; + mDiagnostics.globalError("Expression too complex."); return false; } - if (shaderType == GL_FRAGMENT_SHADER) - { - TDependencyGraph graph(root); - - // Output any errors first. - bool success = enforceFragmentShaderTimingRestrictions(graph); - - // Then, output the dependency graph. - if (outputGraph) - { - TDependencyGraphOutput output(infoSink.info); - output.outputAllSpanningTrees(graph); - } - - return success; - } - else - { - return enforceVertexShaderTimingRestrictions(root); - } -} - -bool TCompiler::limitExpressionComplexity(TIntermNode* root) -{ - TMaxDepthTraverser traverser(maxExpressionComplexity+1); - root->traverse(&traverser); - - if (traverser.getMaxDepth() > maxExpressionComplexity) + if (!ValidateMaxParameters(root, maxFunctionParameters)) { - infoSink.info << "Expression too complex."; + mDiagnostics.globalError("Function has too many parameters."); return false; } return true; } -bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) +bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions) { - RestrictFragmentShaderTiming restrictor(infoSink.info); - restrictor.enforceRestrictions(graph); - return restrictor.numErrors() == 0; + return (compileOptions & SH_VARIABLES) != 0; } -bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) +bool TCompiler::wereVariablesCollected() const { - RestrictVertexShaderTiming restrictor(infoSink.info); - restrictor.enforceRestrictions(root); - return restrictor.numErrors() == 0; + return variablesCollected; } -void TCompiler::collectVariables(TIntermNode* root) +void TCompiler::initializeGLPosition(TIntermBlock *root) { - sh::CollectVariables collect(&attributes, - &outputVariables, - &uniforms, - &varyings, - &interfaceBlocks, - hashFunction, - symbolTable); - root->traverse(&collect); - - // This is for enforcePackingRestriction(). - sh::ExpandUniforms(uniforms, &expandedUniforms); + InitVariableList list; + sh::ShaderVariable var(GL_FLOAT_VEC4); + var.name = "gl_Position"; + list.push_back(var); + InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false); } -bool TCompiler::enforcePackingRestrictions() +void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root) { - VariablePacker packer; - return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms); -} + sh::InterfaceBlockList list; -void TCompiler::initializeGLPosition(TIntermNode* root) -{ - InitializeVariables::InitVariableInfoList variables; - InitializeVariables::InitVariableInfo var( - "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4)); - variables.push_back(var); - InitializeVariables initializer(variables); - root->traverse(&initializer); + for (auto block : uniformBlocks) + { + if (!block.staticUse && + (block.layout == sh::BLOCKLAYOUT_STD140 || block.layout == sh::BLOCKLAYOUT_SHARED)) + { + list.push_back(block); + } + } + + sh::UseInterfaceBlockFields(root, list, symbolTable); } -void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) +void TCompiler::initializeOutputVariables(TIntermBlock *root) { - InitializeVariables::InitVariableInfoList variables; - for (size_t ii = 0; ii < varyings.size(); ++ii) + InitVariableList list; + if (shaderType == GL_VERTEX_SHADER || shaderType == GL_GEOMETRY_SHADER_OES) { - const sh::Varying& varying = varyings[ii]; - if (varying.staticUse) - continue; - unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type)); - unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type)); - TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray()); - TString name = varying.name.c_str(); - if (varying.isArray()) + for (auto var : outputVaryings) { - type.setArraySize(varying.arraySize); - name = name.substr(0, name.find_first_of('[')); + list.push_back(var); + if (var.name == "gl_Position") + { + ASSERT(!mGLPositionInitialized); + mGLPositionInitialized = true; + } } - - InitializeVariables::InitVariableInfo var(name, type); - variables.push_back(var); } - InitializeVariables initializer(variables); - root->traverse(&initializer); + else + { + ASSERT(shaderType == GL_FRAGMENT_SHADER); + for (auto var : outputVariables) + { + list.push_back(var); + } + } + InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false); } -const TExtensionBehavior& TCompiler::getExtensionBehavior() const +const TExtensionBehavior &TCompiler::getExtensionBehavior() const { return extensionBehavior; } @@ -830,12 +1115,12 @@ const char *TCompiler::getSourcePath() const return mSourcePath; } -const ShBuiltInResources& TCompiler::getResources() const +const ShBuiltInResources &TCompiler::getResources() const { return compileResources; } -const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const +const ArrayBoundsClamper &TCompiler::getArrayBoundsClamper() const { return arrayBoundsClamper; } @@ -845,14 +1130,40 @@ ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const return clampingStrategy; } -const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const +const BuiltInFunctionEmulator &TCompiler::getBuiltInFunctionEmulator() const { return builtInFunctionEmulator; } -void TCompiler::writePragma() +void TCompiler::writePragma(ShCompileOptions compileOptions) +{ + if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL)) + { + TInfoSinkBase &sink = infoSink.obj; + if (mPragma.stdgl.invariantAll) + sink << "#pragma STDGL invariant(all)\n"; + } +} + +bool TCompiler::isVaryingDefined(const char *varyingName) { - TInfoSinkBase &sink = infoSink.obj; - if (mPragma.stdgl.invariantAll) - sink << "#pragma STDGL invariant(all)\n"; + ASSERT(variablesCollected); + for (size_t ii = 0; ii < inputVaryings.size(); ++ii) + { + if (inputVaryings[ii].name == varyingName) + { + return true; + } + } + for (size_t ii = 0; ii < outputVaryings.size(); ++ii) + { + if (outputVaryings[ii].name == varyingName) + { + return true; + } + } + + return false; } + +} // namespace sh |