summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp461
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h62
-rw-r--r--gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp112
-rw-r--r--gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h50
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BaseTypes.h1086
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp162
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h80
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp284
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h40
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp173
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h27
-rw-r--r--gfx/angle/checkout/src/compiler/translator/CallDAG.cpp316
-rw-r--r--gfx/angle/checkout/src/compiler/translator/CallDAG.h77
-rw-r--r--gfx/angle/checkout/src/compiler/translator/CodeGen.cpp75
-rw-r--r--gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp970
-rw-r--r--gfx/angle/checkout/src/compiler/translator/CollectVariables.h36
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Common.h151
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Compiler.cpp1478
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Compiler.h304
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp772
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ConstantUnion.h119
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Declarator.cpp33
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Declarator.h49
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp106
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Diagnostics.h67
-rw-r--r--gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp204
-rw-r--r--gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h59
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp101
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h65
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp104
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h44
-rw-r--r--gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp76
-rw-r--r--gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h30
-rw-r--r--gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp179
-rw-r--r--gfx/angle/checkout/src/compiler/translator/FunctionLookup.h60
-rw-r--r--gfx/angle/checkout/src/compiler/translator/HashNames.cpp94
-rw-r--r--gfx/angle/checkout/src/compiler/translator/HashNames.h33
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp371
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h96
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp69
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ImmutableString.h144
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp63
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h80
-rw-r--r--gfx/angle/checkout/src/compiler/translator/InfoSink.cpp82
-rw-r--r--gfx/angle/checkout/src/compiler/translator/InfoSink.h129
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Initialize.cpp117
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Initialize.h28
-rw-r--r--gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp33
-rw-r--r--gfx/angle/checkout/src/compiler/translator/InitializeDll.h15
-rw-r--r--gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h13
-rw-r--r--gfx/angle/checkout/src/compiler/translator/IntermNode.cpp3787
-rw-r--r--gfx/angle/checkout/src/compiler/translator/IntermNode.h936
-rw-r--r--gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp37
-rw-r--r--gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h20
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Operator.cpp420
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Operator.h268
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp46
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputESSL.h37
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp118
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputGLSL.h36
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp1433
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h125
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp3568
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputHLSL.h279
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputTree.cpp699
-rw-r--r--gfx/angle/checkout/src/compiler/translator/OutputTree.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ParseContext.cpp6100
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ParseContext.h667
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h66
-rw-r--r--gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp40
-rw-r--r--gfx/angle/checkout/src/compiler/translator/PoolAlloc.h102
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Pragma.h31
-rw-r--r--gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp829
-rw-r--r--gfx/angle/checkout/src/compiler/translator/QualifierTypes.h200
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp790
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h139
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Severity.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp675
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp435
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h94
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp762
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h92
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp582
-rw-r--r--gfx/angle/checkout/src/compiler/translator/StaticType.h202
-rw-r--r--gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp591
-rw-r--r--gfx/angle/checkout/src/compiler/translator/StructureHLSL.h98
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Symbol.cpp238
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Symbol.h277
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp417
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolTable.h201
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp20959
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h78
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp27
-rw-r--r--gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h58
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp1554
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h77
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp184
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h35
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp334
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h38
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp204
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h51
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Types.cpp970
-rw-r--r--gfx/angle/checkout/src/compiler/translator/Types.h464
-rw-r--r--gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp1108
-rw-r--r--gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h135
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp251
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateAST.h58
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp141
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h20
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp442
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h26
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp30
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h21
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp184
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h30
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp315
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h27
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp179
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h25
-rw-r--r--gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp413
-rw-r--r--gfx/angle/checkout/src/compiler/translator/VariablePacker.h32
-rw-r--r--gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp149
-rw-r--r--gfx/angle/checkout/src/compiler/translator/VersionGLSL.h76
-rw-r--r--gfx/angle/checkout/src/compiler/translator/blocklayout.cpp606
-rw-r--r--gfx/angle/checkout/src/compiler/translator/blocklayout.h302
-rw-r--r--gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp167
-rw-r--r--gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h68
-rw-r--r--gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp881
-rw-r--r--gfx/angle/checkout/src/compiler/translator/glslang.h24
-rw-r--r--gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp4108
-rw-r--r--gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp5201
-rw-r--r--gfx/angle/checkout/src/compiler/translator/glslang_tab.h284
-rw-r--r--gfx/angle/checkout/src/compiler/translator/length_limits.h26
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp58
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h20
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp58
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp228
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp107
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h23
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp54
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h24
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp48
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp186
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h48
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp167
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h33
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp131
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h31
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp213
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h47
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp776
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h85
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp145
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h29
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp115
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h24
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp311
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h56
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp101
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h25
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp127
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h19
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp166
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h25
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp167
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h28
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp87
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h40
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp83
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h34
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp543
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h28
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp43
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h18
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp101
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp270
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h27
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp371
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h24
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp462
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h21
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp182
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h38
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp89
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h30
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp144
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h23
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp120
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp411
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h32
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp92
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h28
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp699
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h31
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp154
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h28
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp92
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h19
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp110
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h20
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp226
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h27
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp84
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp90
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h29
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp78
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h26
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp129
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h23
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp299
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h24
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp163
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h25
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp74
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp193
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h25
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp104
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h30
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp287
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h25
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp126
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h1373
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp32
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h21
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp54
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h24
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp53
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h23
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp204
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h80
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp291
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h76
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp638
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h322
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h56
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp136
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h21
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp64
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h27
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp116
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h23
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h22
-rw-r--r--gfx/angle/checkout/src/compiler/translator/util.cpp936
-rw-r--r--gfx/angle/checkout/src/compiler/translator/util.h92
253 files changed, 90338 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp
new file mode 100644
index 0000000000..e2d4df3d5a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -0,0 +1,461 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Analysis of the AST needed for HLSL generation
+
+#include "compiler/translator/ASTMetadataHLSL.h"
+
+#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// Class used to traverse the AST of a function definition, checking if the
+// function uses a gradient, and writing the set of control flow using gradients.
+// It assumes that the analysis has already been made for the function's
+// callees.
+class PullGradient : public TIntermTraverser
+{
+ public:
+ PullGradient(MetadataList *metadataList, size_t index, const CallDAG &dag)
+ : TIntermTraverser(true, false, true),
+ mMetadataList(metadataList),
+ mMetadata(&(*metadataList)[index]),
+ mIndex(index),
+ mDag(dag)
+ {
+ ASSERT(index < metadataList->size());
+
+ // ESSL 100 builtin gradient functions
+ mGradientBuiltinFunctions.insert(ImmutableString("texture2D"));
+ mGradientBuiltinFunctions.insert(ImmutableString("texture2DProj"));
+ mGradientBuiltinFunctions.insert(ImmutableString("textureCube"));
+
+ // ESSL 300 builtin gradient functions
+ mGradientBuiltinFunctions.insert(ImmutableString("texture"));
+ mGradientBuiltinFunctions.insert(ImmutableString("textureProj"));
+ mGradientBuiltinFunctions.insert(ImmutableString("textureOffset"));
+ mGradientBuiltinFunctions.insert(ImmutableString("textureProjOffset"));
+
+ // ESSL 310 doesn't add builtin gradient functions
+ }
+
+ void traverse(TIntermFunctionDefinition *node)
+ {
+ node->traverse(this);
+ ASSERT(mParents.empty());
+ }
+
+ // Called when a gradient operation or a call to a function using a gradient is found.
+ void onGradient()
+ {
+ mMetadata->mUsesGradient = true;
+ // Mark the latest control flow as using a gradient.
+ if (!mParents.empty())
+ {
+ mMetadata->mControlFlowsContainingGradient.insert(mParents.back());
+ }
+ }
+
+ void visitControlFlow(Visit visit, TIntermNode *node)
+ {
+ if (visit == PreVisit)
+ {
+ mParents.push_back(node);
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mParents.back() == node);
+ mParents.pop_back();
+ // A control flow's using a gradient means its parents are too.
+ if (mMetadata->mControlFlowsContainingGradient.count(node) > 0 && !mParents.empty())
+ {
+ mMetadata->mControlFlowsContainingGradient.insert(mParents.back());
+ }
+ }
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop) override
+ {
+ visitControlFlow(visit, loop);
+ return true;
+ }
+
+ bool visitIfElse(Visit visit, TIntermIfElse *ifElse) override
+ {
+ visitControlFlow(visit, ifElse);
+ return true;
+ }
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override
+ {
+ if (visit == PreVisit)
+ {
+ switch (node->getOp())
+ {
+ case EOpDFdx:
+ case EOpDFdy:
+ case EOpFwidth:
+ onGradient();
+ break;
+ default:
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit)
+ {
+ if (node->getOp() == EOpCallFunctionInAST)
+ {
+ size_t calleeIndex = mDag.findIndex(node->getFunction()->uniqueId());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+
+ if ((*mMetadataList)[calleeIndex].mUsesGradient)
+ {
+ onGradient();
+ }
+ }
+ else if (node->getOp() == EOpCallBuiltInFunction)
+ {
+ if (mGradientBuiltinFunctions.find(node->getFunction()->name()) !=
+ mGradientBuiltinFunctions.end())
+ {
+ onGradient();
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ // Contains a stack of the control flow nodes that are parents of the node being
+ // currently visited. It is used to mark control flows using a gradient.
+ std::vector<TIntermNode *> mParents;
+
+ // A list of builtin functions that use gradients
+ std::set<ImmutableString> mGradientBuiltinFunctions;
+};
+
+// Traverses the AST of a function definition to compute the the discontinuous loops
+// and the if statements containing gradient loops. It assumes that the gradient loops
+// (loops that contain a gradient) have already been computed and that it has already
+// traversed the current function's callees.
+class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
+{
+ public:
+ PullComputeDiscontinuousAndGradientLoops(MetadataList *metadataList,
+ size_t index,
+ const CallDAG &dag)
+ : TIntermTraverser(true, false, true),
+ mMetadataList(metadataList),
+ mMetadata(&(*metadataList)[index]),
+ mIndex(index),
+ mDag(dag)
+ {}
+
+ void traverse(TIntermFunctionDefinition *node)
+ {
+ node->traverse(this);
+ ASSERT(mLoopsAndSwitches.empty());
+ ASSERT(mIfs.empty());
+ }
+
+ // Called when traversing a gradient loop or a call to a function with a
+ // gradient loop in its call graph.
+ void onGradientLoop()
+ {
+ mMetadata->mHasGradientLoopInCallGraph = true;
+ // Mark the latest if as using a discontinuous loop.
+ if (!mIfs.empty())
+ {
+ mMetadata->mIfsContainingGradientLoop.insert(mIfs.back());
+ }
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop) override
+ {
+ if (visit == PreVisit)
+ {
+ mLoopsAndSwitches.push_back(loop);
+
+ if (mMetadata->hasGradientInCallGraph(loop))
+ {
+ onGradientLoop();
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mLoopsAndSwitches.back() == loop);
+ mLoopsAndSwitches.pop_back();
+ }
+
+ return true;
+ }
+
+ bool visitIfElse(Visit visit, TIntermIfElse *node) override
+ {
+ if (visit == PreVisit)
+ {
+ mIfs.push_back(node);
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mIfs.back() == node);
+ mIfs.pop_back();
+ // An if using a discontinuous loop means its parents ifs are also discontinuous.
+ if (mMetadata->mIfsContainingGradientLoop.count(node) > 0 && !mIfs.empty())
+ {
+ mMetadata->mIfsContainingGradientLoop.insert(mIfs.back());
+ }
+ }
+
+ return true;
+ }
+
+ bool visitBranch(Visit visit, TIntermBranch *node) override
+ {
+ if (visit == PreVisit)
+ {
+ switch (node->getFlowOp())
+ {
+ case EOpBreak:
+ {
+ ASSERT(!mLoopsAndSwitches.empty());
+ TIntermLoop *loop = mLoopsAndSwitches.back()->getAsLoopNode();
+ if (loop != nullptr)
+ {
+ mMetadata->mDiscontinuousLoops.insert(loop);
+ }
+ }
+ break;
+ case EOpContinue:
+ {
+ ASSERT(!mLoopsAndSwitches.empty());
+ TIntermLoop *loop = nullptr;
+ size_t i = mLoopsAndSwitches.size();
+ while (loop == nullptr && i > 0)
+ {
+ --i;
+ loop = mLoopsAndSwitches.at(i)->getAsLoopNode();
+ }
+ ASSERT(loop != nullptr);
+ mMetadata->mDiscontinuousLoops.insert(loop);
+ }
+ break;
+ case EOpKill:
+ case EOpReturn:
+ // A return or discard jumps out of all the enclosing loops
+ if (!mLoopsAndSwitches.empty())
+ {
+ for (TIntermNode *intermNode : mLoopsAndSwitches)
+ {
+ TIntermLoop *loop = intermNode->getAsLoopNode();
+ if (loop)
+ {
+ mMetadata->mDiscontinuousLoops.insert(loop);
+ }
+ }
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST)
+ {
+ size_t calleeIndex = mDag.findIndex(node->getFunction()->uniqueId());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+
+ if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph)
+ {
+ onGradientLoop();
+ }
+ }
+
+ return true;
+ }
+
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override
+ {
+ if (visit == PreVisit)
+ {
+ mLoopsAndSwitches.push_back(node);
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mLoopsAndSwitches.back() == node);
+ mLoopsAndSwitches.pop_back();
+ }
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ std::vector<TIntermNode *> mLoopsAndSwitches;
+ std::vector<TIntermIfElse *> mIfs;
+};
+
+// Tags all the functions called in a discontinuous loop
+class PushDiscontinuousLoops : public TIntermTraverser
+{
+ public:
+ PushDiscontinuousLoops(MetadataList *metadataList, size_t index, const CallDAG &dag)
+ : TIntermTraverser(true, true, true),
+ mMetadataList(metadataList),
+ mMetadata(&(*metadataList)[index]),
+ mIndex(index),
+ mDag(dag),
+ mNestedDiscont(mMetadata->mCalledInDiscontinuousLoop ? 1 : 0)
+ {}
+
+ void traverse(TIntermFunctionDefinition *node)
+ {
+ node->traverse(this);
+ ASSERT(mNestedDiscont == (mMetadata->mCalledInDiscontinuousLoop ? 1 : 0));
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop) override
+ {
+ bool isDiscontinuous = mMetadata->mDiscontinuousLoops.count(loop) > 0;
+
+ if (visit == PreVisit && isDiscontinuous)
+ {
+ mNestedDiscont++;
+ }
+ else if (visit == PostVisit && isDiscontinuous)
+ {
+ mNestedDiscont--;
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ switch (node->getOp())
+ {
+ case EOpCallFunctionInAST:
+ if (visit == PreVisit && mNestedDiscont > 0)
+ {
+ size_t calleeIndex = mDag.findIndex(node->getFunction()->uniqueId());
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+
+ (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ int mNestedDiscont;
+};
+} // namespace
+
+bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node)
+{
+ return mControlFlowsContainingGradient.count(node) > 0;
+}
+
+bool ASTMetadataHLSL::hasGradientLoop(TIntermIfElse *node)
+{
+ return mIfsContainingGradientLoop.count(node) > 0;
+}
+
+MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag)
+{
+ MetadataList metadataList(callDag.size());
+
+ // Compute all the information related to when gradient operations are used.
+ // We want to know for each function and control flow operation if they have
+ // a gradient operation in their call graph (shortened to "using a gradient"
+ // in the rest of the file).
+ //
+ // This computation is logically split in three steps:
+ // 1 - For each function compute if it uses a gradient in its body, ignoring
+ // calls to other user-defined functions.
+ // 2 - For each function determine if it uses a gradient in its call graph,
+ // using the result of step 1 and the CallDAG to know its callees.
+ // 3 - For each control flow statement of each function, check if it uses a
+ // gradient in the function's body, or if it calls a user-defined function that
+ // uses a gradient.
+ //
+ // We take advantage of the call graph being a DAG and instead compute 1, 2 and 3
+ // for leaves first, then going down the tree. This is correct because 1 doesn't
+ // depend on other functions, and 2 and 3 depend only on callees.
+ for (size_t i = 0; i < callDag.size(); i++)
+ {
+ PullGradient pull(&metadataList, i, callDag);
+ pull.traverse(callDag.getRecordFromIndex(i).node);
+ }
+
+ // Compute which loops are discontinuous and which function are called in
+ // these loops. The same way computing gradient usage is a "pull" process,
+ // computing "bing used in a discont. loop" is a push process. However we also
+ // need to know what ifs have a discontinuous loop inside so we do the same type
+ // of callgraph analysis as for the gradient.
+
+ // First compute which loops are discontinuous (no specific order) and pull
+ // the ifs and functions using a gradient loop.
+ for (size_t i = 0; i < callDag.size(); i++)
+ {
+ PullComputeDiscontinuousAndGradientLoops pull(&metadataList, i, callDag);
+ pull.traverse(callDag.getRecordFromIndex(i).node);
+ }
+
+ // Then push the information to callees, either from the a local discontinuous
+ // loop or from the caller being called in a discontinuous loop already
+ for (size_t i = callDag.size(); i-- > 0;)
+ {
+ PushDiscontinuousLoops push(&metadataList, i, callDag);
+ push.traverse(callDag.getRecordFromIndex(i).node);
+ }
+
+ // We create "Lod0" version of functions with the gradient operations replaced
+ // by non-gradient operations so that the D3D compiler is happier with discont
+ // loops.
+ for (auto &metadata : metadataList)
+ {
+ metadata.mNeedsLod0 = metadata.mCalledInDiscontinuousLoop && metadata.mUsesGradient;
+ }
+
+ return metadataList;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h
new file mode 100644
index 0000000000..da00faabeb
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h
@@ -0,0 +1,62 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Defines analyses of the AST needed for HLSL generation
+
+#ifndef COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
+#define COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
+
+#include <set>
+#include <vector>
+
+namespace sh
+{
+
+class CallDAG;
+class TIntermNode;
+class TIntermIfElse;
+class TIntermLoop;
+
+struct ASTMetadataHLSL
+{
+ ASTMetadataHLSL()
+ : mUsesGradient(false),
+ mCalledInDiscontinuousLoop(false),
+ mHasGradientLoopInCallGraph(false),
+ mNeedsLod0(false)
+ {}
+
+ // Here "something uses a gradient" means here that it either contains a
+ // gradient operation, or a call to a function that uses a gradient.
+ bool hasGradientInCallGraph(TIntermLoop *node);
+ bool hasGradientLoop(TIntermIfElse *node);
+
+ // Does the function use a gradient.
+ bool mUsesGradient;
+
+ // Even if usesGradient is true, some control flow might not use a gradient
+ // so we store the set of all gradient-using control flows.
+ std::set<TIntermNode *> mControlFlowsContainingGradient;
+
+ // Remember information about the discontinuous loops and which functions
+ // are called in such loops.
+ bool mCalledInDiscontinuousLoop;
+ bool mHasGradientLoopInCallGraph;
+ std::set<TIntermLoop *> mDiscontinuousLoops;
+ std::set<TIntermIfElse *> mIfsContainingGradientLoop;
+
+ // Will we need to generate a Lod0 version of the function.
+ bool mNeedsLod0;
+};
+
+typedef std::vector<ASTMetadataHLSL> MetadataList;
+
+// Return the AST analysis result, in the order defined by the call DAG
+MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp
new file mode 100644
index 0000000000..52b8b878c3
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp
@@ -0,0 +1,112 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// AtomicCounterFunctionHLSL: Class for writing implementation of atomic counter functions into HLSL
+// output.
+//
+
+#include "compiler/translator/AtomicCounterFunctionHLSL.h"
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+namespace
+{
+constexpr ImmutableString kAtomicCounter("atomicCounter");
+constexpr ImmutableString kAtomicCounterIncrement("atomicCounterIncrement");
+constexpr ImmutableString kAtomicCounterDecrement("atomicCounterDecrement");
+constexpr ImmutableString kAtomicCounterBaseName("_acbase_");
+} // namespace
+
+AtomicCounterFunctionHLSL::AtomicCounterFunctionHLSL(bool forceResolution)
+ : mForceResolution(forceResolution)
+{}
+
+ImmutableString AtomicCounterFunctionHLSL::useAtomicCounterFunction(const ImmutableString &name)
+{
+ // The largest string that will be create created is "_acbase_increment" or "_acbase_decrement"
+ ImmutableStringBuilder hlslFunctionNameSB(kAtomicCounterBaseName.length() +
+ strlen("increment"));
+ hlslFunctionNameSB << kAtomicCounterBaseName;
+
+ AtomicCounterFunction atomicMethod;
+ if (kAtomicCounter == name)
+ {
+ atomicMethod = AtomicCounterFunction::LOAD;
+ hlslFunctionNameSB << "load";
+ }
+ else if (kAtomicCounterIncrement == name)
+ {
+ atomicMethod = AtomicCounterFunction::INCREMENT;
+ hlslFunctionNameSB << "increment";
+ }
+ else if (kAtomicCounterDecrement == name)
+ {
+ atomicMethod = AtomicCounterFunction::DECREMENT;
+ hlslFunctionNameSB << "decrement";
+ }
+ else
+ {
+ atomicMethod = AtomicCounterFunction::INVALID;
+ UNREACHABLE();
+ }
+
+ ImmutableString hlslFunctionName(hlslFunctionNameSB);
+ mAtomicCounterFunctions[hlslFunctionName] = atomicMethod;
+
+ return hlslFunctionName;
+}
+
+void AtomicCounterFunctionHLSL::atomicCounterFunctionHeader(TInfoSinkBase &out)
+{
+ for (auto &atomicFunction : mAtomicCounterFunctions)
+ {
+ out << "uint " << atomicFunction.first
+ << "(in RWByteAddressBuffer counter, int address)\n"
+ "{\n"
+ " uint ret;\n";
+
+ switch (atomicFunction.second)
+ {
+ case AtomicCounterFunction::INCREMENT:
+ out << " counter.InterlockedAdd(address, 1u, ret);\n";
+ break;
+ case AtomicCounterFunction::DECREMENT:
+ out << " counter.InterlockedAdd(address, 0u - 1u, ret);\n"
+ " ret -= 1u;\n"; // atomicCounterDecrement is a post-decrement op
+ break;
+ case AtomicCounterFunction::LOAD:
+ out << " ret = counter.Load(address);\n";
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ if (mForceResolution && atomicFunction.second != AtomicCounterFunction::LOAD)
+ {
+ out << " if (ret == 0) {\n"
+ " ret = 0 - ret;\n"
+ " }\n";
+ }
+
+ out << " return ret;\n"
+ "}\n\n";
+ }
+}
+
+ImmutableString getAtomicCounterNameForBinding(int binding)
+{
+ std::stringstream counterName = sh::InitializeStream<std::stringstream>();
+ counterName << kAtomicCounterBaseName << binding;
+ return ImmutableString(counterName.str());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h
new file mode 100644
index 0000000000..e658df3c20
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// AtomicCounterFunctionHLSL: Class for writing implementation of atomic counter functions into HLSL
+// output.
+//
+
+#ifndef COMPILER_TRANSLATOR_ATOMICCOUNTERFUNCTIONHLSL_H_
+#define COMPILER_TRANSLATOR_ATOMICCOUNTERFUNCTIONHLSL_H_
+
+#include <map>
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/ImmutableString.h"
+
+namespace sh
+{
+
+class TInfoSinkBase;
+struct TLayoutQualifier;
+
+class AtomicCounterFunctionHLSL final : angle::NonCopyable
+{
+ public:
+ AtomicCounterFunctionHLSL(bool forceResolution);
+
+ ImmutableString useAtomicCounterFunction(const ImmutableString &name);
+
+ void atomicCounterFunctionHeader(TInfoSinkBase &out);
+
+ private:
+ enum class AtomicCounterFunction
+ {
+ LOAD,
+ INCREMENT,
+ DECREMENT,
+ INVALID
+ };
+
+ std::map<ImmutableString, AtomicCounterFunction> mAtomicCounterFunctions;
+ bool mForceResolution;
+};
+
+ImmutableString getAtomicCounterNameForBinding(int binding);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_ATOMICCOUNTERFUNCTIONHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/BaseTypes.h b/gfx/angle/checkout/src/compiler/translator/BaseTypes.h
new file mode 100644
index 0000000000..555910fa72
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BaseTypes.h
@@ -0,0 +1,1086 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_BASETYPES_H_
+#define COMPILER_TRANSLATOR_BASETYPES_H_
+
+#include <algorithm>
+#include <array>
+
+#include "GLSLANG/ShaderLang.h"
+#include "common/debug.h"
+#include "compiler/translator/ImmutableString.h"
+
+namespace sh
+{
+
+//
+// Precision qualifiers
+//
+enum TPrecision
+{
+ // These need to be kept sorted
+ EbpUndefined,
+ EbpLow,
+ EbpMedium,
+ EbpHigh,
+
+ // end of list
+ EbpLast
+};
+
+inline const char *getPrecisionString(TPrecision p)
+{
+ switch (p)
+ {
+ case EbpHigh:
+ return "highp";
+ case EbpMedium:
+ return "mediump";
+ case EbpLow:
+ return "lowp";
+ default:
+ return "mediump"; // Safest fallback
+ }
+}
+
+//
+// Basic type. Arrays, vectors, etc., are orthogonal to this.
+//
+enum TBasicType
+{
+ EbtVoid,
+ EbtFloat,
+ EbtInt,
+ EbtUInt,
+ EbtBool,
+
+ EbtAtomicCounter,
+ EbtYuvCscStandardEXT, // Only valid if EXT_YUV_target exists.
+
+ EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
+ EbtSampler2D = EbtGuardSamplerBegin,
+ EbtSampler3D,
+ EbtSamplerCube,
+ EbtSampler2DArray,
+ EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists.
+ EbtSamplerExternal2DY2YEXT, // Only valid if GL_EXT_YUV_target exists.
+ EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
+ EbtSampler2DMS,
+ EbtSampler2DMSArray,
+ EbtISampler2D,
+ EbtISampler3D,
+ EbtISamplerCube,
+ EbtISampler2DArray,
+ EbtISampler2DMS,
+ EbtISampler2DMSArray,
+ EbtUSampler2D,
+ EbtUSampler3D,
+ EbtUSamplerCube,
+ EbtUSampler2DArray,
+ EbtUSampler2DMS,
+ EbtUSampler2DMSArray,
+ EbtSampler2DShadow,
+ EbtSamplerCubeShadow,
+ EbtSampler2DArrayShadow,
+ EbtGuardSamplerEnd = EbtSampler2DArrayShadow, // non type: see implementation of IsSampler()
+
+ // images
+ EbtGuardImageBegin,
+ EbtImage2D = EbtGuardImageBegin,
+ EbtIImage2D,
+ EbtUImage2D,
+ EbtImage3D,
+ EbtIImage3D,
+ EbtUImage3D,
+ EbtImage2DArray,
+ EbtIImage2DArray,
+ EbtUImage2DArray,
+ EbtImageCube,
+ EbtIImageCube,
+ EbtUImageCube,
+ EbtGuardImageEnd = EbtUImageCube,
+
+ EbtLastSimpleType = EbtGuardImageEnd,
+
+ EbtStruct,
+ EbtInterfaceBlock,
+
+ // end of list
+ EbtLast = EbtInterfaceBlock
+};
+
+constexpr char GetBasicMangledName(TBasicType t)
+{
+ if (t > EbtLastSimpleType)
+ {
+ return '{';
+ }
+ static_assert(EbtLastSimpleType < 52, "We only use alphabetic characters for mangled names");
+ if (t < 26)
+ {
+ return static_cast<char>('A' + t);
+ }
+ return static_cast<char>('a' - 26 + t);
+}
+
+const char *getBasicString(TBasicType t);
+
+inline bool IsSampler(TBasicType type)
+{
+ return type >= EbtGuardSamplerBegin && type <= EbtGuardSamplerEnd;
+}
+
+inline bool IsImage(TBasicType type)
+{
+ return type >= EbtGuardImageBegin && type <= EbtGuardImageEnd;
+}
+
+inline bool IsAtomicCounter(TBasicType type)
+{
+ return type == EbtAtomicCounter;
+}
+
+inline bool IsOpaqueType(TBasicType type)
+{
+ return IsSampler(type) || IsImage(type) || IsAtomicCounter(type);
+}
+
+inline bool IsIntegerSampler(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtISampler2DMS:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtUSampler2DMS:
+ case EbtUSampler2DMSArray:
+ return true;
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSamplerExternal2DY2YEXT:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ case EbtSampler2DMS:
+ case EbtSampler2DMSArray:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsIntegerSamplerUnsigned(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtISampler2DMS:
+ case EbtISampler2DMSArray:
+ return false;
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtUSampler2DMS:
+ case EbtUSampler2DMSArray:
+ return true;
+ default:
+ assert(!IsIntegerSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSampler2DMS(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2DMS:
+ case EbtISampler2DMS:
+ case EbtUSampler2DMS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool IsSampler2DMSArray(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2DMSArray:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2DMSArray:
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool IsFloatImage(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtImage2D:
+ case EbtImage3D:
+ case EbtImage2DArray:
+ case EbtImageCube:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+inline bool IsIntegerImage(TBasicType type)
+{
+
+ switch (type)
+ {
+ case EbtIImage2D:
+ case EbtIImage3D:
+ case EbtIImage2DArray:
+ case EbtIImageCube:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+inline bool IsUnsignedImage(TBasicType type)
+{
+
+ switch (type)
+ {
+ case EbtUImage2D:
+ case EbtUImage3D:
+ case EbtUImage2DArray:
+ case EbtUImageCube:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+// Samplers are divided into 4 disjoint categories: 2D, cube, 3D, and array.
+// Array samplers are not 2D samplers.
+inline bool IsSampler2D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DRect:
+ case EbtSamplerExternalOES:
+ case EbtSamplerExternal2DY2YEXT:
+ case EbtSampler2DShadow:
+ case EbtSampler2DMS:
+ case EbtISampler2DMS:
+ case EbtUSampler2DMS:
+ return true;
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DMSArray:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2DMSArray:
+ case EbtSampler2DArrayShadow:
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCube:
+ case EbtSamplerCubeShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSamplerCube(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCubeShadow:
+ return true;
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerExternalOES:
+ case EbtSamplerExternal2DY2YEXT:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtSampler2DMS:
+ case EbtSampler2DMSArray:
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISampler2DArray:
+ case EbtISampler2DMS:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSampler2DArray:
+ case EbtUSampler2DMS:
+ case EbtUSampler2DMSArray:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSampler3D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ return true;
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSamplerExternal2DY2YEXT:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtSampler2DMS:
+ case EbtSampler2DMSArray:
+ case EbtISampler2D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtISampler2DMS:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtUSampler2DMS:
+ case EbtUSampler2DMSArray:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSamplerArray(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DMSArray:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2DMSArray:
+ case EbtSampler2DArrayShadow:
+ return true;
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DRect:
+ case EbtSamplerExternalOES:
+ case EbtSamplerExternal2DY2YEXT:
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCube:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DMS:
+ case EbtISampler2DMS:
+ case EbtUSampler2DMS:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsShadowSampler(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ return true;
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtISampler2DMS:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtUSampler2DMS:
+ case EbtUSampler2DMSArray:
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSamplerExternal2DY2YEXT:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtSampler2DMS:
+ case EbtSampler2DMSArray:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsImage2D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtImage2D:
+ case EbtIImage2D:
+ case EbtUImage2D:
+ return true;
+ case EbtImage3D:
+ case EbtIImage3D:
+ case EbtUImage3D:
+ case EbtImage2DArray:
+ case EbtIImage2DArray:
+ case EbtUImage2DArray:
+ case EbtImageCube:
+ case EbtIImageCube:
+ case EbtUImageCube:
+ return false;
+ default:
+ assert(!IsImage(type));
+ }
+
+ return false;
+}
+
+inline bool IsImage3D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtImage3D:
+ case EbtIImage3D:
+ case EbtUImage3D:
+ return true;
+ case EbtImage2D:
+ case EbtIImage2D:
+ case EbtUImage2D:
+ case EbtImage2DArray:
+ case EbtIImage2DArray:
+ case EbtUImage2DArray:
+ case EbtImageCube:
+ case EbtIImageCube:
+ case EbtUImageCube:
+ return false;
+ default:
+ assert(!IsImage(type));
+ }
+
+ return false;
+}
+
+inline bool IsImage2DArray(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtImage2DArray:
+ case EbtIImage2DArray:
+ case EbtUImage2DArray:
+ return true;
+ case EbtImage2D:
+ case EbtIImage2D:
+ case EbtUImage2D:
+ case EbtImage3D:
+ case EbtIImage3D:
+ case EbtUImage3D:
+ case EbtImageCube:
+ case EbtIImageCube:
+ case EbtUImageCube:
+ return false;
+ default:
+ assert(!IsImage(type));
+ }
+
+ return false;
+}
+
+inline bool IsImageCube(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtImageCube:
+ case EbtIImageCube:
+ case EbtUImageCube:
+ return true;
+ case EbtImage2D:
+ case EbtIImage2D:
+ case EbtUImage2D:
+ case EbtImage3D:
+ case EbtIImage3D:
+ case EbtUImage3D:
+ case EbtImage2DArray:
+ case EbtIImage2DArray:
+ case EbtUImage2DArray:
+ return false;
+ default:
+ assert(!IsImage(type));
+ }
+
+ return false;
+}
+
+inline bool IsInteger(TBasicType type)
+{
+ return type == EbtInt || type == EbtUInt;
+}
+
+inline bool SupportsPrecision(TBasicType type)
+{
+ return type == EbtFloat || type == EbtInt || type == EbtUInt || IsOpaqueType(type);
+}
+
+//
+// Qualifiers and built-ins. These are mainly used to see what can be read
+// or written, and by the machine dependent translator to know which registers
+// to allocate variables in. Since built-ins tend to go to different registers
+// than varying or uniform, it makes sense they are peers, not sub-classes.
+//
+enum TQualifier
+{
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
+ EvqBuffer, // read/write, vertex, fragment and compute shader
+
+ EvqVertexIn, // Vertex shader input
+ EvqFragmentOut, // Fragment shader output
+ EvqVertexOut, // Vertex shader output
+ EvqFragmentIn, // Fragment shader input
+
+ // parameters
+ EvqIn,
+ EvqOut,
+ EvqInOut,
+ EvqConstReadOnly,
+
+ // built-ins read by vertex shader
+ EvqInstanceID,
+ EvqVertexID,
+
+ // built-ins written by vertex shader
+ EvqPosition,
+ EvqPointSize,
+
+ EvqDrawID, // ANGLE_multi_draw
+
+ EvqBaseVertex, // ANGLE_base_vertex_base_instance
+ EvqBaseInstance, // ANGLE_base_vertex_base_instance
+
+ // built-ins read by fragment shader
+ EvqFragCoord,
+ EvqFrontFacing,
+ EvqPointCoord,
+
+ // built-ins written by fragment shader
+ EvqFragColor,
+ EvqFragData,
+
+ EvqFragDepth, // gl_FragDepth for ESSL300.
+ EvqFragDepthEXT, // gl_FragDepthEXT for ESSL100, EXT_frag_depth.
+
+ EvqSecondaryFragColorEXT, // EXT_blend_func_extended
+ EvqSecondaryFragDataEXT, // EXT_blend_func_extended
+
+ EvqViewIDOVR, // OVR_multiview
+ EvqViewportIndex, // gl_ViewportIndex
+
+ // built-ins written by the shader_framebuffer_fetch extension(s)
+ EvqLastFragColor,
+ EvqLastFragData,
+
+ // GLSL ES 3.0 vertex output and fragment input
+ EvqSmooth, // Incomplete qualifier, smooth is the default
+ EvqFlat, // Incomplete qualifier
+ EvqCentroid, // Incomplete qualifier
+ EvqSmoothOut,
+ EvqFlatOut,
+ EvqCentroidOut, // Implies smooth
+ EvqSmoothIn,
+ EvqFlatIn,
+ EvqCentroidIn, // Implies smooth
+
+ // GLSL ES 3.1 compute shader special variables
+ EvqShared,
+ EvqComputeIn,
+ EvqNumWorkGroups,
+ EvqWorkGroupSize,
+ EvqWorkGroupID,
+ EvqLocalInvocationID,
+ EvqGlobalInvocationID,
+ EvqLocalInvocationIndex,
+
+ // GLSL ES 3.1 memory qualifiers
+ EvqReadOnly,
+ EvqWriteOnly,
+ EvqCoherent,
+ EvqRestrict,
+ EvqVolatile,
+
+ // GLSL ES 3.1 extension EXT_geometry_shader qualifiers
+ EvqGeometryIn,
+ EvqGeometryOut,
+ EvqPerVertexIn, // gl_in
+ EvqPrimitiveIDIn, // gl_PrimitiveIDIn
+ EvqInvocationID, // gl_InvocationID
+ EvqPrimitiveID, // gl_PrimitiveID
+ EvqLayer, // gl_Layer
+
+ // end of list
+ EvqLast
+};
+
+inline bool IsQualifierUnspecified(TQualifier qualifier)
+{
+ return (qualifier == EvqTemporary || qualifier == EvqGlobal);
+}
+
+inline bool IsStorageBuffer(TQualifier qualifier)
+{
+ return qualifier == EvqBuffer;
+}
+
+enum TLayoutImageInternalFormat
+{
+ EiifUnspecified,
+ EiifRGBA32F,
+ EiifRGBA16F,
+ EiifR32F,
+ EiifRGBA32UI,
+ EiifRGBA16UI,
+ EiifRGBA8UI,
+ EiifR32UI,
+ EiifRGBA32I,
+ EiifRGBA16I,
+ EiifRGBA8I,
+ EiifR32I,
+ EiifRGBA8,
+ EiifRGBA8_SNORM
+};
+
+enum TLayoutMatrixPacking
+{
+ EmpUnspecified,
+ EmpRowMajor,
+ EmpColumnMajor
+};
+
+enum TLayoutBlockStorage
+{
+ EbsUnspecified,
+ EbsShared,
+ EbsPacked,
+ EbsStd140,
+ EbsStd430
+};
+
+enum TYuvCscStandardEXT
+{
+ EycsUndefined,
+ EycsItu601,
+ EycsItu601FullRange,
+ EycsItu709
+};
+
+enum TLayoutPrimitiveType
+{
+ EptUndefined,
+ EptPoints,
+ EptLines,
+ EptLinesAdjacency,
+ EptTriangles,
+ EptTrianglesAdjacency,
+ EptLineStrip,
+ EptTriangleStrip
+};
+
+struct TLayoutQualifier
+{
+ // Must have a trivial default constructor since it is used in YYSTYPE.
+ TLayoutQualifier() = default;
+
+ constexpr static TLayoutQualifier Create() { return TLayoutQualifier(0); }
+
+ bool isEmpty() const
+ {
+ return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false &&
+ matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified &&
+ !localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified &&
+ primitiveType == EptUndefined && invocations == 0 && maxVertices == -1 &&
+ index == -1;
+ }
+
+ bool isCombinationValid() const
+ {
+ bool workSizeSpecified = localSize.isAnyValueSet();
+ bool numViewsSet = (numViews != -1);
+ bool geometryShaderSpecified =
+ (primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1);
+ bool otherLayoutQualifiersSpecified =
+ (location != -1 || binding != -1 || index != -1 || matrixPacking != EmpUnspecified ||
+ blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified);
+
+ // we can have either the work group size specified, or number of views,
+ // or yuv layout qualifier, or the other layout qualifiers.
+ return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) + (yuv ? 1 : 0) +
+ (otherLayoutQualifiersSpecified ? 1 : 0) + (geometryShaderSpecified ? 1 : 0) <=
+ 1;
+ }
+
+ bool isLocalSizeEqual(const WorkGroupSize &localSizeIn) const
+ {
+ return localSize.isWorkGroupSizeMatching(localSizeIn);
+ }
+
+ int location;
+ unsigned int locationsSpecified;
+ TLayoutMatrixPacking matrixPacking;
+ TLayoutBlockStorage blockStorage;
+
+ // Compute shader layout qualifiers.
+ WorkGroupSize localSize;
+
+ int binding;
+ int offset;
+
+ // Image format layout qualifier
+ TLayoutImageInternalFormat imageInternalFormat;
+
+ // OVR_multiview num_views.
+ int numViews;
+
+ // EXT_YUV_target yuv layout qualifier.
+ bool yuv;
+
+ // OES_geometry_shader layout qualifiers.
+ TLayoutPrimitiveType primitiveType;
+ int invocations;
+ int maxVertices;
+
+ // EXT_blend_func_extended fragment output layout qualifier
+ int index;
+
+ private:
+ explicit constexpr TLayoutQualifier(int /*placeholder*/)
+ : location(-1),
+ locationsSpecified(0),
+ matrixPacking(EmpUnspecified),
+ blockStorage(EbsUnspecified),
+ localSize(-1),
+ binding(-1),
+ offset(-1),
+ imageInternalFormat(EiifUnspecified),
+ numViews(-1),
+ yuv(false),
+ primitiveType(EptUndefined),
+ invocations(0),
+ maxVertices(-1),
+ index(-1)
+ {}
+};
+
+struct TMemoryQualifier
+{
+ // Must have a trivial default constructor since it is used in YYSTYPE.
+ TMemoryQualifier() = default;
+
+ bool isEmpty() const
+ {
+ return !readonly && !writeonly && !coherent && !restrictQualifier && !volatileQualifier;
+ }
+
+ constexpr static TMemoryQualifier Create() { return TMemoryQualifier(0); }
+
+ // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
+ // An image can be qualified as both readonly and writeonly. It still can be can be used with
+ // imageSize().
+ bool readonly;
+ bool writeonly;
+ bool coherent;
+
+ // restrict and volatile are reserved keywords in C/C++
+ bool restrictQualifier;
+ bool volatileQualifier;
+
+ private:
+ explicit constexpr TMemoryQualifier(int /*placeholder*/)
+ : readonly(false),
+ writeonly(false),
+ coherent(false),
+ restrictQualifier(false),
+ volatileQualifier(false)
+ {}
+};
+
+inline const char *getWorkGroupSizeString(size_t dimension)
+{
+ switch (dimension)
+ {
+ case 0u:
+ return "local_size_x";
+ case 1u:
+ return "local_size_y";
+ case 2u:
+ return "local_size_z";
+ default:
+ UNREACHABLE();
+ return "dimension out of bounds";
+ }
+}
+
+//
+// This is just for debug and error message print out, carried along with the definitions above.
+//
+inline const char *getQualifierString(TQualifier q)
+{
+ // clang-format off
+ switch(q)
+ {
+ case EvqTemporary: return "Temporary";
+ case EvqGlobal: return "Global";
+ case EvqConst: return "const";
+ case EvqAttribute: return "attribute";
+ case EvqVaryingIn: return "varying";
+ case EvqVaryingOut: return "varying";
+ case EvqUniform: return "uniform";
+ case EvqBuffer: return "buffer";
+ case EvqVertexIn: return "in";
+ case EvqFragmentOut: return "out";
+ case EvqVertexOut: return "out";
+ case EvqFragmentIn: return "in";
+ case EvqIn: return "in";
+ case EvqOut: return "out";
+ case EvqInOut: return "inout";
+ case EvqConstReadOnly: return "const";
+ case EvqInstanceID: return "InstanceID";
+ case EvqVertexID: return "VertexID";
+ case EvqPosition: return "Position";
+ case EvqPointSize: return "PointSize";
+ case EvqDrawID: return "DrawID";
+ case EvqBaseVertex: return "BaseVertex";
+ case EvqBaseInstance: return "BaseInstance";
+ case EvqFragCoord: return "FragCoord";
+ case EvqFrontFacing: return "FrontFacing";
+ case EvqPointCoord: return "PointCoord";
+ case EvqFragColor: return "FragColor";
+ case EvqFragData: return "FragData";
+ case EvqFragDepthEXT: return "FragDepth";
+ case EvqFragDepth: return "FragDepth";
+ case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
+ case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
+ case EvqViewIDOVR: return "ViewIDOVR";
+ case EvqViewportIndex: return "ViewportIndex";
+ case EvqLayer: return "Layer";
+ case EvqLastFragColor: return "LastFragColor";
+ case EvqLastFragData: return "LastFragData";
+ case EvqSmoothOut: return "smooth out";
+ case EvqCentroidOut: return "smooth centroid out";
+ case EvqFlatOut: return "flat out";
+ case EvqSmoothIn: return "smooth in";
+ case EvqFlatIn: return "flat in";
+ case EvqCentroidIn: return "smooth centroid in";
+ case EvqCentroid: return "centroid";
+ case EvqFlat: return "flat";
+ case EvqSmooth: return "smooth";
+ case EvqShared: return "shared";
+ case EvqComputeIn: return "in";
+ case EvqNumWorkGroups: return "NumWorkGroups";
+ case EvqWorkGroupSize: return "WorkGroupSize";
+ case EvqWorkGroupID: return "WorkGroupID";
+ case EvqLocalInvocationID: return "LocalInvocationID";
+ case EvqGlobalInvocationID: return "GlobalInvocationID";
+ case EvqLocalInvocationIndex: return "LocalInvocationIndex";
+ case EvqReadOnly: return "readonly";
+ case EvqWriteOnly: return "writeonly";
+ case EvqGeometryIn: return "in";
+ case EvqGeometryOut: return "out";
+ case EvqPerVertexIn: return "gl_in";
+ default: UNREACHABLE(); return "unknown qualifier";
+ }
+ // clang-format on
+}
+
+inline const char *getMatrixPackingString(TLayoutMatrixPacking mpq)
+{
+ switch (mpq)
+ {
+ case EmpUnspecified:
+ return "mp_unspecified";
+ case EmpRowMajor:
+ return "row_major";
+ case EmpColumnMajor:
+ return "column_major";
+ default:
+ UNREACHABLE();
+ return "unknown matrix packing";
+ }
+}
+
+inline const char *getBlockStorageString(TLayoutBlockStorage bsq)
+{
+ switch (bsq)
+ {
+ case EbsUnspecified:
+ return "bs_unspecified";
+ case EbsShared:
+ return "shared";
+ case EbsPacked:
+ return "packed";
+ case EbsStd140:
+ return "std140";
+ case EbsStd430:
+ return "std430";
+ default:
+ UNREACHABLE();
+ return "unknown block storage";
+ }
+}
+
+inline const char *getImageInternalFormatString(TLayoutImageInternalFormat iifq)
+{
+ switch (iifq)
+ {
+ case EiifRGBA32F:
+ return "rgba32f";
+ case EiifRGBA16F:
+ return "rgba16f";
+ case EiifR32F:
+ return "r32f";
+ case EiifRGBA32UI:
+ return "rgba32ui";
+ case EiifRGBA16UI:
+ return "rgba16ui";
+ case EiifRGBA8UI:
+ return "rgba8ui";
+ case EiifR32UI:
+ return "r32ui";
+ case EiifRGBA32I:
+ return "rgba32i";
+ case EiifRGBA16I:
+ return "rgba16i";
+ case EiifRGBA8I:
+ return "rgba8i";
+ case EiifR32I:
+ return "r32i";
+ case EiifRGBA8:
+ return "rgba8";
+ case EiifRGBA8_SNORM:
+ return "rgba8_snorm";
+ default:
+ UNREACHABLE();
+ return "unknown internal image format";
+ }
+}
+
+inline TYuvCscStandardEXT getYuvCscStandardEXT(const ImmutableString &str)
+{
+ if (str == "itu_601")
+ return EycsItu601;
+ else if (str == "itu_601_full_range")
+ return EycsItu601FullRange;
+ else if (str == "itu_709")
+ return EycsItu709;
+ return EycsUndefined;
+}
+
+inline const char *getYuvCscStandardEXTString(TYuvCscStandardEXT ycsq)
+{
+ switch (ycsq)
+ {
+ case EycsItu601:
+ return "itu_601";
+ case EycsItu601FullRange:
+ return "itu_601_full_range";
+ case EycsItu709:
+ return "itu_709";
+ default:
+ UNREACHABLE();
+ return "unknown color space conversion standard";
+ }
+}
+
+inline const char *getGeometryShaderPrimitiveTypeString(TLayoutPrimitiveType primitiveType)
+{
+ switch (primitiveType)
+ {
+ case EptPoints:
+ return "points";
+ case EptLines:
+ return "lines";
+ case EptTriangles:
+ return "triangles";
+ case EptLinesAdjacency:
+ return "lines_adjacency";
+ case EptTrianglesAdjacency:
+ return "triangles_adjacency";
+ case EptLineStrip:
+ return "line_strip";
+ case EptTriangleStrip:
+ return "triangle_strip";
+ default:
+ UNREACHABLE();
+ return "unknown geometry shader primitive type";
+ }
+}
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_BASETYPES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
new file mode 100644
index 0000000000..290f84df68
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -0,0 +1,162 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "angle_gl.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
+{
+ public:
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
+ : TIntermTraverser(true, false, false), mEmulator(emulator)
+ {}
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override
+ {
+ if (node->getFunction())
+ {
+ bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ // Here we handle all the built-in functions mapped to ops, not just the ones that are
+ // currently identified as problematic.
+ if (node->isConstructor() || node->isFunctionCall())
+ {
+ return true;
+ }
+ bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ return true;
+ }
+
+ private:
+ BuiltInFunctionEmulator &mEmulator;
+};
+
+BuiltInFunctionEmulator::BuiltInFunctionEmulator() {}
+
+void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
+ const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
+}
+
+void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
+ const TSymbolUniqueId &dependency,
+ const TSymbolUniqueId &uniqueId,
+ const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
+ mFunctionDependencies[uniqueId.get()] = dependency.get();
+}
+
+bool BuiltInFunctionEmulator::isOutputEmpty() const
+{
+ return (mFunctions.size() == 0);
+}
+
+void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
+{
+ for (const auto &function : mFunctions)
+ {
+ const char *body = findEmulatedFunction(function);
+ ASSERT(body);
+ out << body;
+ out << "\n\n";
+ }
+}
+
+const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const
+{
+ for (const auto &queryFunction : mQueryFunctions)
+ {
+ const char *result = queryFunction(uniqueId);
+ if (result)
+ {
+ return result;
+ }
+ }
+
+ const auto &result = mEmulatedFunctions.find(uniqueId);
+ if (result != mEmulatedFunctions.end())
+ {
+ return result->second.c_str();
+ }
+
+ return nullptr;
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
+{
+ ASSERT(function != nullptr);
+ return setFunctionCalled(function->uniqueId().get());
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId)
+{
+ if (!findEmulatedFunction(uniqueId))
+ {
+ return false;
+ }
+
+ for (size_t i = 0; i < mFunctions.size(); ++i)
+ {
+ if (mFunctions[i] == uniqueId)
+ return true;
+ }
+ // If the function depends on another, mark the dependency as called.
+ auto dependency = mFunctionDependencies.find(uniqueId);
+ if (dependency != mFunctionDependencies.end())
+ {
+ setFunctionCalled((*dependency).second);
+ }
+ mFunctions.push_back(uniqueId);
+ return true;
+}
+
+void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
+{
+ ASSERT(root);
+
+ if (mEmulatedFunctions.empty() && mQueryFunctions.empty())
+ return;
+
+ BuiltInFunctionEmulationMarker marker(*this);
+ root->traverse(&marker);
+}
+
+void BuiltInFunctionEmulator::cleanup()
+{
+ mFunctions.clear();
+ mFunctionDependencies.clear();
+}
+
+void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
+{
+ mQueryFunctions.push_back(queryFunc);
+}
+
+// static
+void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
+{
+ ASSERT(name[strlen(name) - 1] != '(');
+ out << name << "_emu";
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h
new file mode 100644
index 0000000000..d15e83d75c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
+
+#include "compiler/translator/InfoSink.h"
+
+namespace sh
+{
+
+class TIntermNode;
+class TFunction;
+class TSymbolUniqueId;
+
+using BuiltinQueryFunc = const char *(int);
+
+//
+// This class decides which built-in functions need to be replaced with the emulated ones. It can be
+// used to work around driver bugs or implement functions that are not natively implemented on a
+// specific platform.
+//
+class BuiltInFunctionEmulator
+{
+ public:
+ BuiltInFunctionEmulator();
+
+ void markBuiltInFunctionsForEmulation(TIntermNode *root);
+
+ void cleanup();
+
+ // "name" gets written as "name_emu".
+ static void WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name);
+
+ bool isOutputEmpty() const;
+
+ // Output function emulation definition. This should be before any other shader source.
+ void outputEmulatedFunctions(TInfoSinkBase &out) const;
+
+ // Add functions that need to be emulated.
+ void addEmulatedFunction(const TSymbolUniqueId &uniqueId,
+ const char *emulatedFunctionDefinition);
+
+ void addEmulatedFunctionWithDependency(const TSymbolUniqueId &dependency,
+ const TSymbolUniqueId &uniqueId,
+ const char *emulatedFunctionDefinition);
+
+ void addFunctionMap(BuiltinQueryFunc queryFunc);
+
+ private:
+ class BuiltInFunctionEmulationMarker;
+
+ // Records that a function is called by the shader and might need to be emulated. If the
+ // function is not in mEmulatedFunctions, this becomes a no-op. Returns true if the function
+ // call needs to be replaced with an emulated one.
+ bool setFunctionCalled(const TFunction *function);
+ bool setFunctionCalled(int uniqueId);
+
+ const char *findEmulatedFunction(int uniqueId) const;
+
+ // Map from function unique id to emulated function definition
+ std::map<int, std::string> mEmulatedFunctions;
+
+ // Map from dependent functions to their dependencies. This structure allows each function to
+ // have at most one dependency.
+ std::map<int, int> mFunctionDependencies;
+
+ // Called function ids
+ std::vector<int> mFunctions;
+
+ // Constexpr function tables.
+ std::vector<BuiltinQueryFunc *> mQueryFunctions;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
new file mode 100644
index 0000000000..dc48527480
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -0,0 +1,284 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/VersionGLSL.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+
+namespace sh
+{
+
+void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType)
+{
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ emu->addEmulatedFunction(BuiltInId::abs_Int1, "int abs_emu(int x) { return x * sign(x); }");
+ }
+}
+
+void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion)
+{
+ // isnan() is supported since GLSL 1.3.
+ if (targetGLSLVersion < GLSL_VERSION_130)
+ return;
+
+ // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float1,
+ "bool isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float2,
+ "bvec2 isnan_emu(vec2 x)\n"
+ "{\n"
+ " bvec2 isnan;\n"
+ " for (int i = 0; i < 2; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float3,
+ "bvec3 isnan_emu(vec3 x)\n"
+ "{\n"
+ " bvec3 isnan;\n"
+ " for (int i = 0; i < 3; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float4,
+ "bvec4 isnan_emu(vec4 x)\n"
+ "{\n"
+ " bvec4 isnan;\n"
+ " for (int i = 0; i < 4; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+}
+
+void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu)
+{
+ emu->addEmulatedFunction(BuiltInId::atan_Float1_Float1,
+ "emu_precision float atan_emu(emu_precision float y, emu_precision "
+ "float x)\n"
+ "{\n"
+ " if (x > 0.0) return atan(y / x);\n"
+ " else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n"
+ " else if (x < 0.0 && y < 0.0) return atan(y / x) - 3.14159265;\n"
+ " else return 1.57079632 * sign(y);\n"
+ "}\n");
+ static const std::array<TSymbolUniqueId, 4> ids = {
+ BuiltInId::atan_Float1_Float1,
+ BuiltInId::atan_Float2_Float2,
+ BuiltInId::atan_Float3_Float3,
+ BuiltInId::atan_Float4_Float4,
+ };
+ for (int dim = 2; dim <= 4; ++dim)
+ {
+ std::stringstream ss = sh::InitializeStream<std::stringstream>();
+ ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim
+ << " y, emu_precision vec" << dim << " x)\n"
+ << "{\n"
+ " return vec"
+ << dim << "(";
+ for (int i = 0; i < dim; ++i)
+ {
+ ss << "atan_emu(y[" << i << "], x[" << i << "])";
+ if (i < dim - 1)
+ {
+ ss << ", ";
+ }
+ }
+ ss << ");\n"
+ "}\n";
+ emu->addEmulatedFunctionWithDependency(BuiltInId::atan_Float1_Float1, ids[dim - 1],
+ ss.str().c_str());
+ }
+}
+
+// Emulate built-in functions missing from GLSL 1.30 and higher
+void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType,
+ int targetGLSLVersion)
+{
+ // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
+ if (targetGLSLVersion < GLSL_VERSION_410)
+ {
+ // clang-format off
+ emu->addEmulatedFunction(BuiltInId::packUnorm2x16_Float2,
+ "uint packUnorm2x16_emu(vec2 v)\n"
+ "{\n"
+ " int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n"
+ " int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n"
+ " return uint((y << 16) | (x & 0xFFFF));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(BuiltInId::unpackUnorm2x16_UInt1,
+ "vec2 unpackUnorm2x16_emu(uint u)\n"
+ "{\n"
+ " float x = float(u & 0xFFFFu) / 65535.0;\n"
+ " float y = float(u >> 16) / 65535.0;\n"
+ " return vec2(x, y);\n"
+ "}\n");
+ // clang-format on
+ }
+
+ // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
+ // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
+ if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
+ {
+ // clang-format off
+ emu->addEmulatedFunction(BuiltInId::packSnorm2x16_Float2,
+ "uint packSnorm2x16_emu(vec2 v)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return packSnorm2x16(v);\n"
+ " #else\n"
+ " int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
+ " int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
+ " return uint((y << 16) | (x & 0xFFFF));\n"
+ " #endif\n"
+ "}\n");
+ emu->addEmulatedFunction(BuiltInId::unpackSnorm2x16_UInt1,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " float fromSnorm(uint x)\n"
+ " {\n"
+ " int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
+ " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
+ " }\n"
+ "#endif\n"
+ "\n"
+ "vec2 unpackSnorm2x16_emu(uint u)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return unpackSnorm2x16(u);\n"
+ " #else\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u;\n"
+ " return vec2(fromSnorm(x), fromSnorm(y));\n"
+ " #endif\n"
+ "}\n");
+ // Functions uint f32tof16(float val) and float f16tof32(uint val) are
+ // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
+ emu->addEmulatedFunction(BuiltInId::packHalf2x16_Float2,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " uint f32tof16(float val)\n"
+ " {\n"
+ " uint f32 = floatBitsToUint(val);\n"
+ " uint f16 = 0u;\n"
+ " uint sign = (f32 >> 16) & 0x8000u;\n"
+ " int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
+ " uint mantissa = f32 & 0x007FFFFFu;\n"
+ " if (exponent == 128)\n"
+ " {\n"
+ " // Infinity or NaN\n"
+ " // NaN bits that are masked out by 0x3FF get discarded.\n"
+ " // This can turn some NaNs to infinity, but this is allowed by the spec.\n"
+ " f16 = sign | (0x1Fu << 10);\n"
+ " f16 |= (mantissa & 0x3FFu);\n"
+ " }\n"
+ " else if (exponent > 15)\n"
+ " {\n"
+ " // Overflow - flush to Infinity\n"
+ " f16 = sign | (0x1Fu << 10);\n"
+ " }\n"
+ " else if (exponent > -15)\n"
+ " {\n"
+ " // Representable value\n"
+ " exponent += 15;\n"
+ " mantissa >>= 13;\n"
+ " f16 = sign | uint(exponent << 10) | mantissa;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " f16 = sign;\n"
+ " }\n"
+ " return f16;\n"
+ " }\n"
+ "#endif\n"
+ "\n"
+ "uint packHalf2x16_emu(vec2 v)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return packHalf2x16(v);\n"
+ " #else\n"
+ " uint x = f32tof16(v.x);\n"
+ " uint y = f32tof16(v.y);\n"
+ " return (y << 16) | x;\n"
+ " #endif\n"
+ "}\n");
+ emu->addEmulatedFunction(BuiltInId::unpackHalf2x16_UInt1,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " float f16tof32(uint val)\n"
+ " {\n"
+ " uint sign = (val & 0x8000u) << 16;\n"
+ " int exponent = int((val & 0x7C00u) >> 10);\n"
+ " uint mantissa = val & 0x03FFu;\n"
+ " float f32 = 0.0;\n"
+ " if(exponent == 0)\n"
+ " {\n"
+ " if (mantissa != 0u)\n"
+ " {\n"
+ " const float scale = 1.0 / (1 << 24);\n"
+ " f32 = scale * mantissa;\n"
+ " }\n"
+ " }\n"
+ " else if (exponent == 31)\n"
+ " {\n"
+ " return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " exponent -= 15;\n"
+ " float scale;\n"
+ " if(exponent < 0)\n"
+ " {\n"
+ " // The negative unary operator is buggy on OSX.\n"
+ " // Work around this by using abs instead.\n"
+ " scale = 1.0 / (1 << abs(exponent));\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " scale = 1 << exponent;\n"
+ " }\n"
+ " float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
+ " f32 = scale * decimal;\n"
+ " }\n"
+ "\n"
+ " if (sign != 0u)\n"
+ " {\n"
+ " f32 = -f32;\n"
+ " }\n"
+ "\n"
+ " return f32;\n"
+ " }\n"
+ "#endif\n"
+ "\n"
+ "vec2 unpackHalf2x16_emu(uint u)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return unpackHalf2x16(u);\n"
+ " #else\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u & 0xFFFFu;\n"
+ " return vec2(f16tof32(x), f16tof32(y));\n"
+ " #endif\n"
+ "}\n");
+ // clang-format on
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
new file mode 100644
index 0000000000..e1b4779bd5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+namespace sh
+{
+class BuiltInFunctionEmulator;
+
+//
+// This works around bug in Intel Mac drivers.
+//
+void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType);
+
+//
+// This works around isnan() bug in Intel Mac drivers
+//
+void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion);
+//
+// This works around atan(y, x) bug in NVIDIA drivers.
+//
+void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu);
+
+//
+// This function is emulating built-in functions missing from GLSL 1.30 and higher.
+//
+void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType,
+ int targetGLSLVersion);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
new file mode 100644
index 0000000000..b4bca0d36d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -0,0 +1,173 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
+#include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/VersionGLSL.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+
+namespace sh
+{
+
+// Defined in emulated_builtin_functions_hlsl_autogen.cpp.
+const char *FindHLSLFunction(int uniqueId);
+
+void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion)
+{
+ if (targetGLSLVersion < GLSL_VERSION_130)
+ return;
+
+ emu->addEmulatedFunction(BuiltInId::isnan_Float1,
+ "bool isnan_emu(float x)\n"
+ "{\n"
+ " return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n"
+ "}\n"
+ "\n");
+
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float2,
+ "bool2 isnan_emu(float2 x)\n"
+ "{\n"
+ " bool2 isnan;\n"
+ " for (int i = 0; i < 2; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float3,
+ "bool3 isnan_emu(float3 x)\n"
+ "{\n"
+ " bool3 isnan;\n"
+ " for (int i = 0; i < 3; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+
+ emu->addEmulatedFunction(
+ BuiltInId::isnan_Float4,
+ "bool4 isnan_emu(float4 x)\n"
+ "{\n"
+ " bool4 isnan;\n"
+ " for (int i = 0; i < 4; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+}
+
+void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
+{
+ emu->addFunctionMap(FindHLSLFunction);
+
+ // (a + b2^16) * (c + d2^16) = ac + (ad + bc) * 2^16 + bd * 2^32
+ // Also note that below, a * d + ((a * c) >> 16) is guaranteed not to overflow, because:
+ // a <= 0xffff, d <= 0xffff, ((a * c) >> 16) <= 0xffff and 0xffff * 0xffff + 0xffff = 0xffff0000
+ emu->addEmulatedFunction(BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
+ "void umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n"
+ "{\n"
+ " lsb = x * y;\n"
+ " uint a = (x & 0xffffu);\n"
+ " uint b = (x >> 16);\n"
+ " uint c = (y & 0xffffu);\n"
+ " uint d = (y >> 16);\n"
+ " uint ad = a * d + ((a * c) >> 16);\n"
+ " uint bc = b * c;\n"
+ " uint carry = uint(ad > (0xffffffffu - bc));\n"
+ " msb = ((ad + bc) >> 16) + (carry << 16) + b * d;\n"
+ "}\n");
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
+ BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2,
+ "void umulExtended_emu(uint2 x, uint2 y, out uint2 msb, out uint2 lsb)\n"
+ "{\n"
+ " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
+ " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
+ "}\n");
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
+ BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3,
+ "void umulExtended_emu(uint3 x, uint3 y, out uint3 msb, out uint3 lsb)\n"
+ "{\n"
+ " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
+ " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
+ " umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
+ "}\n");
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
+ BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4,
+ "void umulExtended_emu(uint4 x, uint4 y, out uint4 msb, out uint4 lsb)\n"
+ "{\n"
+ " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
+ " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
+ " umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
+ " umulExtended_emu(x.w, y.w, msb.w, lsb.w);\n"
+ "}\n");
+
+ // The imul emulation does two's complement negation on the lsb and msb manually in case the
+ // result needs to be negative.
+ // TODO(oetuaho): Note that this code doesn't take one edge case into account, where x or y is
+ // -2^31. abs(-2^31) is undefined.
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
+ BuiltInId::imulExtended_Int1_Int1_Int1_Int1,
+ "void imulExtended_emu(int x, int y, out int msb, out int lsb)\n"
+ "{\n"
+ " uint unsignedMsb;\n"
+ " uint unsignedLsb;\n"
+ " bool negative = (x < 0) != (y < 0);\n"
+ " umulExtended_emu(uint(abs(x)), uint(abs(y)), unsignedMsb, unsignedLsb);\n"
+ " lsb = asint(unsignedLsb);\n"
+ " msb = asint(unsignedMsb);\n"
+ " if (negative)\n"
+ " {\n"
+ " lsb = ~lsb;\n"
+ " msb = ~msb;\n"
+ " if (lsb == 0xffffffff)\n"
+ " {\n"
+ " lsb = 0;\n"
+ " msb += 1;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " lsb += 1;\n"
+ " }\n"
+ " }\n"
+ "}\n");
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int2_Int2_Int2_Int2,
+ "void imulExtended_emu(int2 x, int2 y, out int2 msb, out int2 lsb)\n"
+ "{\n"
+ " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
+ " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
+ "}\n");
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int3_Int3_Int3_Int3,
+ "void imulExtended_emu(int3 x, int3 y, out int3 msb, out int3 lsb)\n"
+ "{\n"
+ " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
+ " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
+ " imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
+ "}\n");
+ emu->addEmulatedFunctionWithDependency(
+ BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int4_Int4_Int4_Int4,
+ "void imulExtended_emu(int4 x, int4 y, out int4 msb, out int4 lsb)\n"
+ "{\n"
+ " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
+ " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
+ " imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
+ " imulExtended_emu(x.w, y.w, msb.w, lsb.w);\n"
+ "}\n");
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
new file mode 100644
index 0000000000..48da73f58e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+namespace sh
+{
+
+class BuiltInFunctionEmulator;
+
+void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu);
+
+//
+// This works around isnan() bug on some Intel drivers.
+//
+void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp b/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp
new file mode 100644
index 0000000000..63c8cd0f92
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp
@@ -0,0 +1,316 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// CallDAG.h: Implements a call graph DAG of functions to be re-used accross
+// analyses, allows to efficiently traverse the functions in topological
+// order.
+
+#include "compiler/translator/CallDAG.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+// The CallDAGCreator does all the processing required to create the CallDAG
+// structure so that the latter contains only the necessary variables.
+class CallDAG::CallDAGCreator : public TIntermTraverser
+{
+ public:
+ CallDAGCreator(TDiagnostics *diagnostics)
+ : TIntermTraverser(true, false, false),
+ mDiagnostics(diagnostics),
+ mCurrentFunction(nullptr),
+ mCurrentIndex(0)
+ {}
+
+ InitResult assignIndices()
+ {
+ int skipped = 0;
+ for (auto &it : mFunctions)
+ {
+ // Skip unimplemented functions
+ if (it.second.definitionNode)
+ {
+ InitResult result = assignIndicesInternal(&it.second);
+ if (result != INITDAG_SUCCESS)
+ {
+ return result;
+ }
+ }
+ else
+ {
+ skipped++;
+ }
+ }
+
+ ASSERT(mFunctions.size() == mCurrentIndex + skipped);
+ return INITDAG_SUCCESS;
+ }
+
+ void fillDataStructures(std::vector<Record> *records, std::map<int, int> *idToIndex)
+ {
+ ASSERT(records->empty());
+ ASSERT(idToIndex->empty());
+
+ records->resize(mCurrentIndex);
+
+ for (auto &it : mFunctions)
+ {
+ CreatorFunctionData &data = it.second;
+ // Skip unimplemented functions
+ if (!data.definitionNode)
+ {
+ continue;
+ }
+ ASSERT(data.index < records->size());
+ Record &record = (*records)[data.index];
+
+ record.node = data.definitionNode;
+
+ record.callees.reserve(data.callees.size());
+ for (auto &callee : data.callees)
+ {
+ record.callees.push_back(static_cast<int>(callee->index));
+ }
+
+ (*idToIndex)[it.first] = static_cast<int>(data.index);
+ }
+ }
+
+ private:
+ struct CreatorFunctionData
+ {
+ CreatorFunctionData()
+ : definitionNode(nullptr), name(""), index(0), indexAssigned(false), visiting(false)
+ {}
+
+ std::set<CreatorFunctionData *> callees;
+ TIntermFunctionDefinition *definitionNode;
+ ImmutableString name;
+ size_t index;
+ bool indexAssigned;
+ bool visiting;
+ };
+
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
+ {
+ // Create the record if need be and remember the definition node.
+ mCurrentFunction = &mFunctions[node->getFunction()->uniqueId().get()];
+ // Name will be overwritten here. If we've already traversed the prototype of this function,
+ // it should have had the same name.
+ ASSERT(mCurrentFunction->name == "" ||
+ mCurrentFunction->name == node->getFunction()->name());
+ mCurrentFunction->name = node->getFunction()->name();
+ mCurrentFunction->definitionNode = node;
+
+ node->getBody()->traverse(this);
+ mCurrentFunction = nullptr;
+ return false;
+ }
+
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override
+ {
+ ASSERT(mCurrentFunction == nullptr);
+
+ // Function declaration, create an empty record.
+ auto &record = mFunctions[node->getFunction()->uniqueId().get()];
+ record.name = node->getFunction()->name();
+ }
+
+ // Track functions called from another function.
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (node->getOp() == EOpCallFunctionInAST)
+ {
+ // Function call, add the callees
+ auto it = mFunctions.find(node->getFunction()->uniqueId().get());
+ ASSERT(it != mFunctions.end());
+
+ // We might be traversing the initializer of a global variable. Even though function
+ // calls in global scope are forbidden by the parser, some subsequent AST
+ // transformations can add them to emulate particular features.
+ if (mCurrentFunction)
+ {
+ mCurrentFunction->callees.insert(&it->second);
+ }
+ }
+ return true;
+ }
+
+ // Recursively assigns indices to a sub DAG
+ InitResult assignIndicesInternal(CreatorFunctionData *root)
+ {
+ // Iterative implementation of the index assignment algorithm. A recursive version
+ // would be prettier but since the CallDAG creation runs before the limiting of the
+ // call depth, we might get stack overflows (computation of the call depth uses the
+ // CallDAG).
+
+ ASSERT(root);
+
+ if (root->indexAssigned)
+ {
+ return INITDAG_SUCCESS;
+ }
+
+ // If we didn't have to detect recursion, functionsToProcess could be a simple queue
+ // in which we add the function being processed's callees. However in order to detect
+ // recursion we need to know which functions we are currently visiting. For that reason
+ // functionsToProcess will look like a concatenation of segments of the form
+ // [F visiting = true, subset of F callees with visiting = false] and the following
+ // segment (if any) will be start with a callee of F.
+ // This way we can remember when we started visiting a function, to put visiting back
+ // to false.
+ TVector<CreatorFunctionData *> functionsToProcess;
+ functionsToProcess.push_back(root);
+
+ InitResult result = INITDAG_SUCCESS;
+
+ std::stringstream errorStream = sh::InitializeStream<std::stringstream>();
+
+ while (!functionsToProcess.empty())
+ {
+ CreatorFunctionData *function = functionsToProcess.back();
+
+ if (function->visiting)
+ {
+ function->visiting = false;
+ function->index = mCurrentIndex++;
+ function->indexAssigned = true;
+
+ functionsToProcess.pop_back();
+ continue;
+ }
+
+ if (!function->definitionNode)
+ {
+ errorStream << "Undefined function '" << function->name
+ << ")' used in the following call chain:";
+ result = INITDAG_UNDEFINED;
+ break;
+ }
+
+ if (function->indexAssigned)
+ {
+ functionsToProcess.pop_back();
+ continue;
+ }
+
+ function->visiting = true;
+
+ for (auto callee : function->callees)
+ {
+ functionsToProcess.push_back(callee);
+
+ // Check if the callee is already being visited after pushing it so that it appears
+ // in the chain printed in the info log.
+ if (callee->visiting)
+ {
+ errorStream << "Recursive function call in the following call chain:";
+ result = INITDAG_RECURSION;
+ break;
+ }
+ }
+
+ if (result != INITDAG_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ // The call chain is made of the function we were visiting when the error was detected.
+ if (result != INITDAG_SUCCESS)
+ {
+ bool first = true;
+ for (auto function : functionsToProcess)
+ {
+ if (function->visiting)
+ {
+ if (!first)
+ {
+ errorStream << " -> ";
+ }
+ errorStream << function->name << ")";
+ first = false;
+ }
+ }
+ if (mDiagnostics)
+ {
+ std::string errorStr = errorStream.str();
+ mDiagnostics->globalError(errorStr.c_str());
+ }
+ }
+
+ return result;
+ }
+
+ TDiagnostics *mDiagnostics;
+
+ std::map<int, CreatorFunctionData> mFunctions;
+ CreatorFunctionData *mCurrentFunction;
+ size_t mCurrentIndex;
+};
+
+// CallDAG
+
+CallDAG::CallDAG() {}
+
+CallDAG::~CallDAG() {}
+
+const size_t CallDAG::InvalidIndex = std::numeric_limits<size_t>::max();
+
+size_t CallDAG::findIndex(const TSymbolUniqueId &id) const
+{
+ auto it = mFunctionIdToIndex.find(id.get());
+
+ if (it == mFunctionIdToIndex.end())
+ {
+ return InvalidIndex;
+ }
+ else
+ {
+ return it->second;
+ }
+}
+
+const CallDAG::Record &CallDAG::getRecordFromIndex(size_t index) const
+{
+ ASSERT(index != InvalidIndex && index < mRecords.size());
+ return mRecords[index];
+}
+
+size_t CallDAG::size() const
+{
+ return mRecords.size();
+}
+
+void CallDAG::clear()
+{
+ mRecords.clear();
+ mFunctionIdToIndex.clear();
+}
+
+CallDAG::InitResult CallDAG::init(TIntermNode *root, TDiagnostics *diagnostics)
+{
+ CallDAGCreator creator(diagnostics);
+
+ // Creates the mapping of functions to callees
+ root->traverse(&creator);
+
+ // Does the topological sort and detects recursions
+ InitResult result = creator.assignIndices();
+ if (result != INITDAG_SUCCESS)
+ {
+ return result;
+ }
+
+ creator.fillDataStructures(&mRecords, &mFunctionIdToIndex);
+ return INITDAG_SUCCESS;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/CallDAG.h b/gfx/angle/checkout/src/compiler/translator/CallDAG.h
new file mode 100644
index 0000000000..813fc75573
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/CallDAG.h
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// CallDAG.h: Defines a call graph DAG of functions to be re-used accross
+// analyses, allows to efficiently traverse the functions in topological
+// order.
+
+#ifndef COMPILER_TRANSLATOR_CALLDAG_H_
+#define COMPILER_TRANSLATOR_CALLDAG_H_
+
+#include <map>
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+// The translator needs to analyze the the graph of the function calls
+// to run checks and analyses; since in GLSL recursion is not allowed
+// that graph is a DAG.
+// This class is used to precompute that function call DAG so that it
+// can be reused by multiple analyses.
+//
+// It stores a vector of function records, with one record per defined function.
+// Records are accessed by index but a function symbol id can be converted
+// to the index of the corresponding record. The records contain the AST node
+// of the function definition and the indices of the function's callees.
+//
+// In addition, records are in reverse topological order: a function F being
+// called by a function G will have index index(F) < index(G), that way
+// depth-first analysis becomes analysis in the order of indices.
+
+class CallDAG : angle::NonCopyable
+{
+ public:
+ CallDAG();
+ ~CallDAG();
+
+ struct Record
+ {
+ TIntermFunctionDefinition *node; // Guaranteed to be non-null.
+ std::vector<int> callees;
+ };
+
+ enum InitResult
+ {
+ INITDAG_SUCCESS,
+ INITDAG_RECURSION,
+ INITDAG_UNDEFINED,
+ };
+
+ // Returns INITDAG_SUCCESS if it was able to create the DAG, otherwise prints
+ // the initialization error in diagnostics, if present.
+ InitResult init(TIntermNode *root, TDiagnostics *diagnostics);
+
+ // Returns InvalidIndex if the function wasn't found
+ size_t findIndex(const TSymbolUniqueId &id) const;
+
+ const Record &getRecordFromIndex(size_t index) const;
+ size_t size() const;
+ void clear();
+
+ const static size_t InvalidIndex;
+
+ private:
+ std::vector<Record> mRecords;
+ std::map<int, int> mFunctionIdToIndex;
+
+ class CallDAGCreator;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_CALLDAG_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/CodeGen.cpp b/gfx/angle/checkout/src/compiler/translator/CodeGen.cpp
new file mode 100644
index 0000000000..6dc9485589
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/CodeGen.cpp
@@ -0,0 +1,75 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifdef ANGLE_ENABLE_ESSL
+# include "compiler/translator/TranslatorESSL.h"
+#endif // ANGLE_ENABLE_ESSL
+
+#ifdef ANGLE_ENABLE_GLSL
+# include "compiler/translator/TranslatorGLSL.h"
+#endif // ANGLE_ENABLE_GLSL
+
+#ifdef ANGLE_ENABLE_HLSL
+# include "compiler/translator/TranslatorHLSL.h"
+#endif // ANGLE_ENABLE_HLSL
+
+#ifdef ANGLE_ENABLE_VULKAN
+# include "compiler/translator/TranslatorVulkan.h"
+#endif // ANGLE_ENABLE_VULKAN
+
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+{
+#ifdef ANGLE_ENABLE_ESSL
+ if (IsOutputESSL(output))
+ {
+ return new TranslatorESSL(type, spec);
+ }
+#endif // ANGLE_ENABLE_ESSL
+
+#ifdef ANGLE_ENABLE_GLSL
+ if (IsOutputGLSL(output))
+ {
+ return new TranslatorGLSL(type, spec, output);
+ }
+#endif // ANGLE_ENABLE_GLSL
+
+#ifdef ANGLE_ENABLE_HLSL
+ if (IsOutputHLSL(output))
+ {
+ return new TranslatorHLSL(type, spec, output);
+ }
+#endif // ANGLE_ENABLE_HLSL
+
+#ifdef ANGLE_ENABLE_VULKAN
+ if (IsOutputVulkan(output))
+ {
+ return new TranslatorVulkan(type, spec);
+ }
+#endif // ANGLE_ENABLE_VULKAN
+
+ // Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API.
+ return nullptr;
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler *compiler)
+{
+ SafeDelete(compiler);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp b/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp
new file mode 100644
index 0000000000..e8bc6edd16
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp
@@ -0,0 +1,970 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// CollectVariables.cpp: Collect lists of shader interface variables based on the AST.
+
+#include "compiler/translator/CollectVariables.h"
+
+#include "angle_gl.h"
+#include "common/utilities.h"
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
+{
+ switch (blockStorage)
+ {
+ case EbsPacked:
+ return BLOCKLAYOUT_PACKED;
+ case EbsShared:
+ return BLOCKLAYOUT_SHARED;
+ case EbsStd140:
+ return BLOCKLAYOUT_STD140;
+ case EbsStd430:
+ return BLOCKLAYOUT_STD430;
+ default:
+ UNREACHABLE();
+ return BLOCKLAYOUT_SHARED;
+ }
+}
+
+// TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
+BlockType GetBlockType(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqUniform:
+ return BlockType::BLOCK_UNIFORM;
+ case EvqBuffer:
+ return BlockType::BLOCK_BUFFER;
+ case EvqPerVertexIn:
+ return BlockType::BLOCK_IN;
+ default:
+ UNREACHABLE();
+ return BlockType::BLOCK_UNIFORM;
+ }
+}
+
+template <class VarT>
+VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList)
+{
+ // TODO(zmo): optimize this function.
+ for (size_t ii = 0; ii < infoList->size(); ++ii)
+ {
+ if (name == (*infoList)[ii].name)
+ return &((*infoList)[ii]);
+ }
+
+ return nullptr;
+}
+
+// Note that this shouldn't be called for interface blocks - active information is collected for
+// individual fields in case of interface blocks.
+void MarkActive(ShaderVariable *variable)
+{
+ if (!variable->active)
+ {
+ if (variable->isStruct())
+ {
+ // Conservatively assume all fields are statically used as well.
+ for (auto &field : variable->fields)
+ {
+ MarkActive(&field);
+ }
+ }
+ ASSERT(variable->staticUse);
+ variable->active = true;
+ }
+}
+
+ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,
+ const TInterfaceBlock *interfaceBlock,
+ std::vector<InterfaceBlock> *infoList)
+{
+ ASSERT(interfaceBlock);
+ InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
+ ASSERT(namedBlock);
+
+ // Set static use on the parent interface block here
+ namedBlock->staticUse = true;
+ namedBlock->active = true;
+ return FindVariable(name, &namedBlock->fields);
+}
+
+// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
+// and interface blocks.
+class CollectVariablesTraverser : public TIntermTraverser
+{
+ public:
+ CollectVariablesTraverser(std::vector<Attribute> *attribs,
+ std::vector<OutputVariable> *outputVariables,
+ std::vector<Uniform> *uniforms,
+ std::vector<Varying> *inputVaryings,
+ std::vector<Varying> *outputVaryings,
+ std::vector<InterfaceBlock> *uniformBlocks,
+ std::vector<InterfaceBlock> *shaderStorageBlocks,
+ std::vector<InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior);
+
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+ void visitSymbol(TIntermSymbol *symbol) override;
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
+
+ private:
+ std::string getMappedName(const TSymbol *symbol) const;
+
+ void setFieldOrVariableProperties(const TType &type,
+ bool staticUse,
+ ShaderVariable *variableOut) const;
+ void setFieldProperties(const TType &type,
+ const ImmutableString &name,
+ bool staticUse,
+ ShaderVariable *variableOut) const;
+ void setCommonVariableProperties(const TType &type,
+ const TVariable &variable,
+ ShaderVariable *variableOut) const;
+
+ Attribute recordAttribute(const TIntermSymbol &variable) const;
+ OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
+ Varying recordVarying(const TIntermSymbol &variable) const;
+ void recordInterfaceBlock(const char *instanceName,
+ const TType &interfaceBlockType,
+ InterfaceBlock *interfaceBlock) const;
+ Uniform recordUniform(const TIntermSymbol &variable) const;
+
+ void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);
+
+ void recordBuiltInVaryingUsed(const TVariable &variable,
+ bool *addedFlag,
+ std::vector<Varying> *varyings);
+ void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);
+ void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);
+ InterfaceBlock *recordGLInUsed(const TType &glInType);
+ InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;
+
+ std::vector<Attribute> *mAttribs;
+ std::vector<OutputVariable> *mOutputVariables;
+ std::vector<Uniform> *mUniforms;
+ std::vector<Varying> *mInputVaryings;
+ std::vector<Varying> *mOutputVaryings;
+ std::vector<InterfaceBlock> *mUniformBlocks;
+ std::vector<InterfaceBlock> *mShaderStorageBlocks;
+ std::vector<InterfaceBlock> *mInBlocks;
+
+ std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
+
+ // Shader uniforms
+ bool mDepthRangeAdded;
+
+ // Vertex Shader builtins
+ bool mInstanceIDAdded;
+ bool mVertexIDAdded;
+ bool mPointSizeAdded;
+ bool mDrawIDAdded;
+ bool mBaseVertexAdded;
+ bool mBaseInstanceAdded;
+
+ // Vertex Shader and Geometry Shader builtins
+ bool mPositionAdded;
+
+ // Fragment Shader builtins
+ bool mPointCoordAdded;
+ bool mFrontFacingAdded;
+ bool mFragCoordAdded;
+ bool mLastFragDataAdded;
+ bool mFragColorAdded;
+ bool mFragDataAdded;
+ bool mFragDepthEXTAdded;
+ bool mFragDepthAdded;
+ bool mSecondaryFragColorEXTAdded;
+ bool mSecondaryFragDataEXTAdded;
+
+ // Geometry Shader builtins
+ bool mPerVertexInAdded;
+ bool mPrimitiveIDInAdded;
+ bool mInvocationIDAdded;
+
+ // Geometry Shader and Fragment Shader builtins
+ bool mPrimitiveIDAdded;
+ bool mLayerAdded;
+
+ ShHashFunction64 mHashFunction;
+
+ GLenum mShaderType;
+ const TExtensionBehavior &mExtensionBehavior;
+};
+
+CollectVariablesTraverser::CollectVariablesTraverser(
+ std::vector<sh::Attribute> *attribs,
+ std::vector<sh::OutputVariable> *outputVariables,
+ std::vector<sh::Uniform> *uniforms,
+ std::vector<sh::Varying> *inputVaryings,
+ std::vector<sh::Varying> *outputVaryings,
+ std::vector<sh::InterfaceBlock> *uniformBlocks,
+ std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
+ std::vector<sh::InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mAttribs(attribs),
+ mOutputVariables(outputVariables),
+ mUniforms(uniforms),
+ mInputVaryings(inputVaryings),
+ mOutputVaryings(outputVaryings),
+ mUniformBlocks(uniformBlocks),
+ mShaderStorageBlocks(shaderStorageBlocks),
+ mInBlocks(inBlocks),
+ mDepthRangeAdded(false),
+ mInstanceIDAdded(false),
+ mVertexIDAdded(false),
+ mPointSizeAdded(false),
+ mDrawIDAdded(false),
+ mBaseVertexAdded(false),
+ mBaseInstanceAdded(false),
+ mPositionAdded(false),
+ mPointCoordAdded(false),
+ mFrontFacingAdded(false),
+ mFragCoordAdded(false),
+ mLastFragDataAdded(false),
+ mFragColorAdded(false),
+ mFragDataAdded(false),
+ mFragDepthEXTAdded(false),
+ mFragDepthAdded(false),
+ mSecondaryFragColorEXTAdded(false),
+ mSecondaryFragDataEXTAdded(false),
+ mPerVertexInAdded(false),
+ mPrimitiveIDInAdded(false),
+ mInvocationIDAdded(false),
+ mPrimitiveIDAdded(false),
+ mLayerAdded(false),
+ mHashFunction(hashFunction),
+ mShaderType(shaderType),
+ mExtensionBehavior(extensionBehavior)
+{}
+
+std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
+{
+ return HashName(symbol, mHashFunction, nullptr).data();
+}
+
+void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,
+ ShaderVariable *info)
+{
+ const TType &type = variable.getType();
+
+ info->name = variable.name().data();
+ info->mappedName = variable.name().data();
+ info->type = GLVariableType(type);
+ info->precision = GLVariablePrecision(type);
+ if (auto *arraySizes = type.getArraySizes())
+ {
+ info->arraySizes.assign(arraySizes->begin(), arraySizes->end());
+ }
+}
+
+void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
+ bool *addedFlag,
+ std::vector<Varying> *varyings)
+{
+ ASSERT(varyings);
+ if (!(*addedFlag))
+ {
+ Varying info;
+ setBuiltInInfoFromSymbol(variable, &info);
+ info.staticUse = true;
+ info.active = true;
+ info.isInvariant = mSymbolTable->isVaryingInvariant(variable);
+ varyings->push_back(info);
+ (*addedFlag) = true;
+ }
+}
+
+void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,
+ bool *addedFlag)
+{
+ if (!(*addedFlag))
+ {
+ OutputVariable info;
+ setBuiltInInfoFromSymbol(variable, &info);
+ info.staticUse = true;
+ info.active = true;
+ mOutputVariables->push_back(info);
+ (*addedFlag) = true;
+ }
+}
+
+void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,
+ bool *addedFlag)
+{
+ if (!(*addedFlag))
+ {
+ Attribute info;
+ setBuiltInInfoFromSymbol(variable, &info);
+ info.staticUse = true;
+ info.active = true;
+ info.location = -1;
+ mAttribs->push_back(info);
+ (*addedFlag) = true;
+ }
+}
+
+InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
+{
+ if (!mPerVertexInAdded)
+ {
+ ASSERT(glInType.getQualifier() == EvqPerVertexIn);
+ InterfaceBlock info;
+ recordInterfaceBlock("gl_in", glInType, &info);
+
+ mPerVertexInAdded = true;
+ mInBlocks->push_back(info);
+ return &mInBlocks->back();
+ }
+ else
+ {
+ return FindVariable(ImmutableString("gl_PerVertex"), mInBlocks);
+ }
+}
+
+bool CollectVariablesTraverser::visitInvariantDeclaration(Visit visit,
+ TIntermInvariantDeclaration *node)
+{
+ // We should not mark variables as active just based on an invariant declaration, so we don't
+ // traverse the symbols declared invariant.
+ return false;
+}
+
+// We want to check whether a uniform/varying is active because we need to skip updating inactive
+// ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,
+// and gl_FrontFacing count toward varying counting if they are active in a fragment shader.
+void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
+{
+ ASSERT(symbol != nullptr);
+
+ if (symbol->variable().symbolType() == SymbolType::AngleInternal ||
+ symbol->variable().symbolType() == SymbolType::Empty)
+ {
+ // Internal variables or nameless variables are not collected.
+ return;
+ }
+
+ ShaderVariable *var = nullptr;
+
+ const ImmutableString &symbolName = symbol->getName();
+
+ // Check the qualifier from the variable, not from the symbol node. The node may have a
+ // different qualifier if it's the result of a folded ternary node.
+ TQualifier qualifier = symbol->variable().getType().getQualifier();
+
+ if (IsVaryingIn(qualifier))
+ {
+ var = FindVariable(symbolName, mInputVaryings);
+ }
+ else if (IsVaryingOut(qualifier))
+ {
+ var = FindVariable(symbolName, mOutputVaryings);
+ }
+ else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
+ {
+ UNREACHABLE();
+ }
+ else if (symbolName == "gl_DepthRange")
+ {
+ ASSERT(qualifier == EvqUniform);
+
+ if (!mDepthRangeAdded)
+ {
+ Uniform info;
+ const char kName[] = "gl_DepthRange";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_NONE;
+ info.precision = GL_NONE;
+ info.staticUse = true;
+ info.active = true;
+
+ ShaderVariable nearInfo(GL_FLOAT);
+ const char kNearName[] = "near";
+ nearInfo.name = kNearName;
+ nearInfo.mappedName = kNearName;
+ nearInfo.precision = GL_HIGH_FLOAT;
+ nearInfo.staticUse = true;
+ nearInfo.active = true;
+
+ ShaderVariable farInfo(GL_FLOAT);
+ const char kFarName[] = "far";
+ farInfo.name = kFarName;
+ farInfo.mappedName = kFarName;
+ farInfo.precision = GL_HIGH_FLOAT;
+ farInfo.staticUse = true;
+ farInfo.active = true;
+
+ ShaderVariable diffInfo(GL_FLOAT);
+ const char kDiffName[] = "diff";
+ diffInfo.name = kDiffName;
+ diffInfo.mappedName = kDiffName;
+ diffInfo.precision = GL_HIGH_FLOAT;
+ diffInfo.staticUse = true;
+ diffInfo.active = true;
+
+ info.fields.push_back(nearInfo);
+ info.fields.push_back(farInfo);
+ info.fields.push_back(diffInfo);
+
+ mUniforms->push_back(info);
+ mDepthRangeAdded = true;
+ }
+ }
+ else
+ {
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ case EvqVertexIn:
+ var = FindVariable(symbolName, mAttribs);
+ break;
+ case EvqFragmentOut:
+ var = FindVariable(symbolName, mOutputVariables);
+ break;
+ case EvqUniform:
+ {
+ const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
+ if (interfaceBlock)
+ {
+ var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);
+ }
+ else
+ {
+ var = FindVariable(symbolName, mUniforms);
+ }
+
+ // It's an internal error to reference an undefined user uniform
+ ASSERT(!symbolName.beginsWith("gl_") || var);
+ }
+ break;
+ case EvqBuffer:
+ {
+ const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
+ var =
+ FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
+ }
+ break;
+ case EvqFragCoord:
+ recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);
+ return;
+ case EvqFrontFacing:
+ recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);
+ return;
+ case EvqPointCoord:
+ recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);
+ return;
+ case EvqInstanceID:
+ // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
+ // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
+ // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1
+ // shaders.
+ recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);
+ return;
+ case EvqVertexID:
+ recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);
+ return;
+ case EvqPosition:
+ recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);
+ return;
+ case EvqPointSize:
+ recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);
+ return;
+ case EvqDrawID:
+ recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded);
+ return;
+ case EvqBaseVertex:
+ recordBuiltInAttributeUsed(symbol->variable(), &mBaseVertexAdded);
+ return;
+ case EvqBaseInstance:
+ recordBuiltInAttributeUsed(symbol->variable(), &mBaseInstanceAdded);
+ return;
+ case EvqLastFragData:
+ recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);
+ return;
+ case EvqFragColor:
+ recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);
+ return;
+ case EvqFragData:
+ if (!mFragDataAdded)
+ {
+ OutputVariable info;
+ setBuiltInInfoFromSymbol(symbol->variable(), &info);
+ if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
+ {
+ ASSERT(info.arraySizes.size() == 1u);
+ info.arraySizes.back() = 1u;
+ }
+ info.staticUse = true;
+ info.active = true;
+ mOutputVariables->push_back(info);
+ mFragDataAdded = true;
+ }
+ return;
+ case EvqFragDepthEXT:
+ recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthEXTAdded);
+ return;
+ case EvqFragDepth:
+ recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);
+ return;
+ case EvqSecondaryFragColorEXT:
+ recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);
+ return;
+ case EvqSecondaryFragDataEXT:
+ recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);
+ return;
+ case EvqInvocationID:
+ recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);
+ break;
+ case EvqPrimitiveIDIn:
+ recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);
+ break;
+ case EvqPrimitiveID:
+ if (mShaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
+ mOutputVaryings);
+ }
+ else
+ {
+ ASSERT(mShaderType == GL_FRAGMENT_SHADER);
+ recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
+ mInputVaryings);
+ }
+ break;
+ case EvqLayer:
+ if (mShaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);
+ }
+ else if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);
+ }
+ else
+ {
+ ASSERT(mShaderType == GL_VERTEX_SHADER &&
+ (IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) ||
+ IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (var)
+ {
+ MarkActive(var);
+ }
+}
+
+void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
+ bool staticUse,
+ ShaderVariable *variableOut) const
+{
+ ASSERT(variableOut);
+
+ variableOut->staticUse = staticUse;
+
+ const TStructure *structure = type.getStruct();
+ if (!structure)
+ {
+ variableOut->type = GLVariableType(type);
+ variableOut->precision = GLVariablePrecision(type);
+ }
+ else
+ {
+ // Structures use a NONE type that isn't exposed outside ANGLE.
+ variableOut->type = GL_NONE;
+ if (structure->symbolType() != SymbolType::Empty)
+ {
+ variableOut->structName = structure->name().data();
+ }
+
+ const TFieldList &fields = structure->fields();
+
+ for (const TField *field : fields)
+ {
+ // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
+ // ShaderVariable objects.
+ ShaderVariable fieldVariable;
+ setFieldProperties(*field->type(), field->name(), staticUse, &fieldVariable);
+ variableOut->fields.push_back(fieldVariable);
+ }
+ }
+ if (auto *arraySizes = type.getArraySizes())
+ {
+ variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end());
+ }
+}
+
+void CollectVariablesTraverser::setFieldProperties(const TType &type,
+ const ImmutableString &name,
+ bool staticUse,
+ ShaderVariable *variableOut) const
+{
+ ASSERT(variableOut);
+ setFieldOrVariableProperties(type, staticUse, variableOut);
+ variableOut->name.assign(name.data(), name.length());
+ variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();
+}
+
+void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
+ const TVariable &variable,
+ ShaderVariable *variableOut) const
+{
+ ASSERT(variableOut);
+
+ variableOut->staticUse = mSymbolTable->isStaticallyUsed(variable);
+ setFieldOrVariableProperties(type, variableOut->staticUse, variableOut);
+ ASSERT(variable.symbolType() != SymbolType::Empty);
+ variableOut->name.assign(variable.name().data(), variable.name().length());
+ variableOut->mappedName = getMappedName(&variable);
+}
+
+Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
+{
+ const TType &type = variable.getType();
+ ASSERT(!type.getStruct());
+
+ Attribute attribute;
+ setCommonVariableProperties(type, variable.variable(), &attribute);
+
+ attribute.location = type.getLayoutQualifier().location;
+ return attribute;
+}
+
+OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
+{
+ const TType &type = variable.getType();
+ ASSERT(!type.getStruct());
+
+ OutputVariable outputVariable;
+ setCommonVariableProperties(type, variable.variable(), &outputVariable);
+
+ outputVariable.location = type.getLayoutQualifier().location;
+ outputVariable.index = type.getLayoutQualifier().index;
+ return outputVariable;
+}
+
+Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
+{
+ const TType &type = variable.getType();
+
+ Varying varying;
+ setCommonVariableProperties(type, variable.variable(), &varying);
+ varying.location = type.getLayoutQualifier().location;
+
+ switch (type.getQualifier())
+ {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqVertexOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ case EvqGeometryOut:
+ if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
+ {
+ varying.isInvariant = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ varying.interpolation = GetInterpolationType(type.getQualifier());
+ return varying;
+}
+
+// TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
+void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
+ const TType &interfaceBlockType,
+ InterfaceBlock *interfaceBlock) const
+{
+ ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
+ ASSERT(interfaceBlock);
+
+ const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
+ ASSERT(blockType);
+
+ interfaceBlock->name = blockType->name().data();
+ interfaceBlock->mappedName = getMappedName(blockType);
+ if (instanceName != nullptr)
+ {
+ interfaceBlock->instanceName = instanceName;
+ const TSymbol *blockSymbol = nullptr;
+ if (strncmp(instanceName, "gl_in", 5u) == 0)
+ {
+ blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
+ }
+ else
+ {
+ blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
+ }
+ ASSERT(blockSymbol && blockSymbol->isVariable());
+ interfaceBlock->staticUse =
+ mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
+ }
+ ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
+ interfaceBlock->arraySize =
+ interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
+
+ interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
+ if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
+ interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
+ {
+ // TODO(oetuaho): Remove setting isRowMajorLayout.
+ interfaceBlock->isRowMajorLayout = false;
+ interfaceBlock->binding = blockType->blockBinding();
+ interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
+ }
+
+ // Gather field information
+ bool anyFieldStaticallyUsed = false;
+ for (const TField *field : blockType->fields())
+ {
+ const TType &fieldType = *field->type();
+
+ bool staticUse = false;
+ if (instanceName == nullptr)
+ {
+ // Static use of individual fields has been recorded, since they are present in the
+ // symbol table as variables.
+ const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
+ ASSERT(fieldSymbol && fieldSymbol->isVariable());
+ staticUse =
+ mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
+ if (staticUse)
+ {
+ anyFieldStaticallyUsed = true;
+ }
+ }
+
+ InterfaceBlockField fieldVariable;
+ setFieldProperties(fieldType, field->name(), staticUse, &fieldVariable);
+ fieldVariable.isRowMajorLayout =
+ (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
+ interfaceBlock->fields.push_back(fieldVariable);
+ }
+ if (anyFieldStaticallyUsed)
+ {
+ interfaceBlock->staticUse = true;
+ }
+}
+
+Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
+{
+ Uniform uniform;
+ setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
+ uniform.binding = variable.getType().getLayoutQualifier().binding;
+ uniform.imageUnitFormat =
+ GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
+ uniform.location = variable.getType().getLayoutQualifier().location;
+ uniform.offset = variable.getType().getLayoutQualifier().offset;
+ uniform.readonly = variable.getType().getMemoryQualifier().readonly;
+ uniform.writeonly = variable.getType().getMemoryQualifier().writeonly;
+ return uniform;
+}
+
+bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ const TIntermSequence &sequence = *(node->getSequence());
+ ASSERT(!sequence.empty());
+
+ const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
+ TQualifier qualifier = typedNode.getQualifier();
+
+ bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
+ qualifier == EvqFragmentOut || qualifier == EvqUniform ||
+ IsVarying(qualifier);
+
+ if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
+ {
+ return true;
+ }
+
+ for (TIntermNode *variableNode : sequence)
+ {
+ // The only case in which the sequence will not contain a TIntermSymbol node is
+ // initialization. It will contain a TInterBinary node in that case. Since attributes,
+ // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
+ // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
+ const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
+ if (variable.variable().symbolType() == SymbolType::AngleInternal)
+ {
+ // Internal variables are not collected.
+ continue;
+ }
+
+ // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
+ if (typedNode.getBasicType() == EbtInterfaceBlock)
+ {
+ InterfaceBlock interfaceBlock;
+ recordInterfaceBlock(variable.variable().symbolType() != SymbolType::Empty
+ ? variable.getName().data()
+ : nullptr,
+ variable.getType(), &interfaceBlock);
+
+ switch (qualifier)
+ {
+ case EvqUniform:
+ mUniformBlocks->push_back(interfaceBlock);
+ break;
+ case EvqBuffer:
+ mShaderStorageBlocks->push_back(interfaceBlock);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ ASSERT(variable.variable().symbolType() != SymbolType::Empty);
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ case EvqVertexIn:
+ mAttribs->push_back(recordAttribute(variable));
+ break;
+ case EvqFragmentOut:
+ mOutputVariables->push_back(recordOutputVariable(variable));
+ break;
+ case EvqUniform:
+ mUniforms->push_back(recordUniform(variable));
+ break;
+ default:
+ if (IsVaryingIn(qualifier))
+ {
+ mInputVaryings->push_back(recordVarying(variable));
+ }
+ else
+ {
+ ASSERT(IsVaryingOut(qualifier));
+ mOutputVaryings->push_back(recordVarying(variable));
+ }
+ break;
+ }
+ }
+ }
+
+ // None of the recorded variables can have initializers, so we don't need to traverse the
+ // declarators.
+ return false;
+}
+
+// TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing
+// GL_EXT_shader_io_blocks.
+InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(
+ const ImmutableString &blockName) const
+{
+ InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
+ if (!namedBlock)
+ {
+ namedBlock = FindVariable(blockName, mShaderStorageBlocks);
+ }
+ return namedBlock;
+}
+
+bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
+{
+ if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
+ {
+ // NOTE: we do not determine static use / activeness for individual blocks of an array.
+ TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
+ ASSERT(blockNode);
+
+ TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
+ ASSERT(constantUnion);
+
+ InterfaceBlock *namedBlock = nullptr;
+
+ bool traverseIndexExpression = false;
+ TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
+ if (interfaceIndexingNode)
+ {
+ TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped();
+ ASSERT(interfaceNode);
+
+ const TType &interfaceType = interfaceNode->getType();
+ if (interfaceType.getQualifier() == EvqPerVertexIn)
+ {
+ namedBlock = recordGLInUsed(interfaceType);
+ ASSERT(namedBlock);
+
+ // We need to continue traversing to collect useful variables in the index
+ // expression of gl_in.
+ traverseIndexExpression = true;
+ }
+ }
+
+ const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
+ if (!namedBlock)
+ {
+ namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
+ }
+ ASSERT(namedBlock);
+ ASSERT(namedBlock->staticUse);
+ namedBlock->active = true;
+ unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
+ ASSERT(fieldIndex < namedBlock->fields.size());
+ // TODO(oetuaho): Would be nicer to record static use of fields of named interface blocks
+ // more accurately at parse time - now we only mark the fields statically used if they are
+ // active. http://anglebug.com/2440
+ namedBlock->fields[fieldIndex].staticUse = true;
+ namedBlock->fields[fieldIndex].active = true;
+
+ if (traverseIndexExpression)
+ {
+ ASSERT(interfaceIndexingNode);
+ interfaceIndexingNode->getRight()->traverse(this);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+} // anonymous namespace
+
+void CollectVariables(TIntermBlock *root,
+ std::vector<Attribute> *attributes,
+ std::vector<OutputVariable> *outputVariables,
+ std::vector<Uniform> *uniforms,
+ std::vector<Varying> *inputVaryings,
+ std::vector<Varying> *outputVaryings,
+ std::vector<InterfaceBlock> *uniformBlocks,
+ std::vector<InterfaceBlock> *shaderStorageBlocks,
+ std::vector<InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior)
+{
+ CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
+ outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
+ hashFunction, symbolTable, shaderType, extensionBehavior);
+ root->traverse(&collect);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/CollectVariables.h b/gfx/angle/checkout/src/compiler/translator/CollectVariables.h
new file mode 100644
index 0000000000..84494a1433
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/CollectVariables.h
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// CollectVariables.h: Collect lists of shader interface variables based on the AST.
+
+#ifndef COMPILER_TRANSLATOR_COLLECTVARIABLES_H_
+#define COMPILER_TRANSLATOR_COLLECTVARIABLES_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+#include "compiler/translator/ExtensionBehavior.h"
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void CollectVariables(TIntermBlock *root,
+ std::vector<Attribute> *attributes,
+ std::vector<OutputVariable> *outputVariables,
+ std::vector<Uniform> *uniforms,
+ std::vector<Varying> *inputVaryings,
+ std::vector<Varying> *outputVaryings,
+ std::vector<InterfaceBlock> *uniformBlocks,
+ std::vector<InterfaceBlock> *shaderStorageBlocks,
+ std::vector<InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_COLLECTVARIABLES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Common.h b/gfx/angle/checkout/src/compiler/translator/Common.h
new file mode 100644
index 0000000000..179cfe21ee
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Common.h
@@ -0,0 +1,151 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_COMMON_H_
+#define COMPILER_TRANSLATOR_COMMON_H_
+
+#include <stdio.h>
+#include <limits>
+#include <map>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "common/third_party/smhasher/src/PMurHash.h"
+#include "compiler/translator/PoolAlloc.h"
+
+namespace sh
+{
+
+struct TSourceLoc
+{
+ int first_file;
+ int first_line;
+ int last_file;
+ int last_line;
+};
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE \
+ void *operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \
+ void *operator new(size_t, void *_Where) { return (_Where); } \
+ void operator delete(void *) {} \
+ void operator delete(void *, void *) {} \
+ void *operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \
+ void *operator new[](size_t, void *_Where) { return (_Where); } \
+ void operator delete[](void *) {} \
+ void operator delete[](void *, void *) {}
+
+//
+// Pool version of string.
+//
+typedef pool_allocator<char> TStringAllocator;
+typedef std::basic_string<char, std::char_traits<char>, TStringAllocator> TString;
+typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream;
+
+//
+// Persistent string memory. Should only be used for strings that survive
+// across compiles.
+//
+#define TPersistString std::string
+#define TPersistStringStream std::ostringstream
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T>
+class TVector : public std::vector<T, pool_allocator<T>>
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+
+ typedef typename std::vector<T, pool_allocator<T>>::size_type size_type;
+ TVector() : std::vector<T, pool_allocator<T>>() {}
+ TVector(const pool_allocator<T> &a) : std::vector<T, pool_allocator<T>>(a) {}
+ TVector(size_type i) : std::vector<T, pool_allocator<T>>(i) {}
+};
+
+template <class K, class D, class H = std::hash<K>, class CMP = std::equal_to<K>>
+class TUnorderedMap : public std::unordered_map<K, D, H, CMP, pool_allocator<std::pair<const K, D>>>
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ typedef pool_allocator<std::pair<const K, D>> tAllocator;
+
+ TUnorderedMap() : std::unordered_map<K, D, H, CMP, tAllocator>() {}
+ // use correct two-stage name lookup supported in gcc 3.4 and above
+ TUnorderedMap(const tAllocator &a)
+ : std::unordered_map<K, D, H, CMP, tAllocator>(
+ std::unordered_map<K, D, H, CMP, tAllocator>::key_compare(),
+ a)
+ {}
+};
+
+template <class K, class D, class CMP = std::less<K>>
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D>>>
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ typedef pool_allocator<std::pair<const K, D>> tAllocator;
+
+ TMap() : std::map<K, D, CMP, tAllocator>() {}
+ // use correct two-stage name lookup supported in gcc 3.4 and above
+ TMap(const tAllocator &a)
+ : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a)
+ {}
+};
+
+// Integer to TString conversion
+template <typename T>
+inline TString str(T i)
+{
+ ASSERT(std::numeric_limits<T>::is_integer);
+ char buffer[((8 * sizeof(T)) / 3) + 3];
+ const char *formatStr = std::numeric_limits<T>::is_signed ? "%d" : "%u";
+ snprintf(buffer, sizeof(buffer), formatStr, i);
+ return buffer;
+}
+
+// Allocate a char array in the global memory pool. str must be a null terminated string. strLength
+// is the length without the null terminator.
+inline const char *AllocatePoolCharArray(const char *str, size_t strLength)
+{
+ size_t requiredSize = strLength + 1;
+ char *buffer = static_cast<char *>(GetGlobalPoolAllocator()->allocate(requiredSize));
+ memcpy(buffer, str, requiredSize);
+ ASSERT(buffer[strLength] == '\0');
+ return buffer;
+}
+
+// Initialize a new stream which must be imbued with the classic locale
+template <typename T>
+T InitializeStream()
+{
+ T stream;
+ stream.imbue(std::locale::classic());
+ return stream;
+}
+
+} // namespace sh
+
+namespace std
+{
+template <>
+struct hash<sh::TString>
+{
+ size_t operator()(const sh::TString &s) const
+ {
+ return angle::PMurHash32(0, s.data(), static_cast<int>(s.length()));
+ }
+};
+} // namespace std
+
+#endif // COMPILER_TRANSLATOR_COMMON_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Compiler.cpp b/gfx/angle/checkout/src/compiler/translator/Compiler.cpp
new file mode 100644
index 0000000000..42a556f363
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Compiler.cpp
@@ -0,0 +1,1478 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/Compiler.h"
+
+#include <sstream>
+
+#include "angle_gl.h"
+#include "common/utilities.h"
+#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/CollectVariables.h"
+#include "compiler/translator/Initialize.h"
+#include "compiler/translator/IsASTDepthBelowLimit.h"
+#include "compiler/translator/OutputTree.h"
+#include "compiler/translator/ParseContext.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/tree_ops/AddAndTrueToLoopCondition.h"
+#include "compiler/translator/tree_ops/ClampFragDepth.h"
+#include "compiler/translator/tree_ops/ClampPointSize.h"
+#include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h"
+#include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
+#include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h"
+#include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h"
+#include "compiler/translator/tree_ops/EmulatePrecision.h"
+#include "compiler/translator/tree_ops/FoldExpressions.h"
+#include "compiler/translator/tree_ops/InitializeVariables.h"
+#include "compiler/translator/tree_ops/PruneEmptyCases.h"
+#include "compiler/translator/tree_ops/PruneNoOps.h"
+#include "compiler/translator/tree_ops/RegenerateStructNames.h"
+#include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h"
+#include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h"
+#include "compiler/translator/tree_ops/RemovePow.h"
+#include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h"
+#include "compiler/translator/tree_ops/RewriteDoWhile.h"
+#include "compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h"
+#include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h"
+#include "compiler/translator/tree_ops/SeparateDeclarations.h"
+#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
+#include "compiler/translator/tree_ops/SplitSequenceOperator.h"
+#include "compiler/translator/tree_ops/UnfoldShortCircuitAST.h"
+#include "compiler/translator/tree_ops/UseInterfaceBlockFields.h"
+#include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/ReplaceShadowingVariables.h"
+#include "compiler/translator/util.h"
+#include "third_party/compiler/ArrayBoundsClamper.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 = sh::InitializeStream<std::ostringstream>();
+ 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 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);
+}
+
+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 (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 length of 256, while ES2 leaves max token
+ // size undefined. ES3 defines a max size of 1024 characters.
+ switch (spec)
+ {
+ case SH_WEBGL_SPEC:
+ return 256;
+ default:
+ return 1024;
+ }
+}
+
+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_EXT:
+ return resources.MaxGeometryUniformComponents / 4;
+ default:
+ UNREACHABLE();
+ return -1;
+ }
+}
+
+namespace
+{
+
+class TScopedPoolAllocator
+{
+ public:
+ TScopedPoolAllocator(angle::PoolAllocator *allocator) : mAllocator(allocator)
+ {
+ mAllocator->push();
+ SetGlobalPoolAllocator(mAllocator);
+ }
+ ~TScopedPoolAllocator()
+ {
+ SetGlobalPoolAllocator(nullptr);
+ mAllocator->pop();
+ }
+
+ private:
+ angle::PoolAllocator *mAllocator;
+};
+
+class TScopedSymbolTableLevel
+{
+ public:
+ TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table)
+ {
+ ASSERT(mTable->isEmpty());
+ mTable->push();
+ }
+ ~TScopedSymbolTableLevel()
+ {
+ while (!mTable->isEmpty())
+ mTable->pop();
+ }
+
+ private:
+ TSymbolTable *mTable;
+};
+
+int MapSpecToShaderVersion(ShShaderSpec spec)
+{
+ switch (spec)
+ {
+ 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;
+ case SH_GL3_3_SPEC:
+ return 330;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+bool ValidateFragColorAndFragData(GLenum shaderType,
+ int shaderVersion,
+ const TSymbolTable &symbolTable,
+ TDiagnostics *diagnostics)
+{
+ if (shaderVersion > 100 || shaderType != GL_FRAGMENT_SHADER)
+ {
+ return true;
+ }
+
+ bool usesFragColor = false;
+ bool usesFragData = false;
+ // This validation is a bit stricter than the spec - it's only an error to write to
+ // both FragData and FragColor. But because it's better not to have reads from undefined
+ // variables, we always return an error if they are both referenced, rather than only if they
+ // are written.
+ if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_FragColor()) ||
+ symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()))
+ {
+ usesFragColor = true;
+ }
+ // Extension variables may not always be initialized (saves some time at symbol table init).
+ bool secondaryFragDataUsed =
+ symbolTable.gl_SecondaryFragDataEXT() != nullptr &&
+ symbolTable.isStaticallyUsed(*symbolTable.gl_SecondaryFragDataEXT());
+ if (symbolTable.isStaticallyUsed(*symbolTable.gl_FragData()) || secondaryFragDataUsed)
+ {
+ usesFragData = true;
+ }
+ if (usesFragColor && usesFragData)
+ {
+ const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
+ if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()) ||
+ secondaryFragDataUsed)
+ {
+ errorMessage =
+ "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
+ " and (gl_FragColor, gl_SecondaryFragColorEXT)";
+ }
+ diagnostics->globalError(errorMessage);
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+TShHandleBase::TShHandleBase()
+{
+ allocator.push();
+ SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase()
+{
+ SetGlobalPoolAllocator(nullptr);
+ allocator.popAll();
+}
+
+TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : mVariablesCollected(false),
+ mGLPositionInitialized(false),
+ mShaderType(type),
+ mShaderSpec(spec),
+ mOutputType(output),
+ mBuiltInFunctionEmulator(),
+ mDiagnostics(mInfoSink.info),
+ mSourcePath(nullptr),
+ mComputeShaderLocalSizeDeclared(false),
+ mComputeShaderLocalSize(1),
+ mGeometryShaderMaxVertices(-1),
+ mGeometryShaderInvocations(0),
+ mGeometryShaderInputPrimitiveType(EptUndefined),
+ mGeometryShaderOutputPrimitiveType(EptUndefined)
+{}
+
+TCompiler::~TCompiler() {}
+
+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
+ // of ESSL 1.00 as in Appendix A of the spec).
+ return (IsWebGLBasedSpec(mShaderSpec) && mShaderVersion == 100) ||
+ (compileOptions & SH_VALIDATE_LOOP_INDEXING);
+}
+
+bool TCompiler::Init(const ShBuiltInResources &resources)
+{
+ SetGlobalPoolAllocator(&allocator);
+
+ // Generate built-in symbol table.
+ if (!initBuiltInSymbolTable(resources))
+ return false;
+
+ mResources = resources;
+ setResourceString();
+
+ InitExtensionBehavior(resources, mExtensionBehavior);
+ mArrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
+ return true;
+}
+
+TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions)
+{
+ return compileTreeImpl(shaderStrings, numStrings, compileOptions);
+}
+
+TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
+ size_t numStrings,
+ const ShCompileOptions compileOptions)
+{
+ clearResults();
+
+ ASSERT(numStrings > 0);
+ ASSERT(GetGlobalPoolAllocator());
+
+ // Reset the extension behavior for each compilation unit.
+ ResetExtensionBehavior(mExtensionBehavior);
+
+ // If gl_DrawID is not supported, remove it from the available extensions
+ // Currently we only allow emulation of gl_DrawID
+ const bool glDrawIDSupported = (compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u;
+ if (!glDrawIDSupported)
+ {
+ auto it = mExtensionBehavior.find(TExtension::ANGLE_multi_draw);
+ if (it != mExtensionBehavior.end())
+ {
+ mExtensionBehavior.erase(it);
+ }
+ }
+
+ const bool glBaseVertexBaseInstanceSupported =
+ (compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u;
+ if (!glBaseVertexBaseInstanceSupported)
+ {
+ auto it = mExtensionBehavior.find(TExtension::ANGLE_base_vertex_base_instance);
+ if (it != mExtensionBehavior.end())
+ {
+ mExtensionBehavior.erase(it);
+ }
+ }
+
+ // First string is path of source file if flag is set. The actual source follows.
+ size_t firstSource = 0;
+ if (compileOptions & SH_SOURCE_PATH)
+ {
+ mSourcePath = shaderStrings[0];
+ ++firstSource;
+ }
+
+ TParseContext parseContext(mSymbolTable, mExtensionBehavior, mShaderType, mShaderSpec,
+ compileOptions, !IsDesktopGLSpec(mShaderSpec), &mDiagnostics,
+ getResources());
+
+ parseContext.setFragmentPrecisionHighOnESSL1(mResources.FragmentPrecisionHigh == 1);
+
+ // We preserve symbols at the built-in level from compile-to-compile.
+ // Start pushing the user-defined symbols at global level.
+ TScopedSymbolTableLevel globalLevel(&mSymbolTable);
+ ASSERT(mSymbolTable.atGlobalLevel());
+
+ // Parse shader.
+ if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr,
+ &parseContext) != 0)
+ {
+ return nullptr;
+ }
+
+ if (parseContext.getTreeRoot() == nullptr)
+ {
+ return nullptr;
+ }
+
+ setASTMetadata(parseContext);
+
+ if (!checkShaderVersion(&parseContext))
+ {
+ return nullptr;
+ }
+
+ TIntermBlock *root = parseContext.getTreeRoot();
+ if (!checkAndSimplifyAST(root, parseContext, compileOptions))
+ {
+ return nullptr;
+ }
+
+ return root;
+}
+
+bool TCompiler::checkShaderVersion(TParseContext *parseContext)
+{
+ if (MapSpecToShaderVersion(mShaderSpec) < mShaderVersion)
+ {
+ mDiagnostics.globalError("unsupported shader version");
+ return false;
+ }
+
+ ASSERT(parseContext);
+ switch (mShaderType)
+ {
+ case GL_COMPUTE_SHADER:
+ if (mShaderVersion < 310)
+ {
+ mDiagnostics.globalError("Compute shader is not supported in this shader version.");
+ return false;
+ }
+ break;
+
+ case GL_GEOMETRY_SHADER_EXT:
+ if (mShaderVersion < 310)
+ {
+ mDiagnostics.globalError(
+ "Geometry shader is not supported in this shader version.");
+ return false;
+ }
+ else
+ {
+ ASSERT(mShaderVersion == 310);
+ if (!parseContext->checkCanUseExtension(sh::TSourceLoc(),
+ TExtension::EXT_geometry_shader))
+ {
+ return false;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+void TCompiler::setASTMetadata(const TParseContext &parseContext)
+{
+ mShaderVersion = parseContext.getShaderVersion();
+
+ mPragma = parseContext.pragma();
+ mSymbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
+
+ mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
+ mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
+
+ mNumViews = parseContext.getNumViews();
+
+ if (mShaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType();
+ mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType();
+ mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices();
+ mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations();
+ }
+}
+
+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 (shouldRunLoopAndIndexingValidation(compileOptions) &&
+ !ValidateLimitations(root, mShaderType, &mSymbolTable, &mDiagnostics))
+ {
+ return false;
+ }
+
+ if (!ValidateFragColorAndFragData(mShaderType, mShaderVersion, mSymbolTable, &mDiagnostics))
+ {
+ return false;
+ }
+
+ // Fold expressions that could not be folded before validation that was done as a part of
+ // parsing.
+ FoldExpressions(root, &mDiagnostics);
+ // Folding should only be able to generate warnings.
+ ASSERT(mDiagnostics.numErrors() == 0);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ // 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, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ // Create the function DAG and check there is no recursion
+ if (!initCallDag(root))
+ {
+ return false;
+ }
+
+ if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth())
+ {
+ return false;
+ }
+
+ // Checks which functions are used and if "main" exists
+ mFunctionMetadata.clear();
+ mFunctionMetadata.resize(mCallDag.size());
+ if (!tagUsedFunctions())
+ {
+ return false;
+ }
+
+ if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
+ {
+ pruneUnusedFunctions(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+ if (IsSpecWithFunctionBodyNewScope(mShaderSpec, mShaderVersion))
+ {
+ ReplaceShadowingVariables(root, &mSymbolTable);
+ }
+
+ if (mShaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, mShaderType))
+ {
+ return false;
+ }
+
+ if (mShaderVersion >= 300 && mShaderType == GL_FRAGMENT_SHADER &&
+ !ValidateOutputs(root, getExtensionBehavior(), mResources.MaxDrawBuffers, &mDiagnostics))
+ {
+ return false;
+ }
+
+ // Fail compilation if precision emulation not supported.
+ if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision &&
+ !EmulatePrecision::SupportedInLanguage(mOutputType))
+ {
+ mDiagnostics.globalError("Precision emulation not supported for this output type.");
+ return false;
+ }
+
+ // Clamping uniform array bounds needs to happen after validateLimitations pass.
+ if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)
+ {
+ mArrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+ }
+
+ if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
+ (parseContext.isExtensionEnabled(TExtension::OVR_multiview2) ||
+ parseContext.isExtensionEnabled(TExtension::OVR_multiview)) &&
+ getShaderType() != GL_COMPUTE_SHADER)
+ {
+ DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, mShaderType, compileOptions,
+ mOutputType, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ // This pass might emit short circuits so keep it before the short circuit unfolding
+ if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)
+ {
+ RewriteDoWhile(root, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION)
+ {
+ AddAndTrueToLoopCondition(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)
+ {
+ UnfoldShortCircuitAST(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)
+ {
+ RemovePow(root, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions & SH_REGENERATE_STRUCT_NAMES)
+ {
+ RegenerateStructNames gen(&mSymbolTable);
+ root->traverse(&gen);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (mShaderType == GL_VERTEX_SHADER &&
+ IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw))
+ {
+ if ((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u)
+ {
+ EmulateGLDrawID(root, &mSymbolTable, &mUniforms,
+ shouldCollectVariables(compileOptions));
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+ }
+
+ if (mShaderType == GL_VERTEX_SHADER &&
+ IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_base_vertex_base_instance))
+ {
+ if ((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u)
+ {
+ EmulateGLBaseVertex(root, &mSymbolTable, &mUniforms,
+ shouldCollectVariables(compileOptions));
+ EmulateGLBaseInstance(root, &mSymbolTable, &mUniforms,
+ shouldCollectVariables(compileOptions));
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+ }
+
+ if (mShaderType == GL_FRAGMENT_SHADER && mShaderVersion == 100 && mResources.EXT_draw_buffers &&
+ mResources.MaxDrawBuffers > 1 &&
+ IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
+ {
+ EmulateGLFragColorBroadcast(root, mResources.MaxDrawBuffers, &mOutputVariables,
+ &mSymbolTable, mShaderVersion);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
+ ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor
+ : 0;
+
+ // 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 | simplifyScalarized,
+ &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ // Note that separate declarations need to be run before other AST transformations that
+ // generate new statements from expressions.
+ SeparateDeclarations(root);
+ mValidateASTOptions.validateMultiDeclarations = true;
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized,
+ &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ RemoveArrayLengthMethod(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ RemoveUnreferencedVariables(root, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ // 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 or RemoveUnreferencedVariables may have
+ // left switch statements that only contained an empty declaration inside the final case in an
+ // invalid state. Relies on that PruneNoOps and RemoveUnreferencedVariables have already been
+ // run.
+ PruneEmptyCases(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ // Built-in function emulation needs to happen after validateLimitations pass.
+ // TODO(jmadill): Remove global pool allocator.
+ GetGlobalPoolAllocator()->lock();
+ initBuiltInFunctionEmulator(&mBuiltInFunctionEmulator, compileOptions);
+ GetGlobalPoolAllocator()->unlock();
+ mBuiltInFunctionEmulator.markBuiltInFunctionsForEmulation(root);
+
+ bool highPrecisionSupported = mShaderVersion > 100 || mShaderType != GL_FRAGMENT_SHADER ||
+ mResources.FragmentPrecisionHigh == 1;
+ if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
+ {
+ ScalarizeVecAndMatConstructorArgs(root, mShaderType, highPrecisionSupported, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (shouldCollectVariables(compileOptions))
+ {
+ ASSERT(!mVariablesCollected);
+ CollectVariables(root, &mAttributes, &mOutputVariables, &mUniforms, &mInputVaryings,
+ &mOutputVaryings, &mUniformBlocks, &mShaderStorageBlocks, &mInBlocks,
+ mResources.HashFunction, &mSymbolTable, mShaderType, mExtensionBehavior);
+ collectInterfaceBlocks();
+ mVariablesCollected = true;
+ if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
+ {
+ useAllMembersInUnusedStandardAndSharedBlocks(root);
+ }
+ if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
+ {
+ int maxUniformVectors = GetMaxUniformVectorsForShaderType(mShaderType, mResources);
+ // 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, mUniforms))
+ {
+ mDiagnostics.globalError("too many uniforms");
+ return false;
+ }
+ }
+ if ((compileOptions & SH_INIT_OUTPUT_VARIABLES) && (mShaderType != GL_COMPUTE_SHADER))
+ {
+ initializeOutputVariables(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Removing invariant declarations must be done after collecting variables.
+ // Otherwise, built-in invariant declarations don't apply.
+ if (RemoveInvariant(mShaderType, mShaderVersion, mOutputType, compileOptions))
+ {
+ RemoveInvariantDeclaration(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ // 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 (mShaderType == GL_VERTEX_SHADER && !mGLPositionInitialized &&
+ ((compileOptions & SH_INIT_GL_POSITION) || (mOutputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
+ {
+ initializeGLPosition(root);
+ mGLPositionInitialized = true;
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ // 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,
+ highPrecisionSupported, &mSymbolTable);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+
+ 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))
+ {
+ SimplifyLoopConditions(root,
+ IntermNodePatternMatcher::kArrayDeclaration |
+ IntermNodePatternMatcher::kNamelessStructDeclaration,
+ &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize,
+ highPrecisionSupported, &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE))
+ {
+ ClampPointSize(root, mResources.MaxPointSize, &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (getShaderType() == GL_FRAGMENT_SHADER && (compileOptions & SH_CLAMP_FRAG_DEPTH))
+ {
+ ClampFragDepth(root, &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions & SH_REWRITE_REPEATED_ASSIGN_TO_SWIZZLED)
+ {
+ sh::RewriteRepeatedAssignToSwizzled(root);
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC)
+ {
+ VectorizeVectorScalarArithmetic(root, &getSymbolTable());
+ if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TCompiler::compile(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptionsIn)
+{
+#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+ DumpFuzzerCase(shaderStrings, numStrings, mShaderType, mShaderSpec, mOutputType,
+ 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);
+ TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
+
+ if (root)
+ {
+ if (compileOptions & SH_INTERMEDIATE_TREE)
+ OutputTree(root, mInfoSink.info);
+
+ if (compileOptions & SH_OBJECT_CODE)
+ {
+ PerformanceDiagnostics perfDiagnostics(&mDiagnostics);
+ translate(root, compileOptions, &perfDiagnostics);
+ }
+
+ if (mShaderType == GL_VERTEX_SHADER)
+ {
+ bool lookForDrawID =
+ IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw) &&
+ ((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u);
+ bool lookForBaseVertexBaseInstance =
+ IsExtensionEnabled(mExtensionBehavior,
+ TExtension::ANGLE_base_vertex_base_instance) &&
+ ((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u);
+
+ if (lookForDrawID || lookForBaseVertexBaseInstance)
+ {
+ for (auto &uniform : mUniforms)
+ {
+ if (lookForDrawID && uniform.name == "angle_DrawID" &&
+ uniform.mappedName == "angle_DrawID")
+ {
+ uniform.name = "gl_DrawID";
+ }
+ else if (lookForBaseVertexBaseInstance && uniform.name == "angle_BaseVertex" &&
+ uniform.mappedName == "angle_BaseVertex")
+ {
+ uniform.name = "gl_BaseVertex";
+ }
+ else if (lookForBaseVertexBaseInstance &&
+ uniform.name == "angle_BaseInstance" &&
+ uniform.mappedName == "angle_BaseInstance")
+ {
+ uniform.name = "gl_BaseInstance";
+ }
+ }
+ }
+ }
+
+ // The IntermNode tree doesn't need to be deleted here, since the
+ // memory will be freed in a big chunk by the PoolAllocator.
+ return true;
+ }
+ return false;
+}
+
+bool TCompiler::initBuiltInSymbolTable(const ShBuiltInResources &resources)
+{
+ if (resources.MaxDrawBuffers < 1)
+ {
+ return false;
+ }
+ if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1)
+ {
+ return false;
+ }
+
+ mSymbolTable.initializeBuiltIns(mShaderType, mShaderSpec, resources);
+
+ return true;
+}
+
+void TCompiler::setResourceString()
+{
+ std::ostringstream strstream = sh::InitializeStream<std::ostringstream>();
+
+ // clang-format off
+ strstream << ":MaxVertexAttribs:" << mResources.MaxVertexAttribs
+ << ":MaxVertexUniformVectors:" << mResources.MaxVertexUniformVectors
+ << ":MaxVaryingVectors:" << mResources.MaxVaryingVectors
+ << ":MaxVertexTextureImageUnits:" << mResources.MaxVertexTextureImageUnits
+ << ":MaxCombinedTextureImageUnits:" << mResources.MaxCombinedTextureImageUnits
+ << ":MaxTextureImageUnits:" << mResources.MaxTextureImageUnits
+ << ":MaxFragmentUniformVectors:" << mResources.MaxFragmentUniformVectors
+ << ":MaxDrawBuffers:" << mResources.MaxDrawBuffers
+ << ":OES_standard_derivatives:" << mResources.OES_standard_derivatives
+ << ":OES_EGL_image_external:" << mResources.OES_EGL_image_external
+ << ":OES_EGL_image_external_essl3:" << mResources.OES_EGL_image_external_essl3
+ << ":NV_EGL_stream_consumer_external:" << mResources.NV_EGL_stream_consumer_external
+ << ":ARB_texture_rectangle:" << mResources.ARB_texture_rectangle
+ << ":EXT_draw_buffers:" << mResources.EXT_draw_buffers
+ << ":FragmentPrecisionHigh:" << mResources.FragmentPrecisionHigh
+ << ":MaxExpressionComplexity:" << mResources.MaxExpressionComplexity
+ << ":MaxCallStackDepth:" << mResources.MaxCallStackDepth
+ << ":MaxFunctionParameters:" << mResources.MaxFunctionParameters
+ << ":EXT_blend_func_extended:" << mResources.EXT_blend_func_extended
+ << ":EXT_frag_depth:" << mResources.EXT_frag_depth
+ << ":EXT_shader_texture_lod:" << mResources.EXT_shader_texture_lod
+ << ":EXT_shader_framebuffer_fetch:" << mResources.EXT_shader_framebuffer_fetch
+ << ":NV_shader_framebuffer_fetch:" << mResources.NV_shader_framebuffer_fetch
+ << ":ARM_shader_framebuffer_fetch:" << mResources.ARM_shader_framebuffer_fetch
+ << ":OVR_multiview2:" << mResources.OVR_multiview2
+ << ":OVR_multiview:" << mResources.OVR_multiview
+ << ":EXT_YUV_target:" << mResources.EXT_YUV_target
+ << ":EXT_geometry_shader:" << mResources.EXT_geometry_shader
+ << ":OES_texture_3D:" << mResources.OES_texture_3D
+ << ":MaxVertexOutputVectors:" << mResources.MaxVertexOutputVectors
+ << ":MaxFragmentInputVectors:" << mResources.MaxFragmentInputVectors
+ << ":MinProgramTexelOffset:" << mResources.MinProgramTexelOffset
+ << ":MaxProgramTexelOffset:" << mResources.MaxProgramTexelOffset
+ << ":MaxDualSourceDrawBuffers:" << mResources.MaxDualSourceDrawBuffers
+ << ":MaxViewsOVR:" << mResources.MaxViewsOVR
+ << ":NV_draw_buffers:" << mResources.NV_draw_buffers
+ << ":WEBGL_debug_shader_precision:" << mResources.WEBGL_debug_shader_precision
+ << ":ANGLE_multi_draw:" << mResources.ANGLE_multi_draw
+ << ":ANGLE_base_vertex_base_instance:" << mResources.ANGLE_base_vertex_base_instance
+ << ":MinProgramTextureGatherOffset:" << mResources.MinProgramTextureGatherOffset
+ << ":MaxProgramTextureGatherOffset:" << mResources.MaxProgramTextureGatherOffset
+ << ":MaxImageUnits:" << mResources.MaxImageUnits
+ << ":MaxVertexImageUniforms:" << mResources.MaxVertexImageUniforms
+ << ":MaxFragmentImageUniforms:" << mResources.MaxFragmentImageUniforms
+ << ":MaxComputeImageUniforms:" << mResources.MaxComputeImageUniforms
+ << ":MaxCombinedImageUniforms:" << mResources.MaxCombinedImageUniforms
+ << ":MaxCombinedShaderOutputResources:" << mResources.MaxCombinedShaderOutputResources
+ << ":MaxComputeWorkGroupCountX:" << mResources.MaxComputeWorkGroupCount[0]
+ << ":MaxComputeWorkGroupCountY:" << mResources.MaxComputeWorkGroupCount[1]
+ << ":MaxComputeWorkGroupCountZ:" << mResources.MaxComputeWorkGroupCount[2]
+ << ":MaxComputeWorkGroupSizeX:" << mResources.MaxComputeWorkGroupSize[0]
+ << ":MaxComputeWorkGroupSizeY:" << mResources.MaxComputeWorkGroupSize[1]
+ << ":MaxComputeWorkGroupSizeZ:" << mResources.MaxComputeWorkGroupSize[2]
+ << ":MaxComputeUniformComponents:" << mResources.MaxComputeUniformComponents
+ << ":MaxComputeTextureImageUnits:" << mResources.MaxComputeTextureImageUnits
+ << ":MaxComputeAtomicCounters:" << mResources.MaxComputeAtomicCounters
+ << ":MaxComputeAtomicCounterBuffers:" << mResources.MaxComputeAtomicCounterBuffers
+ << ":MaxVertexAtomicCounters:" << mResources.MaxVertexAtomicCounters
+ << ":MaxFragmentAtomicCounters:" << mResources.MaxFragmentAtomicCounters
+ << ":MaxCombinedAtomicCounters:" << mResources.MaxCombinedAtomicCounters
+ << ":MaxAtomicCounterBindings:" << mResources.MaxAtomicCounterBindings
+ << ":MaxVertexAtomicCounterBuffers:" << mResources.MaxVertexAtomicCounterBuffers
+ << ":MaxFragmentAtomicCounterBuffers:" << mResources.MaxFragmentAtomicCounterBuffers
+ << ":MaxCombinedAtomicCounterBuffers:" << mResources.MaxCombinedAtomicCounterBuffers
+ << ":MaxAtomicCounterBufferSize:" << mResources.MaxAtomicCounterBufferSize
+ << ":MaxGeometryUniformComponents:" << mResources.MaxGeometryUniformComponents
+ << ":MaxGeometryUniformBlocks:" << mResources.MaxGeometryUniformBlocks
+ << ":MaxGeometryInputComponents:" << mResources.MaxGeometryInputComponents
+ << ":MaxGeometryOutputComponents:" << mResources.MaxGeometryOutputComponents
+ << ":MaxGeometryOutputVertices:" << mResources.MaxGeometryOutputVertices
+ << ":MaxGeometryTotalOutputComponents:" << mResources.MaxGeometryTotalOutputComponents
+ << ":MaxGeometryTextureImageUnits:" << mResources.MaxGeometryTextureImageUnits
+ << ":MaxGeometryAtomicCounterBuffers:" << mResources.MaxGeometryAtomicCounterBuffers
+ << ":MaxGeometryAtomicCounters:" << mResources.MaxGeometryAtomicCounters
+ << ":MaxGeometryShaderStorageBlocks:" << mResources.MaxGeometryShaderStorageBlocks
+ << ":MaxGeometryShaderInvocations:" << mResources.MaxGeometryShaderInvocations
+ << ":MaxGeometryImageUniforms:" << mResources.MaxGeometryImageUniforms;
+ // clang-format on
+
+ mBuiltInResourcesString = strstream.str();
+}
+
+void TCompiler::collectInterfaceBlocks()
+{
+ ASSERT(mInterfaceBlocks.empty());
+ mInterfaceBlocks.reserve(mUniformBlocks.size() + mShaderStorageBlocks.size() +
+ mInBlocks.size());
+ mInterfaceBlocks.insert(mInterfaceBlocks.end(), mUniformBlocks.begin(), mUniformBlocks.end());
+ mInterfaceBlocks.insert(mInterfaceBlocks.end(), mShaderStorageBlocks.begin(),
+ mShaderStorageBlocks.end());
+ mInterfaceBlocks.insert(mInterfaceBlocks.end(), mInBlocks.begin(), mInBlocks.end());
+}
+
+void TCompiler::clearResults()
+{
+ mArrayBoundsClamper.Cleanup();
+ mInfoSink.info.erase();
+ mInfoSink.obj.erase();
+ mInfoSink.debug.erase();
+ mDiagnostics.resetErrorCount();
+
+ mAttributes.clear();
+ mOutputVariables.clear();
+ mUniforms.clear();
+ mInputVaryings.clear();
+ mOutputVaryings.clear();
+ mInterfaceBlocks.clear();
+ mUniformBlocks.clear();
+ mShaderStorageBlocks.clear();
+ mInBlocks.clear();
+ mVariablesCollected = false;
+ mGLPositionInitialized = false;
+
+ mNumViews = -1;
+
+ mGeometryShaderInputPrimitiveType = EptUndefined;
+ mGeometryShaderOutputPrimitiveType = EptUndefined;
+ mGeometryShaderInvocations = 0;
+ mGeometryShaderMaxVertices = -1;
+
+ mBuiltInFunctionEmulator.cleanup();
+
+ mNameMap.clear();
+
+ mSourcePath = nullptr;
+
+ mSymbolTable.clearCompilationResults();
+}
+
+bool TCompiler::initCallDag(TIntermNode *root)
+{
+ mCallDag.clear();
+
+ switch (mCallDag.init(root, &mDiagnostics))
+ {
+ 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();
+ return true;
+}
+
+bool TCompiler::checkCallDepth()
+{
+ std::vector<int> depths(mCallDag.size());
+
+ for (size_t i = 0; i < mCallDag.size(); i++)
+ {
+ int depth = 0;
+ const CallDAG::Record &record = mCallDag.getRecordFromIndex(i);
+
+ for (const int &calleeIndex : record.callees)
+ {
+ depth = std::max(depth, depths[calleeIndex] + 1);
+ }
+
+ depths[i] = depth;
+
+ if (depth >= mResources.MaxCallStackDepth)
+ {
+ // Trace back the function chain to have a meaningful info log.
+ std::stringstream errorStream = sh::InitializeStream<std::stringstream>();
+ errorStream << "Call stack too deep (larger than " << mResources.MaxCallStackDepth
+ << ") with the following call chain: "
+ << record.node->getFunction()->name();
+
+ int currentFunction = static_cast<int>(i);
+ int currentDepth = depth;
+
+ while (currentFunction != -1)
+ {
+ errorStream
+ << " -> "
+ << mCallDag.getRecordFromIndex(currentFunction).node->getFunction()->name();
+
+ int nextFunction = -1;
+ for (const int &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
+ {
+ if (depths[calleeIndex] == currentDepth - 1)
+ {
+ currentDepth--;
+ nextFunction = calleeIndex;
+ }
+ }
+
+ currentFunction = nextFunction;
+ }
+
+ std::string errorStr = errorStream.str();
+ mDiagnostics.globalError(errorStr.c_str());
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+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).node->getFunction()->isMain())
+ {
+ internalTagUsedFunction(i);
+ return true;
+ }
+ }
+
+ mDiagnostics.globalError("Missing main()");
+ return false;
+}
+
+void TCompiler::internalTagUsedFunction(size_t index)
+{
+ if (mFunctionMetadata[index].used)
+ {
+ return;
+ }
+
+ mFunctionMetadata[index].used = true;
+
+ for (int calleeIndex : mCallDag.getRecordFromIndex(index).callees)
+ {
+ internalTagUsedFunction(calleeIndex);
+ }
+}
+
+// A predicate for the stl that returns if a top-level node is unused
+class TCompiler::UnusedPredicate
+{
+ public:
+ UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
+ : mCallDag(callDag), mMetadatas(metadatas)
+ {}
+
+ bool operator()(TIntermNode *node)
+ {
+ const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode();
+ const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition();
+
+ const TFunction *func = nullptr;
+
+ if (asFunctionDefinition)
+ {
+ func = asFunctionDefinition->getFunction();
+ }
+ else if (asFunctionPrototype)
+ {
+ func = asFunctionPrototype->getFunction();
+ }
+ if (func == nullptr)
+ {
+ return false;
+ }
+
+ size_t callDagIndex = mCallDag->findIndex(func->uniqueId());
+ if (callDagIndex == CallDAG::InvalidIndex)
+ {
+ // This happens only for unimplemented prototypes which are thus unused
+ ASSERT(asFunctionPrototype);
+ return true;
+ }
+
+ ASSERT(callDagIndex < mMetadatas->size());
+ return !(*mMetadatas)[callDagIndex].used;
+ }
+
+ private:
+ const CallDAG *mCallDag;
+ const std::vector<FunctionMetadata> *mMetadatas;
+};
+
+void TCompiler::pruneUnusedFunctions(TIntermBlock *root)
+{
+ UnusedPredicate isUnused(&mCallDag, &mFunctionMetadata);
+ TIntermSequence *sequence = root->getSequence();
+
+ if (!sequence->empty())
+ {
+ sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused),
+ sequence->end());
+ }
+}
+
+bool TCompiler::limitExpressionComplexity(TIntermBlock *root)
+{
+ if (!IsASTDepthBelowLimit(root, mResources.MaxExpressionComplexity))
+ {
+ mDiagnostics.globalError("Expression too complex.");
+ return false;
+ }
+
+ if (!ValidateMaxParameters(root, mResources.MaxFunctionParameters))
+ {
+ mDiagnostics.globalError("Function has too many parameters.");
+ return false;
+ }
+
+ return true;
+}
+
+bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions)
+{
+ return (compileOptions & SH_VARIABLES) != 0;
+}
+
+bool TCompiler::wereVariablesCollected() const
+{
+ return mVariablesCollected;
+}
+
+void TCompiler::initializeGLPosition(TIntermBlock *root)
+{
+ InitVariableList list;
+ sh::ShaderVariable var(GL_FLOAT_VEC4);
+ var.name = "gl_Position";
+ list.push_back(var);
+ InitializeVariables(root, list, &mSymbolTable, mShaderVersion, mExtensionBehavior, false,
+ false);
+}
+
+void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
+{
+ sh::InterfaceBlockList list;
+
+ for (const sh::InterfaceBlock &block : mUniformBlocks)
+ {
+ if (!block.staticUse &&
+ (block.layout == sh::BLOCKLAYOUT_STD140 || block.layout == sh::BLOCKLAYOUT_SHARED))
+ {
+ list.push_back(block);
+ }
+ }
+
+ sh::UseInterfaceBlockFields(root, list, mSymbolTable);
+}
+
+void TCompiler::initializeOutputVariables(TIntermBlock *root)
+{
+ InitVariableList list;
+ if (mShaderType == GL_VERTEX_SHADER || mShaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ for (const sh::Varying &var : mOutputVaryings)
+ {
+ list.push_back(var);
+ if (var.name == "gl_Position")
+ {
+ ASSERT(!mGLPositionInitialized);
+ mGLPositionInitialized = true;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(mShaderType == GL_FRAGMENT_SHADER);
+ for (const sh::OutputVariable &var : mOutputVariables)
+ {
+ list.push_back(var);
+ }
+ }
+ InitializeVariables(root, list, &mSymbolTable, mShaderVersion, mExtensionBehavior, false,
+ false);
+}
+
+const TExtensionBehavior &TCompiler::getExtensionBehavior() const
+{
+ return mExtensionBehavior;
+}
+
+const char *TCompiler::getSourcePath() const
+{
+ return mSourcePath;
+}
+
+const ShBuiltInResources &TCompiler::getResources() const
+{
+ return mResources;
+}
+
+const ArrayBoundsClamper &TCompiler::getArrayBoundsClamper() const
+{
+ return mArrayBoundsClamper;
+}
+
+ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
+{
+ return mResources.ArrayIndexClampingStrategy;
+}
+
+const BuiltInFunctionEmulator &TCompiler::getBuiltInFunctionEmulator() const
+{
+ return mBuiltInFunctionEmulator;
+}
+
+void TCompiler::writePragma(ShCompileOptions compileOptions)
+{
+ if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
+ {
+ TInfoSinkBase &sink = mInfoSink.obj;
+ if (mPragma.stdgl.invariantAll)
+ sink << "#pragma STDGL invariant(all)\n";
+ }
+}
+
+bool TCompiler::isVaryingDefined(const char *varyingName)
+{
+ ASSERT(mVariablesCollected);
+ for (size_t ii = 0; ii < mInputVaryings.size(); ++ii)
+ {
+ if (mInputVaryings[ii].name == varyingName)
+ {
+ return true;
+ }
+ }
+ for (size_t ii = 0; ii < mOutputVaryings.size(); ++ii)
+ {
+ if (mOutputVaryings[ii].name == varyingName)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void EmitWorkGroupSizeGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
+{
+ if (compiler.isComputeShaderLocalSizeDeclared())
+ {
+ const sh::WorkGroupSize &localSize = compiler.getComputeShaderLocalSize();
+ sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
+ << ", local_size_z=" << localSize[2] << ") in;\n";
+ }
+}
+
+void EmitMultiviewGLSL(const TCompiler &compiler,
+ const ShCompileOptions &compileOptions,
+ const TBehavior behavior,
+ TInfoSinkBase &sink)
+{
+ ASSERT(behavior != EBhUndefined);
+ if (behavior == EBhDisable)
+ return;
+
+ const bool isVertexShader = (compiler.getShaderType() == GL_VERTEX_SHADER);
+ if (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW)
+ {
+ // Emit ARB_shader_viewport_layer_array/NV_viewport_array2 in a vertex shader if the
+ // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
+ // OVR_multiview(2) extension is requested.
+ if (isVertexShader && (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER))
+ {
+ sink << "#if defined(GL_ARB_shader_viewport_layer_array)\n"
+ << "#extension GL_ARB_shader_viewport_layer_array : require\n"
+ << "#elif defined(GL_NV_viewport_array2)\n"
+ << "#extension GL_NV_viewport_array2 : require\n"
+ << "#endif\n";
+ }
+ }
+ else
+ {
+ sink << "#extension GL_OVR_multiview2 : " << GetBehaviorString(behavior) << "\n";
+
+ const auto &numViews = compiler.getNumViews();
+ if (isVertexShader && numViews != -1)
+ {
+ sink << "layout(num_views=" << numViews << ") in;\n";
+ }
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/Compiler.h b/gfx/angle/checkout/src/compiler/translator/Compiler.h
new file mode 100644
index 0000000000..70c02855f1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Compiler.h
@@ -0,0 +1,304 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_COMPILER_H_
+#define COMPILER_TRANSLATOR_COMPILER_H_
+
+//
+// Machine independent part of the compiler private objects
+// sent as ShHandle to the driver.
+//
+// This should not be included by driver code.
+//
+
+#include <GLSLANG/ShaderVars.h>
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/Pragma.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/ValidateAST.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+namespace sh
+{
+
+class TCompiler;
+class TParseContext;
+#ifdef ANGLE_ENABLE_HLSL
+class TranslatorHLSL;
+#endif // ANGLE_ENABLE_HLSL
+
+//
+// Helper function to check if the shader type is GLSL.
+//
+bool IsGLSL130OrNewer(ShShaderOutput output);
+bool IsGLSL420OrNewer(ShShaderOutput output);
+bool IsGLSL410OrOlder(ShShaderOutput output);
+
+//
+// Helper function to check if the invariant qualifier can be removed.
+//
+bool RemoveInvariant(sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput outputType,
+ ShCompileOptions compileOptions);
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase
+{
+ public:
+ TShHandleBase();
+ virtual ~TShHandleBase();
+ virtual TCompiler *getAsCompiler() { return 0; }
+#ifdef ANGLE_ENABLE_HLSL
+ virtual TranslatorHLSL *getAsTranslatorHLSL() { return 0; }
+#endif // ANGLE_ENABLE_HLSL
+
+ protected:
+ // Memory allocator. Allocates and tracks memory required by the compiler.
+ // Deallocates all memory when compiler is destructed.
+ angle::PoolAllocator allocator;
+};
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase
+{
+ public:
+ TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+ ~TCompiler() override;
+ TCompiler *getAsCompiler() override { return this; }
+
+ bool Init(const ShBuiltInResources &resources);
+
+ // compileTreeForTesting should be used only when tests require access to
+ // the AST. Users of this function need to manually manage the global pool
+ // allocator. Returns nullptr whenever there are compilation errors.
+ TIntermBlock *compileTreeForTesting(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions);
+
+ bool compile(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions);
+
+ // Get results of the last compilation.
+ int getShaderVersion() const { return mShaderVersion; }
+ TInfoSink &getInfoSink() { return mInfoSink; }
+
+ bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
+ const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
+ int getNumViews() const { return mNumViews; }
+
+ // Clears the results from the previous compilation.
+ void clearResults();
+
+ const std::vector<sh::Attribute> &getAttributes() const { return mAttributes; }
+ const std::vector<sh::OutputVariable> &getOutputVariables() const { return mOutputVariables; }
+ const std::vector<sh::Uniform> &getUniforms() const { return mUniforms; }
+ const std::vector<sh::Varying> &getInputVaryings() const { return mInputVaryings; }
+ const std::vector<sh::Varying> &getOutputVaryings() const { return mOutputVaryings; }
+ const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return mInterfaceBlocks; }
+ const std::vector<sh::InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
+ const std::vector<sh::InterfaceBlock> &getShaderStorageBlocks() const
+ {
+ return mShaderStorageBlocks;
+ }
+ const std::vector<sh::InterfaceBlock> &getInBlocks() const { return mInBlocks; }
+
+ ShHashFunction64 getHashFunction() const { return mResources.HashFunction; }
+ NameMap &getNameMap() { return mNameMap; }
+ TSymbolTable &getSymbolTable() { return mSymbolTable; }
+ ShShaderSpec getShaderSpec() const { return mShaderSpec; }
+ ShShaderOutput getOutputType() const { return mOutputType; }
+ const std::string &getBuiltInResourcesString() const { return mBuiltInResourcesString; }
+
+ bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const;
+
+ // Get the resources set by InitBuiltInSymbolTable
+ const ShBuiltInResources &getResources() const;
+
+ int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
+ int getGeometryShaderInvocations() const { return mGeometryShaderInvocations; }
+ TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const
+ {
+ return mGeometryShaderInputPrimitiveType;
+ }
+ TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const
+ {
+ return mGeometryShaderOutputPrimitiveType;
+ }
+
+ sh::GLenum getShaderType() const { return mShaderType; }
+
+ protected:
+ // Add emulated functions to the built-in function emulator.
+ virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions)
+ {}
+ // Translate to object code. May generate performance warnings through the diagnostics.
+ virtual void translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics *perfDiagnostics) = 0;
+ // Get built-in extensions with default behavior.
+ const TExtensionBehavior &getExtensionBehavior() const;
+ const char *getSourcePath() const;
+ const TPragma &getPragma() const { return mPragma; }
+ void writePragma(ShCompileOptions compileOptions);
+ // Relies on collectVariables having been called.
+ bool isVaryingDefined(const char *varyingName);
+
+ const ArrayBoundsClamper &getArrayBoundsClamper() const;
+ ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
+ const BuiltInFunctionEmulator &getBuiltInFunctionEmulator() const;
+
+ virtual bool shouldFlattenPragmaStdglInvariantAll() = 0;
+ virtual bool shouldCollectVariables(ShCompileOptions compileOptions);
+
+ bool wereVariablesCollected() const;
+ std::vector<sh::Attribute> mAttributes;
+ std::vector<sh::OutputVariable> mOutputVariables;
+ std::vector<sh::Uniform> mUniforms;
+ std::vector<sh::Varying> mInputVaryings;
+ std::vector<sh::Varying> mOutputVaryings;
+ std::vector<sh::InterfaceBlock> mInterfaceBlocks;
+ std::vector<sh::InterfaceBlock> mUniformBlocks;
+ std::vector<sh::InterfaceBlock> mShaderStorageBlocks;
+ std::vector<sh::InterfaceBlock> mInBlocks;
+
+ private:
+ // Initialize symbol-table with built-in symbols.
+ bool initBuiltInSymbolTable(const ShBuiltInResources &resources);
+ // Compute the string representation of the built-in resources
+ void setResourceString();
+ // Return false if the call depth is exceeded.
+ bool checkCallDepth();
+ // Insert statements to reference all members in unused uniform blocks with standard and shared
+ // layout. This is to work around a Mac driver that treats unused standard/shared
+ // uniform blocks as inactive.
+ void useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root);
+ // Insert statements to initialize output variables in the beginning of main().
+ // This is to avoid undefined behaviors.
+ void initializeOutputVariables(TIntermBlock *root);
+ // Insert gl_Position = vec4(0,0,0,0) to the beginning of main().
+ // It is to work around a Linux driver bug where missing this causes compile failure
+ // while spec says it is allowed.
+ // This function should only be applied to vertex shaders.
+ void initializeGLPosition(TIntermBlock *root);
+ // Return true if the maximum expression complexity is below the limit.
+ bool limitExpressionComplexity(TIntermBlock *root);
+ // Creates the function call DAG for further analysis, returning false if there is a recursion
+ bool initCallDag(TIntermNode *root);
+ // Return false if "main" doesn't exist
+ bool tagUsedFunctions();
+ void internalTagUsedFunction(size_t index);
+
+ void collectInterfaceBlocks();
+
+ bool mVariablesCollected;
+
+ bool mGLPositionInitialized;
+
+ // Removes unused function declarations and prototypes from the AST
+ class UnusedPredicate;
+ void pruneUnusedFunctions(TIntermBlock *root);
+
+ TIntermBlock *compileTreeImpl(const char *const shaderStrings[],
+ size_t numStrings,
+ 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);
+
+ // Check if shader version meets the requirement.
+ bool checkShaderVersion(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 mShaderType;
+ ShShaderSpec mShaderSpec;
+ ShShaderOutput mOutputType;
+
+ struct FunctionMetadata
+ {
+ FunctionMetadata() : used(false) {}
+ bool used;
+ };
+
+ CallDAG mCallDag;
+ std::vector<FunctionMetadata> mFunctionMetadata;
+
+ ShBuiltInResources mResources;
+ std::string mBuiltInResourcesString;
+
+ // Built-in symbol table for the given language, spec, and resources.
+ // It is preserved from compile-to-compile.
+ TSymbolTable mSymbolTable;
+ // Built-in extensions with default behavior.
+ TExtensionBehavior mExtensionBehavior;
+
+ ArrayBoundsClamper mArrayBoundsClamper;
+ BuiltInFunctionEmulator mBuiltInFunctionEmulator;
+
+ // Results of compilation.
+ int mShaderVersion;
+ TInfoSink mInfoSink; // Output sink.
+ TDiagnostics mDiagnostics;
+ const char *mSourcePath; // Path of source file or NULL
+
+ // compute shader local group size
+ bool mComputeShaderLocalSizeDeclared;
+ sh::WorkGroupSize mComputeShaderLocalSize;
+
+ // GL_OVR_multiview num_views.
+ int mNumViews;
+
+ // geometry shader parameters.
+ int mGeometryShaderMaxVertices;
+ int mGeometryShaderInvocations;
+ TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
+ TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
+
+ // name hashing.
+ NameMap mNameMap;
+
+ TPragma mPragma;
+
+ // Track what should be validated given passes currently applied.
+ ValidateASTOptions mValidateASTOptions;
+};
+
+//
+// This is the interface between the machine independent code
+// and the machine dependent code.
+//
+// The machine dependent code should derive from the classes
+// above. Then Construct*() and Delete*() will create and
+// destroy the machine dependent objects, which contain the
+// above machine independent information.
+//
+TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+void DeleteCompiler(TCompiler *);
+
+void EmitWorkGroupSizeGLSL(const TCompiler &, TInfoSinkBase &sink);
+void EmitMultiviewGLSL(const TCompiler &, const ShCompileOptions &, TBehavior, TInfoSinkBase &sink);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_COMPILER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp
new file mode 100644
index 0000000000..fe22a2d9b9
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp
@@ -0,0 +1,772 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ConstantUnion: Constant folding helper class.
+
+#include "compiler/translator/ConstantUnion.h"
+
+#include "common/mathutil.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
+{
+ float result = lhs + rhs;
+ if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
+ {
+ diag->warning(line, "Constant folded undefined addition generated NaN", "+");
+ }
+ else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
+ {
+ diag->warning(line, "Constant folded addition overflowed to infinity", "+");
+ }
+ return result;
+}
+
+float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
+{
+ float result = lhs - rhs;
+ if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
+ {
+ diag->warning(line, "Constant folded undefined subtraction generated NaN", "-");
+ }
+ else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
+ {
+ diag->warning(line, "Constant folded subtraction overflowed to infinity", "-");
+ }
+ return result;
+}
+
+float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
+{
+ float result = lhs * rhs;
+ if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
+ {
+ diag->warning(line, "Constant folded undefined multiplication generated NaN", "*");
+ }
+ else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
+ {
+ diag->warning(line, "Constant folded multiplication overflowed to infinity", "*");
+ }
+ return result;
+}
+
+bool IsValidShiftOffset(const TConstantUnion &rhs)
+{
+ return (rhs.getType() == EbtInt && (rhs.getIConst() >= 0 && rhs.getIConst() <= 31)) ||
+ (rhs.getType() == EbtUInt && rhs.getUConst() <= 31u);
+}
+
+} // anonymous namespace
+
+TConstantUnion::TConstantUnion()
+{
+ iConst = 0;
+ type = EbtVoid;
+}
+
+int TConstantUnion::getIConst() const
+{
+ ASSERT(type == EbtInt);
+ return iConst;
+}
+
+unsigned int TConstantUnion::getUConst() const
+{
+ ASSERT(type == EbtUInt);
+ return uConst;
+}
+
+float TConstantUnion::getFConst() const
+{
+ switch (type)
+ {
+ case EbtInt:
+ return static_cast<float>(iConst);
+ case EbtUInt:
+ return static_cast<float>(uConst);
+ default:
+ ASSERT(type == EbtFloat);
+ return fConst;
+ }
+}
+
+bool TConstantUnion::getBConst() const
+{
+ ASSERT(type == EbtBool);
+ return bConst;
+}
+
+TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const
+{
+ ASSERT(type == EbtYuvCscStandardEXT);
+ return yuvCscStandardEXTConst;
+}
+
+bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
+{
+ switch (newType)
+ {
+ case EbtFloat:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setFConst(static_cast<float>(constant.getIConst()));
+ break;
+ case EbtUInt:
+ setFConst(static_cast<float>(constant.getUConst()));
+ break;
+ case EbtBool:
+ setFConst(static_cast<float>(constant.getBConst()));
+ break;
+ case EbtFloat:
+ setFConst(static_cast<float>(constant.getFConst()));
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtInt:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setIConst(static_cast<int>(constant.getIConst()));
+ break;
+ case EbtUInt:
+ setIConst(static_cast<int>(constant.getUConst()));
+ break;
+ case EbtBool:
+ setIConst(static_cast<int>(constant.getBConst()));
+ break;
+ case EbtFloat:
+ setIConst(static_cast<int>(constant.getFConst()));
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtUInt:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setUConst(static_cast<unsigned int>(constant.getIConst()));
+ break;
+ case EbtUInt:
+ setUConst(static_cast<unsigned int>(constant.getUConst()));
+ break;
+ case EbtBool:
+ setUConst(static_cast<unsigned int>(constant.getBConst()));
+ break;
+ case EbtFloat:
+ if (constant.getFConst() < 0.0f)
+ {
+ // Avoid undefined behavior in C++ by first casting to signed int.
+ setUConst(
+ static_cast<unsigned int>(static_cast<int>(constant.getFConst())));
+ }
+ else
+ {
+ setUConst(static_cast<unsigned int>(constant.getFConst()));
+ }
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtBool:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setBConst(constant.getIConst() != 0);
+ break;
+ case EbtUInt:
+ setBConst(constant.getUConst() != 0);
+ break;
+ case EbtBool:
+ setBConst(constant.getBConst());
+ break;
+ case EbtFloat:
+ setBConst(constant.getFConst() != 0.0f);
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtStruct: // Struct fields don't get cast
+ switch (constant.type)
+ {
+ case EbtInt:
+ setIConst(constant.getIConst());
+ break;
+ case EbtUInt:
+ setUConst(constant.getUConst());
+ break;
+ case EbtBool:
+ setBConst(constant.getBConst());
+ break;
+ case EbtFloat:
+ setFConst(constant.getFConst());
+ break;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool TConstantUnion::operator==(const int i) const
+{
+ switch (type)
+ {
+ case EbtFloat:
+ return static_cast<float>(i) == fConst;
+ default:
+ return i == iConst;
+ }
+}
+
+bool TConstantUnion::operator==(const unsigned int u) const
+{
+ switch (type)
+ {
+ case EbtFloat:
+ return static_cast<float>(u) == fConst;
+ default:
+ return u == uConst;
+ }
+}
+
+bool TConstantUnion::operator==(const float f) const
+{
+ switch (type)
+ {
+ case EbtInt:
+ return f == static_cast<float>(iConst);
+ case EbtUInt:
+ return f == static_cast<float>(uConst);
+ default:
+ return f == fConst;
+ }
+}
+
+bool TConstantUnion::operator==(const bool b) const
+{
+ return b == bConst;
+}
+
+bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const
+{
+ return s == yuvCscStandardEXTConst;
+}
+
+bool TConstantUnion::operator==(const TConstantUnion &constant) const
+{
+ ImplicitTypeConversion conversion = GetConversion(constant.type, type);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ switch (type)
+ {
+ case EbtInt:
+ return constant.iConst == iConst;
+ case EbtUInt:
+ return constant.uConst == uConst;
+ case EbtFloat:
+ return constant.fConst == fConst;
+ case EbtBool:
+ return constant.bConst == bConst;
+ case EbtYuvCscStandardEXT:
+ return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst;
+ default:
+ return false;
+ }
+ }
+ else if (conversion == ImplicitTypeConversion::Invalid)
+ {
+ return false;
+ }
+ else
+ {
+ return constant.getFConst() == getFConst();
+ }
+}
+
+bool TConstantUnion::operator!=(const int i) const
+{
+ return !operator==(i);
+}
+
+bool TConstantUnion::operator!=(const unsigned int u) const
+{
+ return !operator==(u);
+}
+
+bool TConstantUnion::operator!=(const float f) const
+{
+ return !operator==(f);
+}
+
+bool TConstantUnion::operator!=(const bool b) const
+{
+ return !operator==(b);
+}
+
+bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const
+{
+ return !operator==(s);
+}
+
+bool TConstantUnion::operator!=(const TConstantUnion &constant) const
+{
+ return !operator==(constant);
+}
+
+bool TConstantUnion::operator>(const TConstantUnion &constant) const
+{
+
+ ImplicitTypeConversion conversion = GetConversion(constant.type, type);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ switch (type)
+ {
+ case EbtInt:
+ return iConst > constant.iConst;
+ case EbtUInt:
+ return uConst > constant.uConst;
+ case EbtFloat:
+ return fConst > constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+ else
+ {
+ ASSERT(conversion != ImplicitTypeConversion::Invalid);
+ return getFConst() > constant.getFConst();
+ }
+}
+
+bool TConstantUnion::operator<(const TConstantUnion &constant) const
+{
+ ImplicitTypeConversion conversion = GetConversion(constant.type, type);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ switch (type)
+ {
+ case EbtInt:
+ return iConst < constant.iConst;
+ case EbtUInt:
+ return uConst < constant.uConst;
+ case EbtFloat:
+ return fConst < constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+ else
+ {
+ ASSERT(conversion != ImplicitTypeConversion::Invalid);
+ return getFConst() < constant.getFConst();
+ }
+}
+
+// static
+TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+
+ ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
+ break;
+ case EbtUInt:
+ returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
+ break;
+ case EbtFloat:
+ returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ ASSERT(conversion != ImplicitTypeConversion::Invalid);
+ returnValue.setFConst(CheckedSum(lhs.getFConst(), rhs.getFConst(), diag, line));
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+
+ ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
+ break;
+ case EbtUInt:
+ returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
+ break;
+ case EbtFloat:
+ returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ ASSERT(conversion != ImplicitTypeConversion::Invalid);
+ returnValue.setFConst(CheckedDiff(lhs.getFConst(), rhs.getFConst(), diag, line));
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+
+ ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
+ break;
+ case EbtUInt:
+ // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely
+ // on that to implement wrapping multiplication.
+ returnValue.setUConst(lhs.uConst * rhs.uConst);
+ break;
+ case EbtFloat:
+ returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ ASSERT(conversion != ImplicitTypeConversion::Invalid);
+ returnValue.setFConst(CheckedMul(lhs.getFConst(), rhs.getFConst(), diag, line));
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst % constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst % constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
+ ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
+ if (!IsValidShiftOffset(rhs))
+ {
+ diag->warning(line, "Undefined shift (operand out of range)", ">>");
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(0);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(0u);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return returnValue;
+ }
+
+ switch (lhs.type)
+ {
+ case EbtInt:
+ {
+ unsigned int shiftOffset = 0;
+ switch (rhs.type)
+ {
+ case EbtInt:
+ shiftOffset = static_cast<unsigned int>(rhs.iConst);
+ break;
+ case EbtUInt:
+ shiftOffset = rhs.uConst;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ if (shiftOffset > 0)
+ {
+ // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
+ // the sign bit." In C++ shifting negative integers is undefined, so we implement
+ // extending the sign bit manually.
+ int lhsSafe = lhs.iConst;
+ if (lhsSafe == std::numeric_limits<int>::min())
+ {
+ // The min integer needs special treatment because only bit it has set is the
+ // sign bit, which we clear later to implement safe right shift of negative
+ // numbers.
+ lhsSafe = -0x40000000;
+ --shiftOffset;
+ }
+ if (shiftOffset > 0)
+ {
+ bool extendSignBit = false;
+ if (lhsSafe < 0)
+ {
+ extendSignBit = true;
+ // Clear the sign bit so that bitshift right is defined in C++.
+ lhsSafe &= 0x7fffffff;
+ ASSERT(lhsSafe > 0);
+ }
+ returnValue.setIConst(lhsSafe >> shiftOffset);
+
+ // Manually fill in the extended sign bit if necessary.
+ if (extendSignBit)
+ {
+ int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
+ returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
+ }
+ }
+ else
+ {
+ returnValue.setIConst(lhsSafe);
+ }
+ }
+ else
+ {
+ returnValue.setIConst(lhs.iConst);
+ }
+ break;
+ }
+ case EbtUInt:
+ switch (rhs.type)
+ {
+ case EbtInt:
+ returnValue.setUConst(lhs.uConst >> rhs.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(lhs.uConst >> rhs.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
+ ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
+ if (!IsValidShiftOffset(rhs))
+ {
+ diag->warning(line, "Undefined shift (operand out of range)", "<<");
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(0);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(0u);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return returnValue;
+ }
+
+ switch (lhs.type)
+ {
+ case EbtInt:
+ switch (rhs.type)
+ {
+ // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
+ // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
+ // integer overflow or undefined shift of a negative integer.
+ case EbtInt:
+ returnValue.setIConst(
+ static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
+ break;
+ case EbtUInt:
+ returnValue.setIConst(
+ static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+
+ case EbtUInt:
+ switch (rhs.type)
+ {
+ case EbtInt:
+ returnValue.setUConst(lhs.uConst << rhs.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(lhs.uConst << rhs.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst & constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst & constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst | constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst | constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst ^ constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst ^ constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtBool:
+ returnValue.setBConst(bConst && constant.bConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtBool:
+ returnValue.setBConst(bConst || constant.bConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ConstantUnion.h b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.h
new file mode 100644
index 0000000000..155fcd44b0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.h
@@ -0,0 +1,119 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_CONSTANTUNION_H_
+#define COMPILER_TRANSLATOR_CONSTANTUNION_H_
+
+#include <assert.h>
+
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+
+class TDiagnostics;
+
+class TConstantUnion
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TConstantUnion();
+
+ bool cast(TBasicType newType, const TConstantUnion &constant);
+
+ void setIConst(int i)
+ {
+ iConst = i;
+ type = EbtInt;
+ }
+ void setUConst(unsigned int u)
+ {
+ uConst = u;
+ type = EbtUInt;
+ }
+ void setFConst(float f)
+ {
+ fConst = f;
+ type = EbtFloat;
+ }
+ void setBConst(bool b)
+ {
+ bConst = b;
+ type = EbtBool;
+ }
+
+ void setYuvCscStandardEXTConst(TYuvCscStandardEXT s)
+ {
+ yuvCscStandardEXTConst = s;
+ type = EbtYuvCscStandardEXT;
+ }
+
+ int getIConst() const;
+ unsigned int getUConst() const;
+ float getFConst() const;
+ bool getBConst() const;
+ TYuvCscStandardEXT getYuvCscStandardEXTConst() const;
+
+ bool operator==(const int i) const;
+ bool operator==(const unsigned int u) const;
+ bool operator==(const float f) const;
+ bool operator==(const bool b) const;
+ bool operator==(const TYuvCscStandardEXT s) const;
+ bool operator==(const TConstantUnion &constant) const;
+ bool operator!=(const int i) const;
+ bool operator!=(const unsigned int u) const;
+ bool operator!=(const float f) const;
+ bool operator!=(const bool b) const;
+ bool operator!=(const TYuvCscStandardEXT s) const;
+ bool operator!=(const TConstantUnion &constant) const;
+ bool operator>(const TConstantUnion &constant) const;
+ bool operator<(const TConstantUnion &constant) const;
+ static TConstantUnion add(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line);
+ static TConstantUnion sub(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line);
+ static TConstantUnion mul(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line);
+ TConstantUnion operator%(const TConstantUnion &constant) const;
+ static TConstantUnion rshift(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line);
+ static TConstantUnion lshift(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag,
+ const TSourceLoc &line);
+ TConstantUnion operator&(const TConstantUnion &constant) const;
+ TConstantUnion operator|(const TConstantUnion &constant) const;
+ TConstantUnion operator^(const TConstantUnion &constant) const;
+ TConstantUnion operator&&(const TConstantUnion &constant) const;
+ TConstantUnion operator||(const TConstantUnion &constant) const;
+
+ TBasicType getType() const { return type; }
+
+ private:
+ union
+ {
+ int iConst; // used for ivec, scalar ints
+ unsigned int uConst; // used for uvec, scalar uints
+ bool bConst; // used for bvec, scalar bools
+ float fConst; // used for vec, mat, scalar floats
+ TYuvCscStandardEXT yuvCscStandardEXTConst;
+ };
+
+ TBasicType type;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Declarator.cpp b/gfx/angle/checkout/src/compiler/translator/Declarator.cpp
new file mode 100644
index 0000000000..7a17a82b6a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Declarator.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declarator.cpp:
+// Declarator type for parsing structure field declarators.
+
+#include "compiler/translator/Declarator.h"
+
+namespace sh
+{
+
+TDeclarator::TDeclarator(const ImmutableString &name, const TSourceLoc &line)
+ : mName(name), mArraySizes(nullptr), mLine(line)
+{
+ ASSERT(mName != "");
+}
+
+TDeclarator::TDeclarator(const ImmutableString &name,
+ const TVector<unsigned int> *arraySizes,
+ const TSourceLoc &line)
+ : mName(name), mArraySizes(arraySizes), mLine(line)
+{
+ ASSERT(mArraySizes);
+}
+
+bool TDeclarator::isArray() const
+{
+ return mArraySizes != nullptr && mArraySizes->size() > 0;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/Declarator.h b/gfx/angle/checkout/src/compiler/translator/Declarator.h
new file mode 100644
index 0000000000..5b5d26b53a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Declarator.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declarator.h:
+// Declarator type for parsing structure field declarators.
+
+#ifndef COMPILER_TRANSLATOR_DECLARATOR_H_
+#define COMPILER_TRANSLATOR_DECLARATOR_H_
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/ImmutableString.h"
+
+namespace sh
+{
+
+// Declarator like "a[2][4]". Only used for parsing structure field declarators.
+class TDeclarator : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TDeclarator(const ImmutableString &name, const TSourceLoc &line);
+
+ TDeclarator(const ImmutableString &name,
+ const TVector<unsigned int> *arraySizes,
+ const TSourceLoc &line);
+
+ const ImmutableString &name() const { return mName; }
+
+ bool isArray() const;
+ const TVector<unsigned int> *arraySizes() const { return mArraySizes; }
+
+ const TSourceLoc &line() const { return mLine; }
+
+ private:
+ const ImmutableString mName;
+
+ // Outermost array size is stored at the end of the vector.
+ const TVector<unsigned int> *const mArraySizes;
+
+ const TSourceLoc mLine;
+};
+
+using TDeclaratorList = TVector<TDeclarator *>;
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_DECLARATOR_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp b/gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp
new file mode 100644
index 0000000000..5ec4867cbb
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/Diagnostics.h"
+
+#include "common/debug.h"
+#include "compiler/preprocessor/SourceLocation.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/InfoSink.h"
+
+namespace sh
+{
+
+TDiagnostics::TDiagnostics(TInfoSinkBase &infoSink)
+ : mInfoSink(infoSink), mNumErrors(0), mNumWarnings(0)
+{}
+
+TDiagnostics::~TDiagnostics() {}
+
+void TDiagnostics::writeInfo(Severity severity,
+ const angle::pp::SourceLocation &loc,
+ const char *reason,
+ const char *token)
+{
+ switch (severity)
+ {
+ case SH_ERROR:
+ ++mNumErrors;
+ break;
+ case SH_WARNING:
+ ++mNumWarnings;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ /* VC++ format: file(linenum) : error #: 'token' : extrainfo */
+ mInfoSink.prefix(severity);
+ mInfoSink.location(loc.file, loc.line);
+ mInfoSink << "'" << token << "' : " << reason << "\n";
+}
+
+void TDiagnostics::globalError(const char *message)
+{
+ ++mNumErrors;
+ mInfoSink.prefix(SH_ERROR);
+ mInfoSink << message << "\n";
+}
+
+void TDiagnostics::error(const angle::pp::SourceLocation &loc,
+ const char *reason,
+ const char *token)
+{
+ writeInfo(SH_ERROR, loc, reason, token);
+}
+
+void TDiagnostics::warning(const angle::pp::SourceLocation &loc,
+ const char *reason,
+ const char *token)
+{
+ writeInfo(SH_WARNING, loc, reason, token);
+}
+
+void TDiagnostics::error(const TSourceLoc &loc, const char *reason, const char *token)
+{
+ angle::pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ error(srcLoc, reason, token);
+}
+
+void TDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token)
+{
+ angle::pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ warning(srcLoc, reason, token);
+}
+
+void TDiagnostics::print(ID id, const angle::pp::SourceLocation &loc, const std::string &text)
+{
+ writeInfo(isError(id) ? SH_ERROR : SH_WARNING, loc, message(id), text.c_str());
+}
+
+void TDiagnostics::resetErrorCount()
+{
+ mNumErrors = 0;
+ mNumWarnings = 0;
+}
+
+PerformanceDiagnostics::PerformanceDiagnostics(TDiagnostics *diagnostics)
+ : mDiagnostics(diagnostics)
+{
+ ASSERT(diagnostics);
+}
+
+void PerformanceDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token)
+{
+ mDiagnostics->warning(loc, reason, token);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/Diagnostics.h b/gfx/angle/checkout/src/compiler/translator/Diagnostics.h
new file mode 100644
index 0000000000..121b6f3c2a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Diagnostics.h
@@ -0,0 +1,67 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_DIAGNOSTICS_H_
+#define COMPILER_TRANSLATOR_DIAGNOSTICS_H_
+
+#include "common/angleutils.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
+#include "compiler/translator/Severity.h"
+
+namespace sh
+{
+
+class TInfoSinkBase;
+struct TSourceLoc;
+
+class TDiagnostics : public angle::pp::Diagnostics, angle::NonCopyable
+{
+ public:
+ TDiagnostics(TInfoSinkBase &infoSink);
+ ~TDiagnostics() override;
+
+ int numErrors() const { return mNumErrors; }
+ int numWarnings() const { return mNumWarnings; }
+
+ void error(const angle::pp::SourceLocation &loc, const char *reason, const char *token);
+ void warning(const angle::pp::SourceLocation &loc, const char *reason, const char *token);
+
+ void error(const TSourceLoc &loc, const char *reason, const char *token);
+ void warning(const TSourceLoc &loc, const char *reason, const char *token);
+
+ void globalError(const char *message);
+
+ void resetErrorCount();
+
+ protected:
+ void writeInfo(Severity severity,
+ const angle::pp::SourceLocation &loc,
+ const char *reason,
+ const char *token);
+
+ void print(ID id, const angle::pp::SourceLocation &loc, const std::string &text) override;
+
+ private:
+ TInfoSinkBase &mInfoSink;
+ int mNumErrors;
+ int mNumWarnings;
+};
+
+// Diagnostics wrapper to use when the code is only allowed to generate warnings.
+class PerformanceDiagnostics : public angle::NonCopyable
+{
+ public:
+ PerformanceDiagnostics(TDiagnostics *diagnostics);
+
+ void warning(const TSourceLoc &loc, const char *reason, const char *token);
+
+ private:
+ TDiagnostics *mDiagnostics;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp
new file mode 100644
index 0000000000..8e4dae42d2
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp
@@ -0,0 +1,204 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/DirectiveHandler.h"
+
+#include <sstream>
+
+#include "angle_gl.h"
+#include "common/debug.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/Diagnostics.h"
+
+namespace sh
+{
+
+static TBehavior getBehavior(const std::string &str)
+{
+ const char kRequire[] = "require";
+ const char kEnable[] = "enable";
+ const char kDisable[] = "disable";
+ const char kWarn[] = "warn";
+
+ if (str == kRequire)
+ return EBhRequire;
+ else if (str == kEnable)
+ return EBhEnable;
+ else if (str == kDisable)
+ return EBhDisable;
+ else if (str == kWarn)
+ return EBhWarn;
+ return EBhUndefined;
+}
+
+TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
+ TDiagnostics &diagnostics,
+ int &shaderVersion,
+ sh::GLenum shaderType,
+ bool debugShaderPrecisionSupported)
+ : mExtensionBehavior(extBehavior),
+ mDiagnostics(diagnostics),
+ mShaderVersion(shaderVersion),
+ mShaderType(shaderType),
+ mDebugShaderPrecisionSupported(debugShaderPrecisionSupported)
+{}
+
+TDirectiveHandler::~TDirectiveHandler() {}
+
+void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg)
+{
+ mDiagnostics.error(loc, msg.c_str(), "");
+}
+
+void TDirectiveHandler::handlePragma(const angle::pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &value,
+ bool stdgl)
+{
+ if (stdgl)
+ {
+ const char kInvariant[] = "invariant";
+ const char kAll[] = "all";
+
+ if (name == kInvariant && value == kAll)
+ {
+ if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ // ESSL 3.00.4 section 4.6.1
+ mDiagnostics.error(
+ loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
+ name.c_str());
+ }
+ mPragma.stdgl.invariantAll = true;
+ }
+ // The STDGL pragma is used to reserve pragmas for use by future
+ // revisions of GLSL. Do not generate an error on unexpected
+ // name and value.
+ return;
+ }
+ else
+ {
+ const char kOptimize[] = "optimize";
+ const char kDebug[] = "debug";
+ const char kDebugShaderPrecision[] = "webgl_debug_shader_precision";
+ const char kOn[] = "on";
+ const char kOff[] = "off";
+
+ bool invalidValue = false;
+ if (name == kOptimize)
+ {
+ if (value == kOn)
+ mPragma.optimize = true;
+ else if (value == kOff)
+ mPragma.optimize = false;
+ else
+ invalidValue = true;
+ }
+ else if (name == kDebug)
+ {
+ if (value == kOn)
+ mPragma.debug = true;
+ else if (value == kOff)
+ mPragma.debug = false;
+ else
+ invalidValue = true;
+ }
+ else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported)
+ {
+ if (value == kOn)
+ mPragma.debugShaderPrecision = true;
+ else if (value == kOff)
+ mPragma.debugShaderPrecision = false;
+ else
+ invalidValue = true;
+ }
+ else
+ {
+ mDiagnostics.report(angle::pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
+ return;
+ }
+
+ if (invalidValue)
+ {
+ mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
+ }
+ }
+}
+
+void TDirectiveHandler::handleExtension(const angle::pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &behavior)
+{
+ const char kExtAll[] = "all";
+
+ TBehavior behaviorVal = getBehavior(behavior);
+ if (behaviorVal == EBhUndefined)
+ {
+ mDiagnostics.error(loc, "behavior invalid", name.c_str());
+ return;
+ }
+
+ if (name == kExtAll)
+ {
+ if (behaviorVal == EBhRequire)
+ {
+ mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
+ }
+ else if (behaviorVal == EBhEnable)
+ {
+ mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
+ }
+ else
+ {
+ for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
+ iter != mExtensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ return;
+ }
+
+ TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
+ if (iter != mExtensionBehavior.end())
+ {
+ iter->second = behaviorVal;
+ return;
+ }
+
+ switch (behaviorVal)
+ {
+ case EBhRequire:
+ mDiagnostics.error(loc, "extension is not supported", name.c_str());
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ mDiagnostics.warning(loc, "extension is not supported", name.c_str());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc,
+ int version,
+ ShShaderSpec spec)
+{
+ if (((version == 100 || version == 300 || version == 310) && !IsDesktopGLSpec(spec)) ||
+ (version == 330 && IsDesktopGLSpec(spec)))
+ {
+ mShaderVersion = version;
+ }
+ else
+ {
+ std::stringstream stream = sh::InitializeStream<std::stringstream>();
+ stream << version;
+ std::string str = stream.str();
+ mDiagnostics.error(loc, "client/version number not supported", str.c_str());
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h
new file mode 100644
index 0000000000..2d3b0ce044
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_
+#define COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "common/angleutils.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/Pragma.h"
+
+namespace sh
+{
+class TDiagnostics;
+
+class TDirectiveHandler : public angle::pp::DirectiveHandler, angle::NonCopyable
+{
+ public:
+ TDirectiveHandler(TExtensionBehavior &extBehavior,
+ TDiagnostics &diagnostics,
+ int &shaderVersion,
+ sh::GLenum shaderType,
+ bool debugShaderPrecisionSupported);
+ ~TDirectiveHandler() override;
+
+ const TPragma &pragma() const { return mPragma; }
+ const TExtensionBehavior &extensionBehavior() const { return mExtensionBehavior; }
+
+ void handleError(const angle::pp::SourceLocation &loc, const std::string &msg) override;
+
+ void handlePragma(const angle::pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &value,
+ bool stdgl) override;
+
+ void handleExtension(const angle::pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &behavior) override;
+
+ void handleVersion(const angle::pp::SourceLocation &loc,
+ int version,
+ ShShaderSpec spec) override;
+
+ private:
+ TPragma mPragma;
+ TExtensionBehavior &mExtensionBehavior;
+ TDiagnostics &mDiagnostics;
+ int &mShaderVersion;
+ sh::GLenum mShaderType;
+ bool mDebugShaderPrecisionSupported;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp
new file mode 100644
index 0000000000..5a5c92b8bd
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp
@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ExtensionBehavior.cpp: Extension name enumeration and data structures for storing extension
+// behavior.
+
+#include "compiler/translator/ExtensionBehavior.h"
+
+#include "common/debug.h"
+
+#include <string.h>
+
+#define LIST_EXTENSIONS(OP) \
+ OP(ARB_texture_rectangle) \
+ OP(ANGLE_texture_multisample) \
+ OP(ARM_shader_framebuffer_fetch) \
+ OP(EXT_blend_func_extended) \
+ OP(EXT_draw_buffers) \
+ OP(EXT_frag_depth) \
+ OP(EXT_geometry_shader) \
+ OP(EXT_shader_framebuffer_fetch) \
+ OP(EXT_shader_texture_lod) \
+ OP(EXT_YUV_target) \
+ OP(NV_EGL_stream_consumer_external) \
+ OP(NV_shader_framebuffer_fetch) \
+ OP(OES_EGL_image_external) \
+ OP(OES_EGL_image_external_essl3) \
+ OP(OES_standard_derivatives) \
+ OP(OES_texture_storage_multisample_2d_array) \
+ OP(OES_texture_3D) \
+ OP(OVR_multiview) \
+ OP(OVR_multiview2) \
+ OP(ANGLE_multi_draw) \
+ OP(ANGLE_base_vertex_base_instance)
+
+namespace sh
+{
+
+#define RETURN_EXTENSION_NAME_CASE(ext) \
+ case TExtension::ext: \
+ return "GL_" #ext;
+
+const char *GetExtensionNameString(TExtension extension)
+{
+ switch (extension)
+ {
+ LIST_EXTENSIONS(RETURN_EXTENSION_NAME_CASE)
+ default:
+ UNREACHABLE();
+ return "";
+ }
+}
+
+#define RETURN_EXTENSION_IF_NAME_MATCHES(ext) \
+ if (strcmp(extWithoutGLPrefix, #ext) == 0) \
+ { \
+ return TExtension::ext; \
+ }
+
+TExtension GetExtensionByName(const char *extension)
+{
+ // If first characters of the extension don't equal "GL_", early out.
+ if (strncmp(extension, "GL_", 3) != 0)
+ {
+ return TExtension::UNDEFINED;
+ }
+ const char *extWithoutGLPrefix = extension + 3;
+
+ LIST_EXTENSIONS(RETURN_EXTENSION_IF_NAME_MATCHES)
+
+ return TExtension::UNDEFINED;
+}
+
+const char *GetBehaviorString(TBehavior b)
+{
+ switch (b)
+ {
+ case EBhRequire:
+ return "require";
+ case EBhEnable:
+ return "enable";
+ case EBhWarn:
+ return "warn";
+ case EBhDisable:
+ return "disable";
+ default:
+ return nullptr;
+ }
+}
+
+bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, TExtension extension)
+{
+ ASSERT(extension != TExtension::UNDEFINED);
+ auto iter = extBehavior.find(extension);
+ return iter != extBehavior.end() &&
+ (iter->second == EBhEnable || iter->second == EBhRequire || iter->second == EBhWarn);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h
new file mode 100644
index 0000000000..2d27ab9922
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ExtensionBehavior.h: Extension name enumeration and data structures for storing extension
+// behavior.
+
+#ifndef COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
+#define COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
+
+#include <map>
+
+namespace sh
+{
+
+enum class TExtension
+{
+ UNDEFINED, // Special value used to indicate no extension.
+
+ ARB_texture_rectangle,
+ ANGLE_texture_multisample,
+ ARM_shader_framebuffer_fetch,
+ EXT_blend_func_extended,
+ EXT_draw_buffers,
+ EXT_frag_depth,
+ EXT_geometry_shader,
+ EXT_shader_framebuffer_fetch,
+ EXT_shader_texture_lod,
+ EXT_YUV_target,
+ NV_EGL_stream_consumer_external,
+ NV_shader_framebuffer_fetch,
+ OES_EGL_image_external,
+ OES_EGL_image_external_essl3,
+ OES_standard_derivatives,
+ OES_texture_storage_multisample_2d_array,
+ OES_texture_3D,
+ OVR_multiview,
+ OVR_multiview2,
+ ANGLE_multi_draw,
+ ANGLE_base_vertex_base_instance
+};
+
+enum TBehavior
+{
+ EBhRequire,
+ EBhEnable,
+ EBhWarn,
+ EBhDisable,
+ EBhUndefined
+};
+
+const char *GetExtensionNameString(TExtension extension);
+TExtension GetExtensionByName(const char *extension);
+
+const char *GetBehaviorString(TBehavior b);
+
+// Mapping between extension id and behavior.
+typedef std::map<TExtension, TBehavior> TExtensionBehavior;
+
+bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, TExtension extension);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp
new file mode 100644
index 0000000000..8a7aca95f2
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp
@@ -0,0 +1,104 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ExtensionGLSL.cpp: Implements the TExtensionGLSL class that tracks GLSL extension requirements
+// of shaders.
+
+#include "compiler/translator/ExtensionGLSL.h"
+
+#include "compiler/translator/VersionGLSL.h"
+
+namespace sh
+{
+
+TExtensionGLSL::TExtensionGLSL(ShShaderOutput output)
+ : TIntermTraverser(true, false, false), mTargetVersion(ShaderOutputTypeToGLSLVersion(output))
+{}
+
+const std::set<std::string> &TExtensionGLSL::getEnabledExtensions() const
+{
+ return mEnabledExtensions;
+}
+
+const std::set<std::string> &TExtensionGLSL::getRequiredExtensions() const
+{
+ return mRequiredExtensions;
+}
+
+bool TExtensionGLSL::visitUnary(Visit, TIntermUnary *node)
+{
+ checkOperator(node);
+
+ return true;
+}
+
+bool TExtensionGLSL::visitAggregate(Visit, TIntermAggregate *node)
+{
+ checkOperator(node);
+
+ return true;
+}
+
+void TExtensionGLSL::checkOperator(TIntermOperator *node)
+{
+ if (mTargetVersion < GLSL_VERSION_130)
+ {
+ return;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpAbs:
+ break;
+
+ case EOpSign:
+ break;
+
+ case EOpMix:
+ break;
+
+ case EOpFloatBitsToInt:
+ case EOpFloatBitsToUint:
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ if (mTargetVersion < GLSL_VERSION_330)
+ {
+ // Bit conversion functions cannot be emulated.
+ mRequiredExtensions.insert("GL_ARB_shader_bit_encoding");
+ }
+ break;
+
+ case EOpPackSnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackHalf2x16:
+ if (mTargetVersion < GLSL_VERSION_420)
+ {
+ mEnabledExtensions.insert("GL_ARB_shading_language_packing");
+
+ if (mTargetVersion < GLSL_VERSION_330)
+ {
+ // floatBitsToUint and uintBitsToFloat are needed to emulate
+ // packHalf2x16 and unpackHalf2x16 respectively and cannot be
+ // emulated themselves.
+ mRequiredExtensions.insert("GL_ARB_shader_bit_encoding");
+ }
+ }
+ break;
+
+ case EOpPackUnorm2x16:
+ case EOpUnpackUnorm2x16:
+ if (mTargetVersion < GLSL_VERSION_410)
+ {
+ mEnabledExtensions.insert("GL_ARB_shading_language_packing");
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h
new file mode 100644
index 0000000000..9d752c4eaf
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ExtensionGLSL.h: Defines the TExtensionGLSL class that tracks GLSL extension requirements of
+// shaders.
+
+#ifndef COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
+#define COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
+
+#include <set>
+#include <string>
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+// Traverses the intermediate tree to determine which GLSL extensions are required
+// to support the shader.
+class TExtensionGLSL : public TIntermTraverser
+{
+ public:
+ TExtensionGLSL(ShShaderOutput output);
+
+ const std::set<std::string> &getEnabledExtensions() const;
+ const std::set<std::string> &getRequiredExtensions() const;
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ private:
+ void checkOperator(TIntermOperator *node);
+
+ int mTargetVersion;
+
+ std::set<std::string> mEnabledExtensions;
+ std::set<std::string> mRequiredExtensions;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp
new file mode 100644
index 0000000000..368854f068
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp
@@ -0,0 +1,76 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FlagStd140Structs.cpp: Find structs in std140 blocks, where the padding added in the translator
+// conflicts with the "natural" unpadded type.
+
+#include "compiler/translator/FlagStd140Structs.h"
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class FlagStd140StructsTraverser : public TIntermTraverser
+{
+ public:
+ FlagStd140StructsTraverser() : TIntermTraverser(true, false, false) {}
+
+ const std::vector<MappedStruct> getMappedStructs() const { return mMappedStructs; }
+
+ protected:
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+
+ private:
+ void mapBlockStructMembers(TIntermSymbol *blockDeclarator, const TInterfaceBlock *block);
+
+ std::vector<MappedStruct> mMappedStructs;
+};
+
+void FlagStd140StructsTraverser::mapBlockStructMembers(TIntermSymbol *blockDeclarator,
+ const TInterfaceBlock *block)
+{
+ for (auto *field : block->fields())
+ {
+ if (field->type()->getBasicType() == EbtStruct)
+ {
+ MappedStruct mappedStruct;
+ mappedStruct.blockDeclarator = blockDeclarator;
+ mappedStruct.field = field;
+ mMappedStructs.push_back(mappedStruct);
+ }
+ }
+}
+
+bool FlagStd140StructsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ TIntermTyped *declarator = node->getSequence()->back()->getAsTyped();
+ if (declarator->getBasicType() == EbtInterfaceBlock)
+ {
+ const TInterfaceBlock *block = declarator->getType().getInterfaceBlock();
+ if (block->blockStorage() == EbsStd140)
+ {
+ mapBlockStructMembers(declarator->getAsSymbolNode(), block);
+ }
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+std::vector<MappedStruct> FlagStd140Structs(TIntermNode *node)
+{
+ FlagStd140StructsTraverser flaggingTraversal;
+
+ node->traverse(&flaggingTraversal);
+
+ return flaggingTraversal.getMappedStructs();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h
new file mode 100644
index 0000000000..ce035d9185
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FlagStd140Structs.h: Find structs in std140 blocks, where the padding added in the translator
+// conflicts with the "natural" unpadded type.
+
+#ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
+#define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
+
+#include <vector>
+
+namespace sh
+{
+
+class TField;
+class TIntermNode;
+class TIntermSymbol;
+
+struct MappedStruct
+{
+ TIntermSymbol *blockDeclarator;
+ TField *field;
+};
+
+std::vector<MappedStruct> FlagStd140Structs(TIntermNode *node);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp
new file mode 100644
index 0000000000..fd5091c5ed
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp
@@ -0,0 +1,179 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FunctionLookup.cpp: Used for storing function calls that have not yet been resolved during
+// parsing.
+//
+
+#include "compiler/translator/FunctionLookup.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const char kFunctionMangledNameSeparator = '(';
+
+constexpr const ImmutableString kEmptyName("");
+
+// Helper function for GetMangledNames
+// Gets all ordered combinations of elements in list[currentIndex, end]
+std::vector<std::vector<int>> GetImplicitConversionCombinations(const std::vector<int> &list)
+{
+ std::vector<std::vector<int>> target;
+ target.push_back(std::vector<int>());
+
+ for (size_t currentIndex = 0; currentIndex < list.size(); currentIndex++)
+ {
+ size_t prevIterSize = target.size();
+ for (size_t copyIndex = 0; copyIndex < prevIterSize; copyIndex++)
+ {
+ std::vector<int> combination = target[copyIndex];
+ combination.push_back(list[currentIndex]);
+ target.push_back(combination);
+ }
+ }
+
+ return target;
+}
+
+} // anonymous namespace
+
+TFunctionLookup::TFunctionLookup(const ImmutableString &name,
+ const TType *constructorType,
+ const TSymbol *symbol)
+ : mName(name), mConstructorType(constructorType), mThisNode(nullptr), mSymbol(symbol)
+{}
+
+// static
+TFunctionLookup *TFunctionLookup::CreateConstructor(const TType *type)
+{
+ ASSERT(type != nullptr);
+ return new TFunctionLookup(kEmptyName, type, nullptr);
+}
+
+// static
+TFunctionLookup *TFunctionLookup::CreateFunctionCall(const ImmutableString &name,
+ const TSymbol *symbol)
+{
+ ASSERT(name != "");
+ return new TFunctionLookup(name, nullptr, symbol);
+}
+
+const ImmutableString &TFunctionLookup::name() const
+{
+ return mName;
+}
+
+ImmutableString TFunctionLookup::getMangledName() const
+{
+ return GetMangledName(mName.data(), mArguments);
+}
+
+ImmutableString TFunctionLookup::GetMangledName(const char *functionName,
+ const TIntermSequence &arguments)
+{
+ std::string newName(functionName);
+ newName += kFunctionMangledNameSeparator;
+
+ for (TIntermNode *argument : arguments)
+ {
+ newName += argument->getAsTyped()->getType().getMangledName();
+ }
+ return ImmutableString(newName);
+}
+
+std::vector<ImmutableString> GetMangledNames(const char *functionName,
+ const TIntermSequence &arguments)
+{
+ std::vector<ImmutableString> target;
+
+ std::vector<int> indexes;
+ for (int i = 0; i < static_cast<int>(arguments.size()); i++)
+ {
+ TIntermNode *argument = arguments[i];
+ TBasicType argType = argument->getAsTyped()->getType().getBasicType();
+ if (argType == EbtInt || argType == EbtUInt)
+ {
+ indexes.push_back(i);
+ }
+ }
+
+ std::vector<std::vector<int>> combinations = GetImplicitConversionCombinations(indexes);
+ for (const std::vector<int> &combination : combinations)
+ {
+ // combination: ordered list of indexes for arguments that should be converted to float
+ std::string newName(functionName);
+ newName += kFunctionMangledNameSeparator;
+ // combination[currentIndex] represents index of next argument to be converted
+ int currentIndex = 0;
+ for (int i = 0; i < (int)arguments.size(); i++)
+ {
+ TIntermNode *argument = arguments[i];
+
+ if (currentIndex != static_cast<int>(combination.size()) &&
+ combination[currentIndex] == i)
+ {
+ // Convert
+ TType type = argument->getAsTyped()->getType();
+ type.setBasicType(EbtFloat);
+ newName += type.getMangledName();
+ currentIndex++;
+ }
+ else
+ {
+ // Don't convert
+ newName += argument->getAsTyped()->getType().getMangledName();
+ }
+ }
+ target.push_back(ImmutableString(newName));
+ }
+
+ return target;
+}
+
+std::vector<ImmutableString> TFunctionLookup::getMangledNamesForImplicitConversions() const
+{
+ return GetMangledNames(mName.data(), mArguments);
+}
+
+bool TFunctionLookup::isConstructor() const
+{
+ return mConstructorType != nullptr;
+}
+
+const TType &TFunctionLookup::constructorType() const
+{
+ return *mConstructorType;
+}
+
+void TFunctionLookup::setThisNode(TIntermTyped *thisNode)
+{
+ mThisNode = thisNode;
+}
+
+TIntermTyped *TFunctionLookup::thisNode() const
+{
+ return mThisNode;
+}
+
+void TFunctionLookup::addArgument(TIntermTyped *argument)
+{
+ mArguments.push_back(argument);
+}
+
+TIntermSequence &TFunctionLookup::arguments()
+{
+ return mArguments;
+}
+
+const TSymbol *TFunctionLookup::symbol() const
+{
+ return mSymbol;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/FunctionLookup.h b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.h
new file mode 100644
index 0000000000..7b0b2dafa5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.h
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FunctionLookup.h: Used for storing function calls that have not yet been resolved during parsing.
+//
+
+#ifndef COMPILER_TRANSLATOR_FUNCTIONLOOKUP_H_
+#define COMPILER_TRANSLATOR_FUNCTIONLOOKUP_H_
+
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+// A function look-up.
+class TFunctionLookup : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+
+ static TFunctionLookup *CreateConstructor(const TType *type);
+ static TFunctionLookup *CreateFunctionCall(const ImmutableString &name, const TSymbol *symbol);
+
+ const ImmutableString &name() const;
+ ImmutableString getMangledName() const;
+ static ImmutableString GetMangledName(const char *functionName,
+ const TIntermSequence &arguments);
+ std::vector<ImmutableString> getMangledNamesForImplicitConversions() const;
+
+ bool isConstructor() const;
+ const TType &constructorType() const;
+
+ void setThisNode(TIntermTyped *thisNode);
+ TIntermTyped *thisNode() const;
+
+ void addArgument(TIntermTyped *argument);
+ TIntermSequence &arguments();
+
+ // Symbol looked up in the lexical phase using only the name of the function.
+ // This does not necessarily correspond to the correct overloaded function.
+ const TSymbol *symbol() const;
+
+ private:
+ TFunctionLookup(const ImmutableString &name,
+ const TType *constructorType,
+ const TSymbol *symbol);
+
+ const ImmutableString mName;
+ const TType *const mConstructorType;
+ TIntermTyped *mThisNode;
+ TIntermSequence mArguments;
+ const TSymbol *mSymbol;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_FUNCTIONLOOKUP_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/HashNames.cpp b/gfx/angle/checkout/src/compiler/translator/HashNames.cpp
new file mode 100644
index 0000000000..6994c10afa
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/HashNames.cpp
@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/HashNames.h"
+
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+namespace
+{
+constexpr const ImmutableString kHashedNamePrefix("webgl_");
+
+// Can't prefix with just _ because then we might introduce a double underscore, which is not safe
+// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for
+// use by the underlying implementation). u is short for user-defined.
+constexpr const ImmutableString kUnhashedNamePrefix("_u");
+
+ImmutableString HashName(const ImmutableString &name, ShHashFunction64 hashFunction)
+{
+ ASSERT(!name.empty());
+ ASSERT(hashFunction);
+ khronos_uint64_t number = (*hashFunction)(name.data(), name.length());
+
+ // Build the hashed name in place.
+ static const unsigned int kHexStrMaxLength = sizeof(number) * 2;
+ static const size_t kHashedNameMaxLength = kHashedNamePrefix.length() + kHexStrMaxLength;
+
+ ImmutableStringBuilder hashedName(kHashedNameMaxLength);
+ hashedName << kHashedNamePrefix;
+
+ hashedName.appendHex(number);
+
+ return hashedName;
+}
+
+} // anonymous namespace
+
+ImmutableString HashName(const ImmutableString &name,
+ ShHashFunction64 hashFunction,
+ NameMap *nameMap)
+{
+ if (hashFunction == nullptr)
+ {
+ if (name.length() + kUnhashedNamePrefix.length() > kESSLMaxIdentifierLength)
+ {
+ // If the identifier length is already close to the limit, we can't prefix it. This is
+ // not a problem since there are no builtins or ANGLE's internal variables that would
+ // have as long names and could conflict.
+ return name;
+ }
+ ImmutableStringBuilder prefixedName(kUnhashedNamePrefix.length() + name.length());
+ prefixedName << kUnhashedNamePrefix << name;
+ return prefixedName;
+ }
+ if (nameMap)
+ {
+ NameMap::const_iterator it = nameMap->find(name.data());
+ if (it != nameMap->end())
+ {
+ // TODO(oetuaho): Would be nice if we didn't need to allocate a string here.
+ return ImmutableString(it->second);
+ }
+ }
+ ImmutableString hashedName = HashName(name, hashFunction);
+ if (nameMap)
+ {
+ (*nameMap)[name.data()] = hashedName.data();
+ }
+ return hashedName;
+}
+
+ImmutableString HashName(const TSymbol *symbol, ShHashFunction64 hashFunction, NameMap *nameMap)
+{
+ if (symbol->symbolType() == SymbolType::Empty)
+ {
+ return kEmptyImmutableString;
+ }
+ if (symbol->symbolType() == SymbolType::AngleInternal ||
+ symbol->symbolType() == SymbolType::BuiltIn)
+ {
+ return symbol->name();
+ }
+ return HashName(symbol->name(), hashFunction, nameMap);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/HashNames.h b/gfx/angle/checkout/src/compiler/translator/HashNames.h
new file mode 100644
index 0000000000..132cb59337
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/HashNames.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_HASHNAMES_H_
+#define COMPILER_TRANSLATOR_HASHNAMES_H_
+
+#include <map>
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+
+typedef std::map<TPersistString, TPersistString> NameMap;
+
+class ImmutableString;
+class TSymbol;
+
+ImmutableString HashName(const ImmutableString &name,
+ ShHashFunction64 hashFunction,
+ NameMap *nameMap);
+
+// Hash user-defined name for GLSL output, with special handling for internal names.
+// The nameMap parameter is optional and is used to cache hashed names if set.
+ImmutableString HashName(const TSymbol *symbol, ShHashFunction64 hashFunction, NameMap *nameMap);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_HASHNAMES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp
new file mode 100644
index 0000000000..d60cce09e5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp
@@ -0,0 +1,371 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output.
+//
+
+#include "compiler/translator/ImageFunctionHLSL.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/UtilsHLSL.h"
+
+namespace sh
+{
+
+// static
+ImmutableString ImageFunctionHLSL::GetImageReference(
+ TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction)
+{
+ static const ImmutableString kImageIndexStr("[index]");
+ if (imageFunction.readonly)
+ {
+ static const ImmutableString kReadonlyImagesStr("readonlyImages");
+ ImmutableString suffix(
+ TextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat));
+ out << " const uint index = imageIndex - readonlyImageIndexOffset" << suffix.data()
+ << ";\n";
+ ImmutableStringBuilder imageRefBuilder(kReadonlyImagesStr.length() + suffix.length() +
+ kImageIndexStr.length());
+ imageRefBuilder << kReadonlyImagesStr << suffix << kImageIndexStr;
+ return imageRefBuilder;
+ }
+ else
+ {
+ static const ImmutableString kImagesStr("images");
+ ImmutableString suffix(
+ RWTextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat));
+ out << " const uint index = imageIndex - imageIndexOffset" << suffix.data() << ";\n";
+ ImmutableStringBuilder imageRefBuilder(kImagesStr.length() + suffix.length() +
+ kImageIndexStr.length());
+ imageRefBuilder << kImagesStr << suffix << kImageIndexStr;
+ return imageRefBuilder;
+ }
+}
+
+void ImageFunctionHLSL::OutputImageFunctionArgumentList(
+ TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction)
+{
+ out << "uint imageIndex";
+
+ if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD ||
+ imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
+ {
+ switch (imageFunction.image)
+ {
+ case EbtImage2D:
+ case EbtIImage2D:
+ case EbtUImage2D:
+ out << ", int2 p";
+ break;
+ case EbtImage3D:
+ case EbtIImage3D:
+ case EbtUImage3D:
+ case EbtImageCube:
+ case EbtIImageCube:
+ case EbtUImageCube:
+ case EbtImage2DArray:
+ case EbtIImage2DArray:
+ case EbtUImage2DArray:
+ out << ", int3 p";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
+ {
+ switch (imageFunction.image)
+ {
+ case EbtImage2D:
+ case EbtImage3D:
+ case EbtImageCube:
+ case EbtImage2DArray:
+ out << ", float4 data";
+ break;
+ case EbtIImage2D:
+ case EbtIImage3D:
+ case EbtIImageCube:
+ case EbtIImage2DArray:
+ out << ", int4 data";
+ break;
+ case EbtUImage2D:
+ case EbtUImage3D:
+ case EbtUImageCube:
+ case EbtUImage2DArray:
+ out << ", uint4 data";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+}
+
+// static
+void ImageFunctionHLSL::OutputImageSizeFunctionBody(
+ TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction,
+ const ImmutableString &imageReference)
+{
+ if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
+ IsImageCube(imageFunction.image))
+ {
+ // "depth" stores either the number of layers in an array texture or 3D depth
+ out << " uint width; uint height; uint depth;\n"
+ << " " << imageReference << ".GetDimensions(width, height, depth);\n";
+ }
+ else if (IsImage2D(imageFunction.image))
+ {
+ out << " uint width; uint height;\n"
+ << " " << imageReference << ".GetDimensions(width, height);\n";
+ }
+ else
+ UNREACHABLE();
+
+ if (strcmp(imageFunction.getReturnType(), "int3") == 0)
+ {
+ out << " return int3(width, height, depth);\n";
+ }
+ else
+ {
+ out << " return int2(width, height);\n";
+ }
+}
+
+// static
+void ImageFunctionHLSL::OutputImageLoadFunctionBody(
+ TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction,
+ const ImmutableString &imageReference)
+{
+ if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
+ IsImageCube(imageFunction.image))
+ {
+ out << " return " << imageReference << "[uint3(p.x, p.y, p.z)];\n";
+ }
+ else if (IsImage2D(imageFunction.image))
+ {
+ out << " return " << imageReference << "[uint2(p.x, p.y)];\n";
+ }
+ else
+ UNREACHABLE();
+}
+
+// static
+void ImageFunctionHLSL::OutputImageStoreFunctionBody(
+ TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction,
+ const ImmutableString &imageReference)
+{
+ if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
+ IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image))
+ {
+ out << " " << imageReference << "[p] = data;\n";
+ }
+ else
+ UNREACHABLE();
+}
+
+ImmutableString ImageFunctionHLSL::ImageFunction::name() const
+{
+ static const ImmutableString kGlImageName("gl_image");
+
+ ImmutableString suffix(nullptr);
+ if (readonly)
+ {
+ suffix = ImmutableString(TextureTypeSuffix(image, imageInternalFormat));
+ }
+ else
+ {
+ suffix = ImmutableString(RWTextureTypeSuffix(image, imageInternalFormat));
+ }
+
+ ImmutableStringBuilder name(kGlImageName.length() + suffix.length() + 5u);
+
+ name << kGlImageName << suffix;
+
+ switch (method)
+ {
+ case Method::SIZE:
+ name << "Size";
+ break;
+ case Method::LOAD:
+ name << "Load";
+ break;
+ case Method::STORE:
+ name << "Store";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return name;
+}
+
+ImageFunctionHLSL::ImageFunction::DataType ImageFunctionHLSL::ImageFunction::getDataType(
+ TLayoutImageInternalFormat format) const
+{
+ switch (format)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return ImageFunction::DataType::FLOAT4;
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return ImageFunction::DataType::UINT4;
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return ImageFunction::DataType::INT4;
+ case EiifRGBA8:
+ return ImageFunction::DataType::UNORM_FLOAT4;
+ case EiifRGBA8_SNORM:
+ return ImageFunction::DataType::SNORM_FLOAT4;
+ default:
+ UNREACHABLE();
+ }
+
+ return ImageFunction::DataType::NONE;
+}
+
+const char *ImageFunctionHLSL::ImageFunction::getReturnType() const
+{
+ if (method == ImageFunction::Method::SIZE)
+ {
+ switch (image)
+ {
+ case EbtImage2D:
+ case EbtIImage2D:
+ case EbtUImage2D:
+ case EbtImageCube:
+ case EbtIImageCube:
+ case EbtUImageCube:
+ return "int2";
+ case EbtImage3D:
+ case EbtIImage3D:
+ case EbtUImage3D:
+ case EbtImage2DArray:
+ case EbtIImage2DArray:
+ case EbtUImage2DArray:
+ return "int3";
+ default:
+ UNREACHABLE();
+ }
+ }
+ else if (method == ImageFunction::Method::LOAD)
+ {
+ switch (image)
+ {
+ case EbtImage2D:
+ case EbtImage3D:
+ case EbtImageCube:
+ case EbtImage2DArray:
+ return "float4";
+ case EbtIImage2D:
+ case EbtIImage3D:
+ case EbtIImageCube:
+ case EbtIImage2DArray:
+ return "int4";
+ case EbtUImage2D:
+ case EbtUImage3D:
+ case EbtUImageCube:
+ case EbtUImage2DArray:
+ return "uint4";
+ default:
+ UNREACHABLE();
+ }
+ }
+ else if (method == ImageFunction::Method::STORE)
+ {
+ return "void";
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ return "";
+}
+
+bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const
+{
+ return std::tie(image, type, method, readonly) <
+ std::tie(rhs.image, rhs.type, rhs.method, rhs.readonly);
+}
+
+ImmutableString ImageFunctionHLSL::useImageFunction(const ImmutableString &name,
+ const TBasicType &type,
+ TLayoutImageInternalFormat imageInternalFormat,
+ bool readonly)
+{
+ ASSERT(IsImage(type));
+ ImageFunction imageFunction;
+ imageFunction.image = type;
+ imageFunction.imageInternalFormat = imageInternalFormat;
+ imageFunction.readonly = readonly;
+ imageFunction.type = imageFunction.getDataType(imageInternalFormat);
+
+ if (name == "imageSize")
+ {
+ imageFunction.method = ImageFunction::Method::SIZE;
+ }
+ else if (name == "imageLoad")
+ {
+ imageFunction.method = ImageFunction::Method::LOAD;
+ }
+ else if (name == "imageStore")
+ {
+ imageFunction.method = ImageFunction::Method::STORE;
+ }
+ else
+ UNREACHABLE();
+
+ mUsesImage.insert(imageFunction);
+ return imageFunction.name();
+}
+
+void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out)
+{
+ for (const ImageFunction &imageFunction : mUsesImage)
+ {
+ // Skip to generate image2D functions here, dynamically generate these
+ // functions when linking, or after dispatch or draw.
+ if (IsImage2D(imageFunction.image))
+ {
+ mUsedImage2DFunctionNames.insert(imageFunction.name().data());
+ continue;
+ }
+ // Function header
+ out << imageFunction.getReturnType() << " " << imageFunction.name() << "(";
+
+ OutputImageFunctionArgumentList(out, imageFunction);
+
+ out << ")\n"
+ "{\n";
+
+ ImmutableString imageReference = GetImageReference(out, imageFunction);
+ if (imageFunction.method == ImageFunction::Method::SIZE)
+ {
+ OutputImageSizeFunctionBody(out, imageFunction, imageReference);
+ }
+ else if (imageFunction.method == ImageFunction::Method::LOAD)
+ {
+ OutputImageLoadFunctionBody(out, imageFunction, imageReference);
+ }
+ else
+ {
+ OutputImageStoreFunctionBody(out, imageFunction, imageReference);
+ }
+
+ out << "}\n"
+ "\n";
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h
new file mode 100644
index 0000000000..56c1dcc8e0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h
@@ -0,0 +1,96 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output.
+//
+
+#ifndef COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_
+#define COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_
+
+#include <set>
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/Types.h"
+
+namespace sh
+{
+
+class ImageFunctionHLSL final : angle::NonCopyable
+{
+ public:
+ // Returns the name of the image function implementation to caller.
+ // The name that's passed in is the name of the GLSL image function that it should implement.
+ ImmutableString useImageFunction(const ImmutableString &name,
+ const TBasicType &type,
+ TLayoutImageInternalFormat imageInternalFormat,
+ bool readonly);
+
+ void imageFunctionHeader(TInfoSinkBase &out);
+ const std::set<std::string> &getUsedImage2DFunctionNames() const
+ {
+ return mUsedImage2DFunctionNames;
+ }
+
+ private:
+ struct ImageFunction
+ {
+ // See ESSL 3.10.4 section 8.12 for reference about what the different methods below do.
+ enum class Method
+ {
+ SIZE,
+ LOAD,
+ STORE
+ };
+
+ enum class DataType
+ {
+ NONE,
+ FLOAT4,
+ UINT4,
+ INT4,
+ UNORM_FLOAT4,
+ SNORM_FLOAT4
+ };
+
+ ImmutableString name() const;
+
+ bool operator<(const ImageFunction &rhs) const;
+
+ DataType getDataType(TLayoutImageInternalFormat format) const;
+
+ const char *getReturnType() const;
+
+ TBasicType image;
+ TLayoutImageInternalFormat imageInternalFormat;
+ bool readonly;
+ Method method;
+ DataType type;
+ };
+
+ static ImmutableString GetImageReference(TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction);
+ static void OutputImageFunctionArgumentList(
+ TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction);
+ static void OutputImageSizeFunctionBody(TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction,
+ const ImmutableString &imageReference);
+ static void OutputImageLoadFunctionBody(TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction,
+ const ImmutableString &imageReference);
+ static void OutputImageStoreFunctionBody(TInfoSinkBase &out,
+ const ImageFunctionHLSL::ImageFunction &imageFunction,
+ const ImmutableString &imageReference);
+ using ImageFunctionSet = std::set<ImageFunction>;
+ ImageFunctionSet mUsesImage;
+ std::set<std::string> mUsedImage2DFunctionNames;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp b/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp
new file mode 100644
index 0000000000..38f3fa052c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImmutableString.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be
+// valid and unchanged for the duration of the compilation.
+//
+
+#include "compiler/translator/ImmutableString.h"
+
+std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str)
+{
+ return os.write(str.data(), str.length());
+}
+
+#if defined(_MSC_VER)
+# pragma warning(disable : 4309) // truncation of constant value
+#endif
+
+namespace sh
+{
+
+template <>
+const size_t ImmutableString::FowlerNollVoHash<4>::kFnvPrime = 16777619u;
+
+template <>
+const size_t ImmutableString::FowlerNollVoHash<4>::kFnvOffsetBasis = 0x811c9dc5u;
+
+template <>
+const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime =
+ static_cast<size_t>(1099511628211ull);
+
+template <>
+const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis =
+ static_cast<size_t>(0xcbf29ce484222325ull);
+
+uint32_t ImmutableString::mangledNameHash() const
+{
+ const char *dataPtr = data();
+ uint32_t hash = static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvOffsetBasis);
+ const uint32_t kMaxSixBitValue = (1u << 6) - 1u;
+ uint32_t parenLocation = kMaxSixBitValue;
+ uint32_t hasArrayOrBlockParamBit = 0u;
+ uint32_t index = 0;
+ while (dataPtr[index] != '\0')
+ {
+ hash = hash ^ dataPtr[index];
+ hash = hash * static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvPrime);
+ if (dataPtr[index] == '(')
+ {
+ // We should only reach here once, since this function should not be called with invalid
+ // mangled names.
+ ASSERT(parenLocation == kMaxSixBitValue);
+ parenLocation = index;
+ }
+ else if (dataPtr[index] == '{' || dataPtr[index] == '[')
+ {
+ hasArrayOrBlockParamBit = 1u;
+ }
+ ++index;
+ }
+ // Should not be called with strings longer than 63 characters.
+ ASSERT(index <= kMaxSixBitValue);
+ return ((hash >> 13) ^ (hash & 0x1fff)) | (index << 19) | (parenLocation << 25) |
+ (hasArrayOrBlockParamBit << 31);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableString.h b/gfx/angle/checkout/src/compiler/translator/ImmutableString.h
new file mode 100644
index 0000000000..5f08ea06cc
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.h
@@ -0,0 +1,144 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImmutableString.h: Wrapper for static or pool allocated char arrays, that are guaranteed to be
+// valid and unchanged for the duration of the compilation.
+//
+
+#ifndef COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
+#define COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
+
+#include <string>
+
+#include "common/string_utils.h"
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+
+namespace
+{
+constexpr size_t constStrlen(const char *str)
+{
+ if (str == nullptr)
+ {
+ return 0u;
+ }
+ size_t len = 0u;
+ while (*(str + len) != '\0')
+ {
+ ++len;
+ }
+ return len;
+}
+} // namespace
+
+class ImmutableString
+{
+ public:
+ // The data pointer passed in must be one of:
+ // 1. nullptr (only valid with length 0).
+ // 2. a null-terminated static char array like a string literal.
+ // 3. a null-terminated pool allocated char array. This can't be c_str() of a local TString,
+ // since when a TString goes out of scope it clears its first character.
+ explicit constexpr ImmutableString(const char *data) : mData(data), mLength(constStrlen(data))
+ {}
+
+ constexpr ImmutableString(const char *data, size_t length) : mData(data), mLength(length) {}
+
+ ImmutableString(const std::string &str)
+ : mData(AllocatePoolCharArray(str.c_str(), str.size())), mLength(str.size())
+ {}
+
+ constexpr ImmutableString(const ImmutableString &) = default;
+
+ ImmutableString &operator=(const ImmutableString &) = default;
+
+ constexpr const char *data() const { return mData ? mData : ""; }
+ constexpr size_t length() const { return mLength; }
+
+ char operator[](size_t index) const { return data()[index]; }
+
+ constexpr bool empty() const { return mLength == 0; }
+ bool beginsWith(const char *prefix) const { return angle::BeginsWith(data(), prefix); }
+ constexpr bool beginsWith(const ImmutableString &prefix) const
+ {
+ return mLength >= prefix.length() && memcmp(data(), prefix.data(), prefix.length()) == 0;
+ }
+ bool contains(const char *substr) const { return strstr(data(), substr) != nullptr; }
+
+ constexpr bool operator==(const ImmutableString &b) const
+ {
+ if (mLength != b.mLength)
+ {
+ return false;
+ }
+ return memcmp(data(), b.data(), mLength) == 0;
+ }
+ constexpr bool operator!=(const ImmutableString &b) const { return !(*this == b); }
+ constexpr bool operator==(const char *b) const
+ {
+ if (b == nullptr)
+ {
+ return empty();
+ }
+ return strcmp(data(), b) == 0;
+ }
+ constexpr bool operator!=(const char *b) const { return !(*this == b); }
+ bool operator==(const std::string &b) const
+ {
+ return mLength == b.length() && memcmp(data(), b.c_str(), mLength) == 0;
+ }
+ bool operator!=(const std::string &b) const { return !(*this == b); }
+
+ constexpr bool operator<(const ImmutableString &b) const
+ {
+ if (mLength < b.mLength)
+ {
+ return true;
+ }
+ if (mLength > b.mLength)
+ {
+ return false;
+ }
+ return (memcmp(data(), b.data(), mLength) < 0);
+ }
+
+ template <size_t hashBytes>
+ struct FowlerNollVoHash
+ {
+ static const size_t kFnvOffsetBasis;
+ static const size_t kFnvPrime;
+
+ constexpr size_t operator()(const ImmutableString &a) const
+ {
+ const char *data = a.data();
+ size_t hash = kFnvOffsetBasis;
+ while ((*data) != '\0')
+ {
+ hash = hash ^ (*data);
+ hash = hash * kFnvPrime;
+ ++data;
+ }
+ return hash;
+ }
+ };
+
+ // This hash encodes the opening parentheses location (if any), name length and whether the name
+ // contains { or [ characters in addition to a 19-bit hash. This way the hash is more useful for
+ // lookups. The string passed in should be at most 63 characters.
+ uint32_t mangledNameHash() const;
+
+ private:
+ const char *mData;
+ size_t mLength;
+};
+
+constexpr ImmutableString kEmptyImmutableString("");
+} // namespace sh
+
+std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str);
+
+#endif // COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp
new file mode 100644
index 0000000000..d7d0a0135d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp
@@ -0,0 +1,63 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImmutableStringBuilder.cpp: Stringstream-like utility for building pool allocated strings where
+// the maximum length is known in advance.
+//
+
+#include "compiler/translator/ImmutableStringBuilder.h"
+
+#include <stdio.h>
+
+namespace sh
+{
+
+ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const ImmutableString &str)
+{
+ ASSERT(mData != nullptr);
+ ASSERT(mPos + str.length() <= mMaxLength);
+ memcpy(mData + mPos, str.data(), str.length());
+ mPos += str.length();
+ return *this;
+}
+
+ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const char *str)
+{
+ ASSERT(mData != nullptr);
+ size_t len = strlen(str);
+ ASSERT(mPos + len <= mMaxLength);
+ memcpy(mData + mPos, str, len);
+ mPos += len;
+ return *this;
+}
+
+ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const char &c)
+{
+ ASSERT(mData != nullptr);
+ ASSERT(mPos + 1 <= mMaxLength);
+ mData[mPos++] = c;
+ return *this;
+}
+
+void ImmutableStringBuilder::appendDecimal(const uint32_t &u)
+{
+ int numChars = snprintf(mData + mPos, mMaxLength - mPos, "%d", u);
+ ASSERT(numChars >= 0);
+ ASSERT(mPos + numChars <= mMaxLength);
+ mPos += numChars;
+}
+
+ImmutableStringBuilder::operator ImmutableString()
+{
+ mData[mPos] = '\0';
+ ImmutableString str(static_cast<const char *>(mData), mPos);
+#if defined(ANGLE_ENABLE_ASSERTS)
+ // Make sure that nothing is added to the string after it is finalized.
+ mData = nullptr;
+#endif
+ return str;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h
new file mode 100644
index 0000000000..e68459169f
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ImmutableStringBuilder.h: Stringstream-like utility for building pool allocated strings where the
+// maximum length is known in advance.
+//
+
+#ifndef COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_
+#define COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_
+
+#include "compiler/translator/ImmutableString.h"
+
+namespace sh
+{
+
+class ImmutableStringBuilder
+{
+ public:
+ ImmutableStringBuilder(size_t maxLength)
+ : mPos(0u), mMaxLength(maxLength), mData(AllocateEmptyPoolCharArray(maxLength))
+ {}
+
+ ImmutableStringBuilder &operator<<(const ImmutableString &str);
+
+ ImmutableStringBuilder &operator<<(const char *str);
+
+ ImmutableStringBuilder &operator<<(const char &c);
+
+ // This invalidates the ImmutableStringBuilder, so it should only be called once.
+ operator ImmutableString();
+
+ void appendDecimal(const uint32_t &i);
+
+ template <typename T>
+ void appendHex(T number)
+ {
+ ASSERT(mData != nullptr);
+ ASSERT(mPos + sizeof(T) * 2u <= mMaxLength);
+ int index = static_cast<int>(sizeof(T)) * 2 - 1;
+ // Loop through leading zeroes.
+ while (((number >> (index * 4)) & 0xfu) == 0 && index > 0)
+ {
+ --index;
+ }
+ // Write the rest of the hex digits.
+ while (index >= 0)
+ {
+ char digit = static_cast<char>((number >> (index * 4)) & 0xfu);
+ char digitChar = (digit < 10) ? (digit + '0') : (digit + ('a' - 10));
+ mData[mPos++] = digitChar;
+ --index;
+ }
+ }
+
+ template <typename T>
+ static constexpr size_t GetHexCharCount()
+ {
+ return sizeof(T) * 2;
+ }
+
+ private:
+ inline static char *AllocateEmptyPoolCharArray(size_t strLength)
+ {
+ size_t requiredSize = strLength + 1u;
+ return static_cast<char *>(GetGlobalPoolAllocator()->allocate(requiredSize));
+ }
+
+ size_t mPos;
+ size_t mMaxLength;
+ char *mData;
+};
+
+// GLSL ES 3.00.6 section 3.9: the maximum length of an identifier is 1024 characters.
+constexpr unsigned int kESSLMaxIdentifierLength = 1024u;
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/InfoSink.cpp b/gfx/angle/checkout/src/compiler/translator/InfoSink.cpp
new file mode 100644
index 0000000000..e8a8453081
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InfoSink.cpp
@@ -0,0 +1,82 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InfoSink.h"
+
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/Types.h"
+
+namespace sh
+{
+
+void TInfoSinkBase::prefix(Severity severity)
+{
+ switch (severity)
+ {
+ case SH_WARNING:
+ sink.append("WARNING: ");
+ break;
+ case SH_ERROR:
+ sink.append("ERROR: ");
+ break;
+ default:
+ sink.append("UNKOWN ERROR: ");
+ break;
+ }
+}
+
+TInfoSinkBase &TInfoSinkBase::operator<<(const ImmutableString &str)
+{
+ sink.append(str.data());
+ return *this;
+}
+
+TInfoSinkBase &TInfoSinkBase::operator<<(const TType &type)
+{
+ if (type.isInvariant())
+ sink.append("invariant ");
+ if (type.getQualifier() != EvqTemporary && type.getQualifier() != EvqGlobal)
+ {
+ sink.append(type.getQualifierString());
+ sink.append(" ");
+ }
+ if (type.getPrecision() != EbpUndefined)
+ {
+ sink.append(type.getPrecisionString());
+ sink.append(" ");
+ }
+ if (type.isArray())
+ {
+ for (auto arraySizeIter = type.getArraySizes()->rbegin();
+ arraySizeIter != type.getArraySizes()->rend(); ++arraySizeIter)
+ {
+ *this << "array[" << (*arraySizeIter) << "] of ";
+ }
+ }
+ if (type.isMatrix())
+ {
+ *this << type.getCols() << "X" << type.getRows() << " matrix of ";
+ }
+ else if (type.isVector())
+ *this << type.getNominalSize() << "-component vector of ";
+
+ sink.append(type.getBasicString());
+ return *this;
+}
+
+void TInfoSinkBase::location(int file, int line)
+{
+ TPersistStringStream stream = sh::InitializeStream<TPersistStringStream>();
+ if (line)
+ stream << file << ":" << line;
+ else
+ stream << file << ":? ";
+ stream << ": ";
+
+ sink.append(stream.str());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/InfoSink.h b/gfx/angle/checkout/src/compiler/translator/InfoSink.h
new file mode 100644
index 0000000000..100d06ec6b
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InfoSink.h
@@ -0,0 +1,129 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_INFOSINK_H_
+#define COMPILER_TRANSLATOR_INFOSINK_H_
+
+#include <math.h>
+#include <stdlib.h>
+#include "compiler/translator/Common.h"
+#include "compiler/translator/Severity.h"
+
+namespace sh
+{
+
+class ImmutableString;
+class TType;
+
+// Returns the fractional part of the given floating-point number.
+inline float fractionalPart(float f)
+{
+ float intPart = 0.0f;
+ return modff(f, &intPart);
+}
+
+class ImmutableString;
+
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase
+{
+ public:
+ TInfoSinkBase() {}
+
+ template <typename T>
+ TInfoSinkBase &operator<<(const T &t)
+ {
+ TPersistStringStream stream = sh::InitializeStream<TPersistStringStream>();
+ stream << t;
+ sink.append(stream.str());
+ return *this;
+ }
+ // Override << operator for specific types. It is faster to append strings
+ // and characters directly to the sink.
+ TInfoSinkBase &operator<<(char c)
+ {
+ sink.append(1, c);
+ return *this;
+ }
+ TInfoSinkBase &operator<<(const char *str)
+ {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase &operator<<(const TPersistString &str)
+ {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase &operator<<(const TString &str)
+ {
+ sink.append(str.c_str());
+ return *this;
+ }
+ TInfoSinkBase &operator<<(const ImmutableString &str);
+
+ TInfoSinkBase &operator<<(const TType &type);
+
+ // Make sure floats are written with correct precision.
+ TInfoSinkBase &operator<<(float f)
+ {
+ // Make sure that at least one decimal point is written. If a number
+ // does not have a fractional part, the default precision format does
+ // not write the decimal portion which gets interpreted as integer by
+ // the compiler.
+ TPersistStringStream stream = sh::InitializeStream<TPersistStringStream>();
+ if (fractionalPart(f) == 0.0f)
+ {
+ stream.precision(1);
+ stream << std::showpoint << std::fixed << f;
+ }
+ else
+ {
+ stream.unsetf(std::ios::fixed);
+ stream.unsetf(std::ios::scientific);
+ stream.precision(8);
+ stream << f;
+ }
+ sink.append(stream.str());
+ return *this;
+ }
+ // Write boolean values as their names instead of integral value.
+ TInfoSinkBase &operator<<(bool b)
+ {
+ const char *str = b ? "true" : "false";
+ sink.append(str);
+ return *this;
+ }
+
+ void erase() { sink.clear(); }
+ int size() { return static_cast<int>(sink.size()); }
+
+ const TPersistString &str() const { return sink; }
+ const char *c_str() const { return sink.c_str(); }
+
+ void prefix(Severity severity);
+ void location(int file, int line);
+
+ private:
+ TPersistString sink;
+};
+
+class TInfoSink
+{
+ public:
+ TInfoSinkBase info;
+ TInfoSinkBase debug;
+ TInfoSinkBase obj;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_INFOSINK_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Initialize.cpp b/gfx/angle/checkout/src/compiler/translator/Initialize.cpp
new file mode 100644
index 0000000000..eb3a7675a1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Initialize.cpp
@@ -0,0 +1,117 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/Initialize.h"
+
+namespace sh
+{
+
+void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavior &extBehavior)
+{
+ if (resources.OES_standard_derivatives)
+ {
+ extBehavior[TExtension::OES_standard_derivatives] = EBhUndefined;
+ }
+ if (resources.OES_EGL_image_external)
+ {
+ extBehavior[TExtension::OES_EGL_image_external] = EBhUndefined;
+ }
+ if (resources.OES_EGL_image_external_essl3)
+ {
+ extBehavior[TExtension::OES_EGL_image_external_essl3] = EBhUndefined;
+ }
+ if (resources.NV_EGL_stream_consumer_external)
+ {
+ extBehavior[TExtension::NV_EGL_stream_consumer_external] = EBhUndefined;
+ }
+ if (resources.ARB_texture_rectangle)
+ {
+ // Special: ARB_texture_rectangle extension does not follow the standard for #extension
+ // directives - it is enabled by default. An extension directive may still disable it.
+ extBehavior[TExtension::ARB_texture_rectangle] = EBhEnable;
+ }
+ if (resources.EXT_blend_func_extended)
+ {
+ extBehavior[TExtension::EXT_blend_func_extended] = EBhUndefined;
+ }
+ if (resources.EXT_draw_buffers)
+ {
+ extBehavior[TExtension::EXT_draw_buffers] = EBhUndefined;
+ }
+ if (resources.EXT_frag_depth)
+ {
+ extBehavior[TExtension::EXT_frag_depth] = EBhUndefined;
+ }
+ if (resources.EXT_shader_texture_lod)
+ {
+ extBehavior[TExtension::EXT_shader_texture_lod] = EBhUndefined;
+ }
+ if (resources.EXT_shader_framebuffer_fetch)
+ {
+ extBehavior[TExtension::EXT_shader_framebuffer_fetch] = EBhUndefined;
+ }
+ if (resources.NV_shader_framebuffer_fetch)
+ {
+ extBehavior[TExtension::NV_shader_framebuffer_fetch] = EBhUndefined;
+ }
+ if (resources.ARM_shader_framebuffer_fetch)
+ {
+ extBehavior[TExtension::ARM_shader_framebuffer_fetch] = EBhUndefined;
+ }
+ if (resources.OVR_multiview)
+ {
+ extBehavior[TExtension::OVR_multiview] = EBhUndefined;
+ }
+ if (resources.OVR_multiview2)
+ {
+ extBehavior[TExtension::OVR_multiview2] = EBhUndefined;
+ }
+ if (resources.EXT_YUV_target)
+ {
+ extBehavior[TExtension::EXT_YUV_target] = EBhUndefined;
+ }
+ if (resources.EXT_geometry_shader)
+ {
+ extBehavior[TExtension::EXT_geometry_shader] = EBhUndefined;
+ }
+ if (resources.OES_texture_storage_multisample_2d_array)
+ {
+ extBehavior[TExtension::OES_texture_storage_multisample_2d_array] = EBhUndefined;
+ }
+ if (resources.OES_texture_3D)
+ {
+ extBehavior[TExtension::OES_texture_3D] = EBhUndefined;
+ }
+ if (resources.ANGLE_texture_multisample)
+ {
+ extBehavior[TExtension::ANGLE_texture_multisample] = EBhUndefined;
+ }
+ if (resources.ANGLE_multi_draw)
+ {
+ extBehavior[TExtension::ANGLE_multi_draw] = EBhUndefined;
+ }
+ if (resources.ANGLE_base_vertex_base_instance)
+ {
+ extBehavior[TExtension::ANGLE_base_vertex_base_instance] = EBhUndefined;
+ }
+}
+
+void ResetExtensionBehavior(TExtensionBehavior &extBehavior)
+{
+ for (auto &ext : extBehavior)
+ {
+ if (ext.first == TExtension::ARB_texture_rectangle)
+ {
+ ext.second = EBhEnable;
+ }
+ else
+ {
+ ext.second = EBhUndefined;
+ }
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/Initialize.h b/gfx/angle/checkout/src/compiler/translator/Initialize.h
new file mode 100644
index 0000000000..290af56684
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Initialize.h
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_INITIALIZE_H_
+#define COMPILER_TRANSLATOR_INITIALIZE_H_
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+void InitExtensionBehavior(const ShBuiltInResources &resources,
+ TExtensionBehavior &extensionBehavior);
+
+// Resets the behavior of the extensions listed in |extensionBehavior| to the
+// undefined state. These extensions will only be those initially supported in
+// the ShBuiltInResources object for this compiler instance. All other
+// extensions will remain unsupported.
+void ResetExtensionBehavior(TExtensionBehavior &extensionBehavior);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_INITIALIZE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp b/gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp
new file mode 100644
index 0000000000..0698364500
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InitializeDll.h"
+#include "compiler/translator/InitializeGlobals.h"
+
+#include "common/platform.h"
+
+#include <assert.h>
+
+namespace sh
+{
+
+bool InitProcess()
+{
+ if (!InitializePoolIndex())
+ {
+ assert(0 && "InitProcess(): Failed to initalize global pool");
+ return false;
+ }
+
+ return true;
+}
+
+void DetachProcess()
+{
+ FreePoolIndex();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/InitializeDll.h b/gfx/angle/checkout/src/compiler/translator/InitializeDll.h
new file mode 100644
index 0000000000..87f7251470
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InitializeDll.h
@@ -0,0 +1,15 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef COMPILER_TRANSLATOR_INITIALIZEDLL_H_
+#define COMPILER_TRANSLATOR_INITIALIZEDLL_H_
+
+namespace sh
+{
+bool InitProcess();
+void DetachProcess();
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h b/gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h
new file mode 100644
index 0000000000..9a67ed0e04
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_
+#define COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_
+
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp b/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp
new file mode 100644
index 0000000000..42c1c994cf
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp
@@ -0,0 +1,3787 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <vector>
+
+#include "common/mathutil.h"
+#include "common/matrix_utils.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const float kPi = 3.14159265358979323846f;
+const float kDegreesToRadiansMultiplier = kPi / 180.0f;
+const float kRadiansToDegreesMultiplier = 180.0f / kPi;
+
+TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
+{
+ return left > right ? left : right;
+}
+
+TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
+{
+ TConstantUnion *constUnion = new TConstantUnion[size];
+ for (unsigned int i = 0; i < size; ++i)
+ constUnion[i] = constant;
+
+ return constUnion;
+}
+
+void UndefinedConstantFoldingError(const TSourceLoc &loc,
+ TOperator op,
+ TBasicType basicType,
+ TDiagnostics *diagnostics,
+ TConstantUnion *result)
+{
+ diagnostics->warning(loc, "operation result is undefined for the values passed in",
+ GetOperatorString(op));
+
+ switch (basicType)
+ {
+ case EbtFloat:
+ result->setFConst(0.0f);
+ break;
+ case EbtInt:
+ result->setIConst(0);
+ break;
+ case EbtUInt:
+ result->setUConst(0u);
+ break;
+ case EbtBool:
+ result->setBConst(false);
+ break;
+ default:
+ break;
+ }
+}
+
+float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
+{
+ float result = 0.0f;
+ for (size_t i = 0; i < paramArraySize; i++)
+ {
+ float f = paramArray[i].getFConst();
+ result += f * f;
+ }
+ return sqrtf(result);
+}
+
+float VectorDotProduct(const TConstantUnion *paramArray1,
+ const TConstantUnion *paramArray2,
+ size_t paramArraySize)
+{
+ float result = 0.0f;
+ for (size_t i = 0; i < paramArraySize; i++)
+ result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
+ return result;
+}
+
+TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
+{
+ ASSERT(constArray != nullptr);
+ // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
+ // without being qualified as constant.
+ TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
+ folded->setLine(originalNode->getLine());
+ return folded;
+}
+
+angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
+ const unsigned int rows,
+ const unsigned int cols)
+{
+ std::vector<float> elements;
+ for (size_t i = 0; i < rows * cols; i++)
+ elements.push_back(paramArray[i].getFConst());
+ // Transpose is used since the Matrix constructor expects arguments in row-major order,
+ // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
+ // so that the created matrix will have the expected dimensions after the transpose.
+ return angle::Matrix<float>(elements, cols, rows).transpose();
+}
+
+angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int size)
+{
+ std::vector<float> elements;
+ for (size_t i = 0; i < size * size; i++)
+ elements.push_back(paramArray[i].getFConst());
+ // Transpose is used since the Matrix constructor expects arguments in row-major order,
+ // whereas the paramArray is in column-major order.
+ return angle::Matrix<float>(elements, size).transpose();
+}
+
+void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
+{
+ // Transpose is used since the input Matrix is in row-major order,
+ // whereas the actual result should be in column-major order.
+ angle::Matrix<float> result = m.transpose();
+ std::vector<float> resultElements = result.elements();
+ for (size_t i = 0; i < resultElements.size(); i++)
+ resultArray[i].setFConst(resultElements[i]);
+}
+
+bool CanFoldAggregateBuiltInOp(TOperator op)
+{
+ switch (op)
+ {
+ case EOpAtan:
+ case EOpPow:
+ case EOpMod:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothstep:
+ case EOpLdexp:
+ case EOpMulMatrixComponentWise:
+ case EOpOuterProduct:
+ case EOpEqualComponentWise:
+ case EOpNotEqualComponentWise:
+ case EOpLessThanComponentWise:
+ case EOpLessThanEqualComponentWise:
+ case EOpGreaterThanComponentWise:
+ case EOpGreaterThanEqualComponentWise:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceforward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpBitfieldExtract:
+ case EOpBitfieldInsert:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t) {}
+
+void TIntermExpression::setTypePreservePrecision(const TType &t)
+{
+ TPrecision precision = getPrecision();
+ mType = t;
+ ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
+ mType.setPrecision(precision);
+}
+
+#define REPLACE_IF_IS(node, type, original, replacement) \
+ do \
+ { \
+ if (node == original) \
+ { \
+ node = static_cast<type *>(replacement); \
+ return true; \
+ } \
+ } while (0)
+
+size_t TIntermSymbol::getChildCount() const
+{
+ return 0;
+}
+
+TIntermNode *TIntermSymbol::getChildNode(size_t index) const
+{
+ UNREACHABLE();
+ return nullptr;
+}
+
+size_t TIntermConstantUnion::getChildCount() const
+{
+ return 0;
+}
+
+TIntermNode *TIntermConstantUnion::getChildNode(size_t index) const
+{
+ UNREACHABLE();
+ return nullptr;
+}
+
+size_t TIntermLoop::getChildCount() const
+{
+ return (mInit ? 1 : 0) + (mCond ? 1 : 0) + (mExpr ? 1 : 0) + (mBody ? 1 : 0);
+}
+
+TIntermNode *TIntermLoop::getChildNode(size_t index) const
+{
+ TIntermNode *children[4];
+ unsigned int childIndex = 0;
+ if (mInit)
+ {
+ children[childIndex] = mInit;
+ ++childIndex;
+ }
+ if (mCond)
+ {
+ children[childIndex] = mCond;
+ ++childIndex;
+ }
+ if (mExpr)
+ {
+ children[childIndex] = mExpr;
+ ++childIndex;
+ }
+ if (mBody)
+ {
+ children[childIndex] = mBody;
+ ++childIndex;
+ }
+ ASSERT(index < childIndex);
+ return children[index];
+}
+
+bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ ASSERT(original != nullptr); // This risks replacing multiple children.
+ REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
+ REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
+ return false;
+}
+
+size_t TIntermBranch::getChildCount() const
+{
+ return (mExpression ? 1 : 0);
+}
+
+TIntermNode *TIntermBranch::getChildNode(size_t index) const
+{
+ ASSERT(mExpression);
+ ASSERT(index == 0);
+ return mExpression;
+}
+
+bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
+ return false;
+}
+
+size_t TIntermSwizzle::getChildCount() const
+{
+ return 1;
+}
+
+TIntermNode *TIntermSwizzle::getChildNode(size_t index) const
+{
+ ASSERT(mOperand);
+ ASSERT(index == 0);
+ return mOperand;
+}
+
+bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
+ REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
+ return false;
+}
+
+size_t TIntermBinary::getChildCount() const
+{
+ return 2;
+}
+
+TIntermNode *TIntermBinary::getChildNode(size_t index) const
+{
+ ASSERT(index < 2);
+ if (index == 0)
+ {
+ return mLeft;
+ }
+ return mRight;
+}
+
+bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
+ return false;
+}
+
+size_t TIntermUnary::getChildCount() const
+{
+ return 1;
+}
+
+TIntermNode *TIntermUnary::getChildNode(size_t index) const
+{
+ ASSERT(mOperand);
+ ASSERT(index == 0);
+ return mOperand;
+}
+
+bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
+ REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
+ return false;
+}
+
+size_t TIntermInvariantDeclaration::getChildCount() const
+{
+ return 1;
+}
+
+TIntermNode *TIntermInvariantDeclaration::getChildNode(size_t index) const
+{
+ ASSERT(mSymbol);
+ ASSERT(index == 0);
+ return mSymbol;
+}
+
+bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
+ return false;
+}
+
+size_t TIntermFunctionDefinition::getChildCount() const
+{
+ return 2;
+}
+
+TIntermNode *TIntermFunctionDefinition::getChildNode(size_t index) const
+{
+ ASSERT(index < 2);
+ if (index == 0)
+ {
+ return mPrototype;
+ }
+ return mBody;
+}
+
+bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
+ REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
+ return false;
+}
+
+size_t TIntermAggregate::getChildCount() const
+{
+ return mArguments.size();
+}
+
+TIntermNode *TIntermAggregate::getChildNode(size_t index) const
+{
+ return mArguments[index];
+}
+
+bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ return replaceChildNodeInternal(original, replacement);
+}
+
+size_t TIntermBlock::getChildCount() const
+{
+ return mStatements.size();
+}
+
+TIntermNode *TIntermBlock::getChildNode(size_t index) const
+{
+ return mStatements[index];
+}
+
+bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ return replaceChildNodeInternal(original, replacement);
+}
+
+size_t TIntermFunctionPrototype::getChildCount() const
+{
+ return 0;
+}
+
+TIntermNode *TIntermFunctionPrototype::getChildNode(size_t index) const
+{
+ UNREACHABLE();
+ return nullptr;
+}
+
+bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ return false;
+}
+
+size_t TIntermDeclaration::getChildCount() const
+{
+ return mDeclarators.size();
+}
+
+TIntermNode *TIntermDeclaration::getChildNode(size_t index) const
+{
+ return mDeclarators[index];
+}
+
+bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ return replaceChildNodeInternal(original, replacement);
+}
+
+bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
+{
+ for (size_t ii = 0; ii < getSequence()->size(); ++ii)
+ {
+ REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
+ }
+ return false;
+}
+
+bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
+ const TIntermSequence &replacements)
+{
+ for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
+ {
+ if (*it == original)
+ {
+ it = getSequence()->erase(it);
+ getSequence()->insert(it, replacements.begin(), replacements.end());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
+ const TIntermSequence &insertions)
+{
+ if (position > getSequence()->size())
+ {
+ return false;
+ }
+ auto it = getSequence()->begin() + position;
+ getSequence()->insert(it, insertions.begin(), insertions.end());
+ return true;
+}
+
+TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable) {}
+
+bool TIntermSymbol::hasConstantValue() const
+{
+ return variable().getConstPointer() != nullptr;
+}
+
+const TConstantUnion *TIntermSymbol::getConstantValue() const
+{
+ return variable().getConstPointer();
+}
+
+const TSymbolUniqueId &TIntermSymbol::uniqueId() const
+{
+ return mVariable->uniqueId();
+}
+
+ImmutableString TIntermSymbol::getName() const
+{
+ return mVariable->name();
+}
+
+const TType &TIntermSymbol::getType() const
+{
+ return mVariable->getType();
+}
+
+TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
+ TIntermSequence *arguments)
+{
+ return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
+}
+
+TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
+ TIntermSequence *arguments)
+{
+ return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
+}
+
+TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
+ TIntermSequence *arguments)
+{
+ // op should be either EOpCallBuiltInFunction or a specific math op.
+ ASSERT(func.getBuiltInOp() != EOpNull);
+ return new TIntermAggregate(&func, func.getReturnType(), func.getBuiltInOp(), arguments);
+}
+
+TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type, TIntermSequence *arguments)
+{
+ return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
+}
+
+TIntermAggregate::TIntermAggregate(const TFunction *func,
+ const TType &type,
+ TOperator op,
+ TIntermSequence *arguments)
+ : TIntermOperator(op, type),
+ mUseEmulatedFunction(false),
+ mGotPrecisionFromChildren(false),
+ mFunction(func)
+{
+ if (arguments != nullptr)
+ {
+ mArguments.swap(*arguments);
+ }
+ ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
+ setPrecisionAndQualifier();
+}
+
+void TIntermAggregate::setPrecisionAndQualifier()
+{
+ mType.setQualifier(EvqTemporary);
+ if (mOp == EOpCallBuiltInFunction)
+ {
+ setBuiltInFunctionPrecision();
+ }
+ else if (!isFunctionCall())
+ {
+ if (isConstructor())
+ {
+ // Structs should not be precision qualified, the individual members may be.
+ // Built-in types on the other hand should be precision qualified.
+ if (getBasicType() != EbtStruct)
+ {
+ setPrecisionFromChildren();
+ }
+ }
+ else
+ {
+ setPrecisionForBuiltInOp();
+ }
+ if (areChildrenConstQualified())
+ {
+ mType.setQualifier(EvqConst);
+ }
+ }
+}
+
+bool TIntermAggregate::areChildrenConstQualified()
+{
+ for (TIntermNode *&arg : mArguments)
+ {
+ TIntermTyped *typedArg = arg->getAsTyped();
+ if (typedArg && typedArg->getQualifier() != EvqConst)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void TIntermAggregate::setPrecisionFromChildren()
+{
+ mGotPrecisionFromChildren = true;
+ if (getBasicType() == EbtBool)
+ {
+ mType.setPrecision(EbpUndefined);
+ return;
+ }
+
+ TPrecision precision = EbpUndefined;
+ TIntermSequence::iterator childIter = mArguments.begin();
+ while (childIter != mArguments.end())
+ {
+ TIntermTyped *typed = (*childIter)->getAsTyped();
+ if (typed)
+ precision = GetHigherPrecision(typed->getPrecision(), precision);
+ ++childIter;
+ }
+ mType.setPrecision(precision);
+}
+
+void TIntermAggregate::setPrecisionForBuiltInOp()
+{
+ ASSERT(!isConstructor());
+ ASSERT(!isFunctionCall());
+ if (!setPrecisionForSpecialBuiltInOp())
+ {
+ setPrecisionFromChildren();
+ }
+}
+
+bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
+{
+ switch (mOp)
+ {
+ case EOpBitfieldExtract:
+ mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
+ mGotPrecisionFromChildren = true;
+ return true;
+ case EOpBitfieldInsert:
+ mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
+ mArguments[1]->getAsTyped()->getPrecision()));
+ mGotPrecisionFromChildren = true;
+ return true;
+ case EOpUaddCarry:
+ case EOpUsubBorrow:
+ mType.setPrecision(EbpHigh);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void TIntermAggregate::setBuiltInFunctionPrecision()
+{
+ // All built-ins returning bool should be handled as ops, not functions.
+ ASSERT(getBasicType() != EbtBool);
+ ASSERT(mOp == EOpCallBuiltInFunction);
+
+ TPrecision precision = EbpUndefined;
+ for (TIntermNode *arg : mArguments)
+ {
+ TIntermTyped *typed = arg->getAsTyped();
+ // ESSL spec section 8: texture functions get their precision from the sampler.
+ if (typed && IsSampler(typed->getBasicType()))
+ {
+ precision = typed->getPrecision();
+ break;
+ }
+ }
+ // ESSL 3.0 spec section 8: textureSize always gets highp precision.
+ // All other functions that take a sampler are assumed to be texture functions.
+ if (mFunction->name() == "textureSize")
+ mType.setPrecision(EbpHigh);
+ else
+ mType.setPrecision(precision);
+}
+
+const char *TIntermAggregate::functionName() const
+{
+ ASSERT(!isConstructor());
+ switch (mOp)
+ {
+ case EOpCallInternalRawFunction:
+ case EOpCallBuiltInFunction:
+ case EOpCallFunctionInAST:
+ return mFunction->name().data();
+ default:
+ return GetOperatorString(mOp);
+ }
+}
+
+bool TIntermAggregate::hasConstantValue() const
+{
+ if (!isConstructor())
+ {
+ return false;
+ }
+ for (TIntermNode *constructorArg : mArguments)
+ {
+ if (!constructorArg->getAsTyped()->hasConstantValue())
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+const TConstantUnion *TIntermAggregate::getConstantValue() const
+{
+ if (!hasConstantValue())
+ {
+ return nullptr;
+ }
+ ASSERT(isConstructor());
+ ASSERT(mArguments.size() > 0u);
+
+ TConstantUnion *constArray = nullptr;
+ if (isArray())
+ {
+ size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
+ constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
+
+ size_t elementOffset = 0u;
+ for (TIntermNode *constructorArg : mArguments)
+ {
+ const TConstantUnion *elementConstArray =
+ constructorArg->getAsTyped()->getConstantValue();
+ ASSERT(elementConstArray);
+ size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
+ memcpy(static_cast<void *>(&constArray[elementOffset]),
+ static_cast<const void *>(elementConstArray), elementSizeBytes);
+ elementOffset += elementSize;
+ }
+ return constArray;
+ }
+
+ size_t resultSize = getType().getObjectSize();
+ constArray = new TConstantUnion[resultSize];
+ TBasicType basicType = getBasicType();
+
+ size_t resultIndex = 0u;
+
+ if (mArguments.size() == 1u)
+ {
+ TIntermNode *argument = mArguments.front();
+ TIntermTyped *argumentTyped = argument->getAsTyped();
+ const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
+ // Check the special case of constructing a matrix diagonal from a single scalar,
+ // or a vector from a single scalar.
+ if (argumentTyped->getType().getObjectSize() == 1u)
+ {
+ if (isMatrix())
+ {
+ int resultCols = getType().getCols();
+ int resultRows = getType().getRows();
+ for (int col = 0; col < resultCols; ++col)
+ {
+ for (int row = 0; row < resultRows; ++row)
+ {
+ if (col == row)
+ {
+ constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
+ }
+ else
+ {
+ constArray[resultIndex].setFConst(0.0f);
+ }
+ ++resultIndex;
+ }
+ }
+ }
+ else
+ {
+ while (resultIndex < resultSize)
+ {
+ constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return constArray;
+ }
+ else if (isMatrix() && argumentTyped->isMatrix())
+ {
+ // The special case of constructing a matrix from a matrix.
+ int argumentCols = argumentTyped->getType().getCols();
+ int argumentRows = argumentTyped->getType().getRows();
+ int resultCols = getType().getCols();
+ int resultRows = getType().getRows();
+ for (int col = 0; col < resultCols; ++col)
+ {
+ for (int row = 0; row < resultRows; ++row)
+ {
+ if (col < argumentCols && row < argumentRows)
+ {
+ constArray[resultIndex].cast(
+ basicType, argumentConstantValue[col * argumentRows + row]);
+ }
+ else if (col == row)
+ {
+ constArray[resultIndex].setFConst(1.0f);
+ }
+ else
+ {
+ constArray[resultIndex].setFConst(0.0f);
+ }
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return constArray;
+ }
+ }
+
+ for (TIntermNode *argument : mArguments)
+ {
+ TIntermTyped *argumentTyped = argument->getAsTyped();
+ size_t argumentSize = argumentTyped->getType().getObjectSize();
+ const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
+ for (size_t i = 0u; i < argumentSize; ++i)
+ {
+ if (resultIndex >= resultSize)
+ break;
+ constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return constArray;
+}
+
+bool TIntermAggregate::hasSideEffects() const
+{
+ if (getQualifier() == EvqConst)
+ {
+ return false;
+ }
+ bool calledFunctionHasNoSideEffects =
+ isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
+ if (calledFunctionHasNoSideEffects || isConstructor())
+ {
+ for (TIntermNode *arg : mArguments)
+ {
+ if (arg->getAsTyped()->hasSideEffects())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ // Conservatively assume most aggregate operators have side-effects
+ return true;
+}
+
+void TIntermBlock::appendStatement(TIntermNode *statement)
+{
+ // Declaration nodes with no children can appear if it was an empty declaration or if all the
+ // declarators just added constants to the symbol table instead of generating code. We still
+ // need to add the declaration to the AST in that case because it might be relevant to the
+ // validity of switch/case.
+ if (statement != nullptr)
+ {
+ mStatements.push_back(statement);
+ }
+}
+
+void TIntermBlock::insertStatement(size_t insertPosition, TIntermNode *statement)
+{
+ ASSERT(statement != nullptr);
+ mStatements.insert(mStatements.begin() + insertPosition, statement);
+}
+
+void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
+{
+ ASSERT(declarator != nullptr);
+ ASSERT(declarator->getAsSymbolNode() != nullptr ||
+ (declarator->getAsBinaryNode() != nullptr &&
+ declarator->getAsBinaryNode()->getOp() == EOpInitialize));
+ ASSERT(mDeclarators.empty() ||
+ declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
+ mDeclarators.push_back(declarator);
+}
+
+size_t TIntermTernary::getChildCount() const
+{
+ return 3;
+}
+
+TIntermNode *TIntermTernary::getChildNode(size_t index) const
+{
+ ASSERT(index < 3);
+ if (index == 0)
+ {
+ return mCondition;
+ }
+ if (index == 1)
+ {
+ return mTrueExpression;
+ }
+ return mFalseExpression;
+}
+
+bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
+ return false;
+}
+
+size_t TIntermIfElse::getChildCount() const
+{
+ return 1 + (mTrueBlock ? 1 : 0) + (mFalseBlock ? 1 : 0);
+}
+
+TIntermNode *TIntermIfElse::getChildNode(size_t index) const
+{
+ if (index == 0)
+ {
+ return mCondition;
+ }
+ if (mTrueBlock && index == 1)
+ {
+ return mTrueBlock;
+ }
+ return mFalseBlock;
+}
+
+bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
+ REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
+ return false;
+}
+
+size_t TIntermSwitch::getChildCount() const
+{
+ return 2;
+}
+
+TIntermNode *TIntermSwitch::getChildNode(size_t index) const
+{
+ ASSERT(index < 2);
+ if (index == 0)
+ {
+ return mInit;
+ }
+ return mStatementList;
+}
+
+bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
+ ASSERT(mStatementList);
+ return false;
+}
+
+size_t TIntermCase::getChildCount() const
+{
+ return (mCondition ? 1 : 0);
+}
+
+TIntermNode *TIntermCase::getChildNode(size_t index) const
+{
+ ASSERT(index == 0);
+ ASSERT(mCondition);
+ return mCondition;
+}
+
+bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
+ return false;
+}
+
+TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
+{
+ // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
+ // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
+ // We need to manually copy any fields of TIntermNode.
+ mLine = node.mLine;
+}
+
+bool TIntermTyped::hasConstantValue() const
+{
+ return false;
+}
+
+const TConstantUnion *TIntermTyped::getConstantValue() const
+{
+ return nullptr;
+}
+
+TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
+ : TIntermExpression(node)
+{
+ mUnionArrayPointer = node.mUnionArrayPointer;
+}
+
+TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
+ : TIntermTyped(), mFunction(function)
+{
+ ASSERT(mFunction->symbolType() != SymbolType::Empty);
+}
+
+const TType &TIntermFunctionPrototype::getType() const
+{
+ return mFunction->getReturnType();
+}
+
+TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
+ : TIntermOperator(node),
+ mUseEmulatedFunction(node.mUseEmulatedFunction),
+ mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
+ mFunction(node.mFunction)
+{
+ for (TIntermNode *arg : node.mArguments)
+ {
+ TIntermTyped *typedArg = arg->getAsTyped();
+ ASSERT(typedArg != nullptr);
+ TIntermTyped *argCopy = typedArg->deepCopy();
+ mArguments.push_back(argCopy);
+ }
+}
+
+TIntermAggregate *TIntermAggregate::shallowCopy() const
+{
+ TIntermSequence *copySeq = new TIntermSequence();
+ copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
+ TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
+ copyNode->setLine(mLine);
+ return copyNode;
+}
+
+TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
+{
+ TIntermTyped *operandCopy = node.mOperand->deepCopy();
+ ASSERT(operandCopy != nullptr);
+ mOperand = operandCopy;
+ mSwizzleOffsets = node.mSwizzleOffsets;
+ mHasFoldedDuplicateOffsets = node.mHasFoldedDuplicateOffsets;
+}
+
+TIntermBinary::TIntermBinary(const TIntermBinary &node)
+ : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
+{
+ TIntermTyped *leftCopy = node.mLeft->deepCopy();
+ TIntermTyped *rightCopy = node.mRight->deepCopy();
+ ASSERT(leftCopy != nullptr && rightCopy != nullptr);
+ mLeft = leftCopy;
+ mRight = rightCopy;
+}
+
+TIntermUnary::TIntermUnary(const TIntermUnary &node)
+ : TIntermOperator(node),
+ mUseEmulatedFunction(node.mUseEmulatedFunction),
+ mFunction(node.mFunction)
+{
+ TIntermTyped *operandCopy = node.mOperand->deepCopy();
+ ASSERT(operandCopy != nullptr);
+ mOperand = operandCopy;
+}
+
+TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
+{
+ TIntermTyped *conditionCopy = node.mCondition->deepCopy();
+ TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
+ TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
+ ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
+ mCondition = conditionCopy;
+ mTrueExpression = trueCopy;
+ mFalseExpression = falseCopy;
+}
+
+bool TIntermOperator::isAssignment() const
+{
+ return IsAssignment(mOp);
+}
+
+bool TIntermOperator::isMultiplication() const
+{
+ switch (mOp)
+ {
+ case EOpMul:
+ case EOpMatrixTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpVectorTimesScalar:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool TIntermOperator::isConstructor() const
+{
+ return (mOp == EOpConstruct);
+}
+
+bool TIntermOperator::isFunctionCall() const
+{
+ switch (mOp)
+ {
+ case EOpCallFunctionInAST:
+ case EOpCallBuiltInFunction:
+ case EOpCallInternalRawFunction:
+ return true;
+ default:
+ return false;
+ }
+}
+
+TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
+{
+ if (left.isMatrix())
+ {
+ if (right.isMatrix())
+ {
+ return EOpMatrixTimesMatrix;
+ }
+ else
+ {
+ if (right.isVector())
+ {
+ return EOpMatrixTimesVector;
+ }
+ else
+ {
+ return EOpMatrixTimesScalar;
+ }
+ }
+ }
+ else
+ {
+ if (right.isMatrix())
+ {
+ if (left.isVector())
+ {
+ return EOpVectorTimesMatrix;
+ }
+ else
+ {
+ return EOpMatrixTimesScalar;
+ }
+ }
+ else
+ {
+ // Neither operand is a matrix.
+ if (left.isVector() == right.isVector())
+ {
+ // Leave as component product.
+ return EOpMul;
+ }
+ else
+ {
+ return EOpVectorTimesScalar;
+ }
+ }
+ }
+}
+
+TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
+{
+ if (left.isMatrix())
+ {
+ if (right.isMatrix())
+ {
+ return EOpMatrixTimesMatrixAssign;
+ }
+ else
+ {
+ // right should be scalar, but this may not be validated yet.
+ return EOpMatrixTimesScalarAssign;
+ }
+ }
+ else
+ {
+ if (right.isMatrix())
+ {
+ // Left should be a vector, but this may not be validated yet.
+ return EOpVectorTimesMatrixAssign;
+ }
+ else
+ {
+ // Neither operand is a matrix.
+ if (left.isVector() == right.isVector())
+ {
+ // Leave as component product.
+ return EOpMulAssign;
+ }
+ else
+ {
+ // left should be vector and right should be scalar, but this may not be validated
+ // yet.
+ return EOpVectorTimesScalarAssign;
+ }
+ }
+ }
+}
+
+//
+// Make sure the type of a unary operator is appropriate for its
+// combination of operation and operand type.
+//
+void TIntermUnary::promote()
+{
+ if (mOp == EOpArrayLength)
+ {
+ // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
+ setType(TType(EbtInt, EbpUndefined, EvqConst));
+ return;
+ }
+
+ TQualifier resultQualifier = EvqTemporary;
+ if (mOperand->getQualifier() == EvqConst)
+ resultQualifier = EvqConst;
+
+ unsigned char operandPrimarySize =
+ static_cast<unsigned char>(mOperand->getType().getNominalSize());
+ switch (mOp)
+ {
+ case EOpFloatBitsToInt:
+ setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpFloatBitsToUint:
+ setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpPackUnorm4x8:
+ case EOpPackSnorm4x8:
+ setType(TType(EbtUInt, EbpHigh, resultQualifier));
+ break;
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
+ break;
+ case EOpUnpackHalf2x16:
+ setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
+ break;
+ case EOpUnpackUnorm4x8:
+ case EOpUnpackSnorm4x8:
+ setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
+ break;
+ case EOpAny:
+ case EOpAll:
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
+ break;
+ case EOpLength:
+ case EOpDeterminant:
+ setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
+ break;
+ case EOpTranspose:
+ setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
+ static_cast<unsigned char>(mOperand->getType().getRows()),
+ static_cast<unsigned char>(mOperand->getType().getCols())));
+ break;
+ case EOpIsinf:
+ case EOpIsnan:
+ setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
+ break;
+ case EOpBitfieldReverse:
+ setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpBitCount:
+ setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
+ break;
+ case EOpFindLSB:
+ setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
+ break;
+ case EOpFindMSB:
+ setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
+ break;
+ default:
+ setType(mOperand->getType());
+ mType.setQualifier(resultQualifier);
+ break;
+ }
+}
+
+TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
+ : TIntermExpression(TType(EbtFloat, EbpUndefined)),
+ mOperand(operand),
+ mSwizzleOffsets(swizzleOffsets),
+ mHasFoldedDuplicateOffsets(false)
+{
+ ASSERT(mOperand);
+ ASSERT(mSwizzleOffsets.size() <= 4);
+ promote();
+}
+
+TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function)
+ : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function)
+{
+ ASSERT(mOperand);
+ promote();
+}
+
+TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
+ : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
+{
+ ASSERT(mLeft);
+ ASSERT(mRight);
+ promote();
+}
+
+TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
+ TIntermTyped *right,
+ int shaderVersion)
+{
+ TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
+ node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
+ return node;
+}
+
+TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol,
+ const TSourceLoc &line)
+ : TIntermNode(), mSymbol(symbol)
+{
+ ASSERT(symbol);
+ setLine(line);
+}
+
+TIntermTernary::TIntermTernary(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression)
+ : TIntermExpression(trueExpression->getType()),
+ mCondition(cond),
+ mTrueExpression(trueExpression),
+ mFalseExpression(falseExpression)
+{
+ ASSERT(mCondition);
+ ASSERT(mTrueExpression);
+ ASSERT(mFalseExpression);
+ getTypePointer()->setQualifier(
+ TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
+}
+
+TIntermLoop::TIntermLoop(TLoopType type,
+ TIntermNode *init,
+ TIntermTyped *cond,
+ TIntermTyped *expr,
+ TIntermBlock *body)
+ : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
+{
+ // Declaration nodes with no children can appear if all the declarators just added constants to
+ // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
+ if (mInit && mInit->getAsDeclarationNode() &&
+ mInit->getAsDeclarationNode()->getSequence()->empty())
+ {
+ mInit = nullptr;
+ }
+}
+
+TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
+ : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
+{
+ ASSERT(mCondition);
+ // Prune empty false blocks so that there won't be unnecessary operations done on it.
+ if (mFalseBlock && mFalseBlock->getSequence()->empty())
+ {
+ mFalseBlock = nullptr;
+ }
+}
+
+TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
+ : TIntermNode(), mInit(init), mStatementList(statementList)
+{
+ ASSERT(mInit);
+ ASSERT(mStatementList);
+}
+
+void TIntermSwitch::setStatementList(TIntermBlock *statementList)
+{
+ ASSERT(statementList);
+ mStatementList = statementList;
+}
+
+// static
+TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression)
+{
+ if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
+ falseExpression->getQualifier() == EvqConst)
+ {
+ return EvqConst;
+ }
+ return EvqTemporary;
+}
+
+TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
+{
+ if (mCondition->getAsConstantUnion())
+ {
+ if (mCondition->getAsConstantUnion()->getBConst(0))
+ {
+ return mTrueExpression;
+ }
+ else
+ {
+ return mFalseExpression;
+ }
+ }
+ return this;
+}
+
+void TIntermSwizzle::promote()
+{
+ TQualifier resultQualifier = EvqTemporary;
+ if (mOperand->getQualifier() == EvqConst)
+ resultQualifier = EvqConst;
+
+ auto numFields = mSwizzleOffsets.size();
+ setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
+ static_cast<unsigned char>(numFields)));
+}
+
+bool TIntermSwizzle::hasDuplicateOffsets() const
+{
+ if (mHasFoldedDuplicateOffsets)
+ {
+ return true;
+ }
+ int offsetCount[4] = {0u, 0u, 0u, 0u};
+ for (const auto offset : mSwizzleOffsets)
+ {
+ offsetCount[offset]++;
+ if (offsetCount[offset] > 1)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
+{
+ mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
+}
+
+bool TIntermSwizzle::offsetsMatch(int offset) const
+{
+ return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
+}
+
+void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
+{
+ for (const int offset : mSwizzleOffsets)
+ {
+ switch (offset)
+ {
+ case 0:
+ *out << "x";
+ break;
+ case 1:
+ *out << "y";
+ break;
+ case 2:
+ *out << "z";
+ break;
+ case 3:
+ *out << "w";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+}
+
+TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
+ const TIntermTyped *left,
+ const TIntermTyped *right)
+{
+ // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
+ if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
+ right->getQualifier() != EvqConst)
+ {
+ return EvqTemporary;
+ }
+ return EvqConst;
+}
+
+// Establishes the type of the result of the binary operation.
+void TIntermBinary::promote()
+{
+ ASSERT(!isMultiplication() ||
+ mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
+
+ // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
+ // version and so is not being set here.
+ if (mOp == EOpComma)
+ {
+ setType(mRight->getType());
+ return;
+ }
+
+ // Base assumption: just make the type the same as the left
+ // operand. Then only deviations from this need be coded.
+ setType(mLeft->getType());
+
+ TQualifier resultQualifier = EvqConst;
+ // Binary operations results in temporary variables unless both
+ // operands are const.
+ if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
+ {
+ resultQualifier = EvqTemporary;
+ getTypePointer()->setQualifier(EvqTemporary);
+ }
+
+ // Handle indexing ops.
+ switch (mOp)
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ if (mLeft->isArray())
+ {
+ mType.toArrayElementType();
+ }
+ else if (mLeft->isMatrix())
+ {
+ setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
+ static_cast<unsigned char>(mLeft->getRows())));
+ }
+ else if (mLeft->isVector())
+ {
+ setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ return;
+ case EOpIndexDirectStruct:
+ {
+ const TFieldList &fields = mLeft->getType().getStruct()->fields();
+ const int i = mRight->getAsConstantUnion()->getIConst(0);
+ setType(*fields[i]->type());
+ getTypePointer()->setQualifier(resultQualifier);
+ return;
+ }
+ case EOpIndexDirectInterfaceBlock:
+ {
+ const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
+ const int i = mRight->getAsConstantUnion()->getIConst(0);
+ setType(*fields[i]->type());
+ getTypePointer()->setQualifier(resultQualifier);
+ return;
+ }
+ default:
+ break;
+ }
+
+ ASSERT(mLeft->isArray() == mRight->isArray());
+
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
+ getTypePointer()->setPrecision(higherPrecision);
+
+ const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
+
+ //
+ // All scalars or structs. Code after this test assumes this case is removed!
+ //
+ if (nominalSize == 1)
+ {
+ switch (mOp)
+ {
+ //
+ // Promote to conditional
+ //
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
+ break;
+
+ //
+ // And and Or operate on conditionals
+ //
+ case EOpLogicalAnd:
+ case EOpLogicalXor:
+ case EOpLogicalOr:
+ ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
+ break;
+
+ default:
+ break;
+ }
+ return;
+ }
+
+ // If we reach here, at least one of the operands is vector or matrix.
+ // The other operand could be a scalar, vector, or matrix.
+ TBasicType basicType = mLeft->getBasicType();
+
+ switch (mOp)
+ {
+ case EOpMul:
+ break;
+ case EOpMatrixTimesScalar:
+ if (mRight->isMatrix())
+ {
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()),
+ static_cast<unsigned char>(mRight->getRows())));
+ }
+ break;
+ case EOpMatrixTimesVector:
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mLeft->getRows()), 1));
+ break;
+ case EOpMatrixTimesMatrix:
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()),
+ static_cast<unsigned char>(mLeft->getRows())));
+ break;
+ case EOpVectorTimesScalar:
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(nominalSize), 1));
+ break;
+ case EOpVectorTimesMatrix:
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()), 1));
+ break;
+ case EOpMulAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
+ break;
+ case EOpAssign:
+ case EOpInitialize:
+ ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
+ (mLeft->getSecondarySize() == mRight->getSecondarySize()));
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpIMod:
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ {
+ const int secondarySize =
+ std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(nominalSize),
+ static_cast<unsigned char>(secondarySize)));
+ ASSERT(!mLeft->isArray() && !mRight->isArray());
+ break;
+ }
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
+ (mLeft->getSecondarySize() == mRight->getSecondarySize()));
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
+ break;
+
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexDirectStruct:
+ // These ops should be already fully handled.
+ UNREACHABLE();
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+bool TIntermConstantUnion::hasConstantValue() const
+{
+ return true;
+}
+
+const TConstantUnion *TIntermConstantUnion::getConstantValue() const
+{
+ return mUnionArrayPointer;
+}
+
+const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
+ const TConstantUnion *constArray,
+ int index)
+{
+ if (type.isArray())
+ {
+ ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
+ TType arrayElementType(type);
+ arrayElementType.toArrayElementType();
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ return &constArray[arrayElementSize * index];
+ }
+ else if (type.isMatrix())
+ {
+ ASSERT(index < type.getCols());
+ int size = type.getRows();
+ return &constArray[size * index];
+ }
+ else if (type.isVector())
+ {
+ ASSERT(index < type.getNominalSize());
+ return &constArray[index];
+ }
+ else
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+}
+
+TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
+{
+ TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
+ if (operandSwizzle)
+ {
+ // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
+ // overflow in ParseContext::checkCanBeLValue().
+ bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
+ TVector<int> foldedOffsets;
+ for (int offset : mSwizzleOffsets)
+ {
+ // Offset should already be validated.
+ ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
+ foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
+ }
+ operandSwizzle->mSwizzleOffsets = foldedOffsets;
+ operandSwizzle->setType(getType());
+ operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
+ return operandSwizzle;
+ }
+ TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
+ if (operandConstant == nullptr)
+ {
+ return this;
+ }
+
+ TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
+ for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
+ {
+ constArray[i] = *TIntermConstantUnion::FoldIndexing(
+ operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
+ }
+ return CreateFoldedNode(constArray, this);
+}
+
+TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
+{
+ const TConstantUnion *rightConstant = mRight->getConstantValue();
+ switch (mOp)
+ {
+ case EOpComma:
+ {
+ if (mLeft->hasSideEffects())
+ {
+ return this;
+ }
+ return mRight;
+ }
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ {
+ if (rightConstant == nullptr)
+ {
+ return this;
+ }
+ size_t index = static_cast<size_t>(rightConstant->getIConst());
+ TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
+ if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
+ !leftAggregate->hasSideEffects())
+ {
+ ASSERT(index < leftAggregate->getSequence()->size());
+ // This transformation can't add complexity as we're eliminating the constructor
+ // entirely.
+ return leftAggregate->getSequence()->at(index)->getAsTyped();
+ }
+
+ // If the indexed value is already a constant union, we can't increase duplication of
+ // data by folding the indexing. Also fold the node in case it's generally beneficial to
+ // replace this type of node with a constant union even if that would mean duplicating
+ // data.
+ if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
+ {
+ const TConstantUnion *constantValue = getConstantValue();
+ if (constantValue == nullptr)
+ {
+ return this;
+ }
+ return CreateFoldedNode(constantValue, this);
+ }
+ return this;
+ }
+ case EOpIndexIndirect:
+ case EOpIndexDirectInterfaceBlock:
+ case EOpInitialize:
+ // Can never be constant folded.
+ return this;
+ default:
+ {
+ if (rightConstant == nullptr)
+ {
+ return this;
+ }
+ const TConstantUnion *leftConstant = mLeft->getConstantValue();
+ if (leftConstant == nullptr)
+ {
+ return this;
+ }
+ const TConstantUnion *constArray =
+ TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
+ mRight->getType(), diagnostics, mLeft->getLine());
+ if (!constArray)
+ {
+ return this;
+ }
+ return CreateFoldedNode(constArray, this);
+ }
+ }
+}
+
+bool TIntermBinary::hasConstantValue() const
+{
+ switch (mOp)
+ {
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ {
+ if (mLeft->hasConstantValue() && mRight->hasConstantValue())
+ {
+ return true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+const TConstantUnion *TIntermBinary::getConstantValue() const
+{
+ if (!hasConstantValue())
+ {
+ return nullptr;
+ }
+
+ const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
+ int index = mRight->getConstantValue()->getIConst();
+ const TConstantUnion *constIndexingResult = nullptr;
+ if (mOp == EOpIndexDirect)
+ {
+ constIndexingResult =
+ TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
+ }
+ else
+ {
+ ASSERT(mOp == EOpIndexDirectStruct);
+ const TFieldList &fields = mLeft->getType().getStruct()->fields();
+
+ size_t previousFieldsSize = 0;
+ for (int i = 0; i < index; ++i)
+ {
+ previousFieldsSize += fields[i]->type()->getObjectSize();
+ }
+ constIndexingResult = leftConstantValue + previousFieldsSize;
+ }
+ return constIndexingResult;
+}
+
+const ImmutableString &TIntermBinary::getIndexStructFieldName() const
+{
+ ASSERT(mOp == EOpIndexDirectStruct);
+
+ const TType &lhsType = mLeft->getType();
+ const TStructure *structure = lhsType.getStruct();
+ const int index = mRight->getAsConstantUnion()->getIConst(0);
+
+ return structure->fields()[index]->name();
+}
+
+TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
+{
+ TConstantUnion *constArray = nullptr;
+
+ if (mOp == EOpArrayLength)
+ {
+ // The size of runtime-sized arrays may only be determined at runtime.
+ if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
+ {
+ return this;
+ }
+ constArray = new TConstantUnion[1];
+ constArray->setIConst(mOperand->getOutermostArraySize());
+ }
+ else
+ {
+ TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
+ if (operandConstant == nullptr)
+ {
+ return this;
+ }
+
+ switch (mOp)
+ {
+ case EOpAny:
+ case EOpAll:
+ case EOpLength:
+ case EOpTranspose:
+ case EOpDeterminant:
+ case EOpInverse:
+ case EOpPackSnorm2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackHalf2x16:
+ case EOpPackUnorm4x8:
+ case EOpPackSnorm4x8:
+ case EOpUnpackUnorm4x8:
+ case EOpUnpackSnorm4x8:
+ constArray = operandConstant->foldUnaryNonComponentWise(mOp);
+ break;
+ default:
+ constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
+ break;
+ }
+ }
+ if (constArray == nullptr)
+ {
+ return this;
+ }
+ return CreateFoldedNode(constArray, this);
+}
+
+TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
+{
+ // Make sure that all params are constant before actual constant folding.
+ for (auto *param : *getSequence())
+ {
+ if (param->getAsConstantUnion() == nullptr)
+ {
+ return this;
+ }
+ }
+ const TConstantUnion *constArray = nullptr;
+ if (isConstructor())
+ {
+ if (mType.canReplaceWithConstantUnion())
+ {
+ constArray = getConstantValue();
+ if (constArray && mType.getBasicType() == EbtUInt)
+ {
+ // Check if we converted a negative float to uint and issue a warning in that case.
+ size_t sizeRemaining = mType.getObjectSize();
+ for (TIntermNode *arg : mArguments)
+ {
+ TIntermTyped *typedArg = arg->getAsTyped();
+ if (typedArg->getBasicType() == EbtFloat)
+ {
+ const TConstantUnion *argValue = typedArg->getConstantValue();
+ size_t castSize =
+ std::min(typedArg->getType().getObjectSize(), sizeRemaining);
+ for (size_t i = 0; i < castSize; ++i)
+ {
+ if (argValue[i].getFConst() < 0.0f)
+ {
+ // ESSL 3.00.6 section 5.4.1.
+ diagnostics->warning(
+ mLine, "casting a negative float to uint is undefined",
+ mType.getBuiltInTypeNameString());
+ }
+ }
+ }
+ sizeRemaining -= typedArg->getType().getObjectSize();
+ }
+ }
+ }
+ }
+ else if (CanFoldAggregateBuiltInOp(mOp))
+ {
+ constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
+ }
+ if (constArray == nullptr)
+ {
+ return this;
+ }
+ return CreateFoldedNode(constArray, this);
+}
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the constant value to keep using or nullptr.
+//
+const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
+ const TConstantUnion *leftArray,
+ const TType &leftType,
+ const TConstantUnion *rightArray,
+ const TType &rightType,
+ TDiagnostics *diagnostics,
+ const TSourceLoc &line)
+{
+ ASSERT(leftArray && rightArray);
+
+ size_t objectSize = leftType.getObjectSize();
+
+ // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
+ if (rightType.getObjectSize() == 1 && objectSize > 1)
+ {
+ rightArray = Vectorize(*rightArray, objectSize);
+ }
+ else if (rightType.getObjectSize() > 1 && objectSize == 1)
+ {
+ // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
+ leftArray = Vectorize(*leftArray, rightType.getObjectSize());
+ objectSize = rightType.getObjectSize();
+ }
+
+ TConstantUnion *resultArray = nullptr;
+
+ switch (op)
+ {
+ case EOpAdd:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] =
+ TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
+ break;
+ case EOpSub:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] =
+ TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
+ break;
+
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] =
+ TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
+ break;
+
+ case EOpMatrixTimesMatrix:
+ {
+ // TODO(jmadll): This code should check for overflows.
+ ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
+
+ const int leftCols = leftType.getCols();
+ const int leftRows = leftType.getRows();
+ const int rightCols = rightType.getCols();
+ const int rightRows = rightType.getRows();
+ const int resultCols = rightCols;
+ const int resultRows = leftRows;
+
+ resultArray = new TConstantUnion[resultCols * resultRows];
+ for (int row = 0; row < resultRows; row++)
+ {
+ for (int column = 0; column < resultCols; column++)
+ {
+ resultArray[resultRows * column + row].setFConst(0.0f);
+ for (int i = 0; i < leftCols; i++)
+ {
+ resultArray[resultRows * column + row].setFConst(
+ resultArray[resultRows * column + row].getFConst() +
+ leftArray[i * leftRows + row].getFConst() *
+ rightArray[column * rightRows + i].getFConst());
+ }
+ }
+ }
+ }
+ break;
+
+ case EOpDiv:
+ case EOpIMod:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (IsFloatDivision(leftType.getBasicType(), rightType.getBasicType()))
+ {
+ // Float division requested, possibly with implicit conversion
+ ASSERT(op == EOpDiv);
+ float dividend = leftArray[i].getFConst();
+ float divisor = rightArray[i].getFConst();
+
+ if (divisor == 0.0f)
+ {
+ if (dividend == 0.0f)
+ {
+ diagnostics->warning(line,
+ "Zero divided by zero during constant "
+ "folding generated NaN",
+ "/");
+ resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
+ }
+ else
+ {
+ diagnostics->warning(line, "Divide by zero during constant folding",
+ "/");
+ bool negativeResult = std::signbit(dividend) != std::signbit(divisor);
+ resultArray[i].setFConst(negativeResult
+ ? -std::numeric_limits<float>::infinity()
+ : std::numeric_limits<float>::infinity());
+ }
+ }
+ else if (gl::isInf(dividend) && gl::isInf(divisor))
+ {
+ diagnostics->warning(line,
+ "Infinity divided by infinity during constant "
+ "folding generated NaN",
+ "/");
+ resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
+ }
+ else
+ {
+ float result = dividend / divisor;
+ if (!gl::isInf(dividend) && gl::isInf(result))
+ {
+ diagnostics->warning(
+ line, "Constant folded division overflowed to infinity", "/");
+ }
+ resultArray[i].setFConst(result);
+ }
+ }
+ else
+ {
+ // Types are either both int or both uint
+ switch (leftType.getBasicType())
+ {
+ case EbtInt:
+ {
+ if (rightArray[i] == 0)
+ {
+ diagnostics->warning(
+ line, "Divide by zero error during constant folding", "/");
+ resultArray[i].setIConst(INT_MAX);
+ }
+ else
+ {
+ int lhs = leftArray[i].getIConst();
+ int divisor = rightArray[i].getIConst();
+ if (op == EOpDiv)
+ {
+ // Check for the special case where the minimum
+ // representable number is divided by -1. If left alone this
+ // leads to integer overflow in C++. ESSL 3.00.6
+ // section 4.1.3 Integers: "However, for the case where the
+ // minimum representable value is divided by -1, it is
+ // allowed to return either the minimum representable value
+ // or the maximum representable value."
+ if (lhs == -0x7fffffff - 1 && divisor == -1)
+ {
+ resultArray[i].setIConst(0x7fffffff);
+ }
+ else
+ {
+ resultArray[i].setIConst(lhs / divisor);
+ }
+ }
+ else
+ {
+ ASSERT(op == EOpIMod);
+ if (lhs < 0 || divisor < 0)
+ {
+ // ESSL 3.00.6 section 5.9: Results of modulus are
+ // undefined when either one of the operands is
+ // negative.
+ diagnostics->warning(line,
+ "Negative modulus operator operand "
+ "encountered during constant folding. "
+ "Results are undefined.",
+ "%");
+ resultArray[i].setIConst(0);
+ }
+ else
+ {
+ resultArray[i].setIConst(lhs % divisor);
+ }
+ }
+ }
+ break;
+ }
+ case EbtUInt:
+ {
+ if (rightArray[i] == 0)
+ {
+ diagnostics->warning(
+ line, "Divide by zero error during constant folding", "/");
+ resultArray[i].setUConst(UINT_MAX);
+ }
+ else
+ {
+ if (op == EOpDiv)
+ {
+ resultArray[i].setUConst(leftArray[i].getUConst() /
+ rightArray[i].getUConst());
+ }
+ else
+ {
+ ASSERT(op == EOpIMod);
+ resultArray[i].setUConst(leftArray[i].getUConst() %
+ rightArray[i].getUConst());
+ }
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ }
+ }
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ {
+ // TODO(jmadll): This code should check for overflows.
+ ASSERT(rightType.getBasicType() == EbtFloat);
+
+ const int matrixCols = leftType.getCols();
+ const int matrixRows = leftType.getRows();
+
+ resultArray = new TConstantUnion[matrixRows];
+
+ for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
+ {
+ resultArray[matrixRow].setFConst(0.0f);
+ for (int col = 0; col < matrixCols; col++)
+ {
+ resultArray[matrixRow].setFConst(
+ resultArray[matrixRow].getFConst() +
+ leftArray[col * matrixRows + matrixRow].getFConst() *
+ rightArray[col].getFConst());
+ }
+ }
+ }
+ break;
+
+ case EOpVectorTimesMatrix:
+ {
+ // TODO(jmadll): This code should check for overflows.
+ ASSERT(leftType.getBasicType() == EbtFloat);
+
+ const int matrixCols = rightType.getCols();
+ const int matrixRows = rightType.getRows();
+
+ resultArray = new TConstantUnion[matrixCols];
+
+ for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
+ {
+ resultArray[matrixCol].setFConst(0.0f);
+ for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
+ {
+ resultArray[matrixCol].setFConst(
+ resultArray[matrixCol].getFConst() +
+ leftArray[matrixRow].getFConst() *
+ rightArray[matrixCol * matrixRows + matrixRow].getFConst());
+ }
+ }
+ }
+ break;
+
+ case EOpLogicalAnd:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ resultArray[i] = leftArray[i] && rightArray[i];
+ }
+ }
+ break;
+
+ case EOpLogicalOr:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ resultArray[i] = leftArray[i] || rightArray[i];
+ }
+ }
+ break;
+
+ case EOpLogicalXor:
+ {
+ ASSERT(leftType.getBasicType() == EbtBool);
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ resultArray[i].setBConst(leftArray[i] != rightArray[i]);
+ }
+ }
+ break;
+
+ case EOpBitwiseAnd:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] & rightArray[i];
+ break;
+ case EOpBitwiseXor:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] ^ rightArray[i];
+ break;
+ case EOpBitwiseOr:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] | rightArray[i];
+ break;
+ case EOpBitShiftLeft:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] =
+ TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
+ break;
+ case EOpBitShiftRight:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] =
+ TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
+ break;
+
+ case EOpLessThan:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(*leftArray < *rightArray);
+ break;
+
+ case EOpGreaterThan:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(*leftArray > *rightArray);
+ break;
+
+ case EOpLessThanEqual:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(!(*leftArray > *rightArray));
+ break;
+
+ case EOpGreaterThanEqual:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(!(*leftArray < *rightArray));
+ break;
+
+ case EOpEqual:
+ case EOpNotEqual:
+ {
+ resultArray = new TConstantUnion[1];
+ bool equal = true;
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (leftArray[i] != rightArray[i])
+ {
+ equal = false;
+ break; // break out of for loop
+ }
+ }
+ if (op == EOpEqual)
+ {
+ resultArray->setBConst(equal);
+ }
+ else
+ {
+ resultArray->setBConst(!equal);
+ }
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ return resultArray;
+}
+
+// The fold functions do operations on a constant at GLSL compile time, without generating run-time
+// code. Returns the constant value to keep using. Nullptr should not be returned.
+TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
+{
+ // Do operations where the return type may have a different number of components compared to the
+ // operand type.
+
+ const TConstantUnion *operandArray = getConstantValue();
+ ASSERT(operandArray);
+
+ size_t objectSize = getType().getObjectSize();
+ TConstantUnion *resultArray = nullptr;
+ switch (op)
+ {
+ case EOpAny:
+ ASSERT(getType().getBasicType() == EbtBool);
+ resultArray = new TConstantUnion();
+ resultArray->setBConst(false);
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (operandArray[i].getBConst())
+ {
+ resultArray->setBConst(true);
+ break;
+ }
+ }
+ break;
+
+ case EOpAll:
+ ASSERT(getType().getBasicType() == EbtBool);
+ resultArray = new TConstantUnion();
+ resultArray->setBConst(true);
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (!operandArray[i].getBConst())
+ {
+ resultArray->setBConst(false);
+ break;
+ }
+ }
+ break;
+
+ case EOpLength:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(VectorLength(operandArray, objectSize));
+ break;
+
+ case EOpTranspose:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray = new TConstantUnion[objectSize];
+ angle::Matrix<float> result =
+ GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+
+ case EOpDeterminant:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ unsigned int size = getType().getNominalSize();
+ ASSERT(size >= 2 && size <= 4);
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(GetMatrix(operandArray, size).determinant());
+ break;
+ }
+
+ case EOpInverse:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ unsigned int size = getType().getNominalSize();
+ ASSERT(size >= 2 && size <= 4);
+ resultArray = new TConstantUnion[objectSize];
+ angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+
+ case EOpPackSnorm2x16:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ ASSERT(getType().getNominalSize() == 2);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(
+ gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ break;
+
+ case EOpUnpackSnorm2x16:
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ resultArray = new TConstantUnion[2];
+ float f1, f2;
+ gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
+ resultArray[0].setFConst(f1);
+ resultArray[1].setFConst(f2);
+ break;
+ }
+
+ case EOpPackUnorm2x16:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ ASSERT(getType().getNominalSize() == 2);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(
+ gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ break;
+
+ case EOpUnpackUnorm2x16:
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ resultArray = new TConstantUnion[2];
+ float f1, f2;
+ gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
+ resultArray[0].setFConst(f1);
+ resultArray[1].setFConst(f2);
+ break;
+ }
+
+ case EOpPackHalf2x16:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ ASSERT(getType().getNominalSize() == 2);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(
+ gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ break;
+
+ case EOpUnpackHalf2x16:
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ resultArray = new TConstantUnion[2];
+ float f1, f2;
+ gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
+ resultArray[0].setFConst(f1);
+ resultArray[1].setFConst(f2);
+ break;
+ }
+
+ case EOpPackUnorm4x8:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(
+ gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
+ operandArray[2].getFConst(), operandArray[3].getFConst()));
+ break;
+ }
+ case EOpPackSnorm4x8:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(
+ gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
+ operandArray[2].getFConst(), operandArray[3].getFConst()));
+ break;
+ }
+ case EOpUnpackUnorm4x8:
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ resultArray = new TConstantUnion[4];
+ float f[4];
+ gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
+ for (size_t i = 0; i < 4; ++i)
+ {
+ resultArray[i].setFConst(f[i]);
+ }
+ break;
+ }
+ case EOpUnpackSnorm4x8:
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ resultArray = new TConstantUnion[4];
+ float f[4];
+ gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
+ for (size_t i = 0; i < 4; ++i)
+ {
+ resultArray[i].setFConst(f[i]);
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return resultArray;
+}
+
+TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
+ TDiagnostics *diagnostics)
+{
+ // Do unary operations where each component of the result is computed based on the corresponding
+ // component of the operand. Also folds normalize, though the divisor in that case takes all
+ // components into account.
+
+ const TConstantUnion *operandArray = getConstantValue();
+ ASSERT(operandArray);
+
+ size_t objectSize = getType().getObjectSize();
+
+ TConstantUnion *resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ switch (op)
+ {
+ case EOpNegative:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(-operandArray[i].getFConst());
+ break;
+ case EbtInt:
+ if (operandArray[i] == std::numeric_limits<int>::min())
+ {
+ // The minimum representable integer doesn't have a positive
+ // counterpart, rather the negation overflows and in ESSL is supposed to
+ // wrap back to the minimum representable integer. Make sure that we
+ // don't actually let the negation overflow, which has undefined
+ // behavior in C++.
+ resultArray[i].setIConst(std::numeric_limits<int>::min());
+ }
+ else
+ {
+ resultArray[i].setIConst(-operandArray[i].getIConst());
+ }
+ break;
+ case EbtUInt:
+ if (operandArray[i] == 0x80000000u)
+ {
+ resultArray[i].setUConst(0x80000000u);
+ }
+ else
+ {
+ resultArray[i].setUConst(static_cast<unsigned int>(
+ -static_cast<int>(operandArray[i].getUConst())));
+ }
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ break;
+
+ case EOpPositive:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(operandArray[i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(static_cast<unsigned int>(
+ static_cast<int>(operandArray[i].getUConst())));
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ break;
+
+ case EOpLogicalNot:
+ switch (getType().getBasicType())
+ {
+ case EbtBool:
+ resultArray[i].setBConst(!operandArray[i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ break;
+
+ case EOpBitwiseNot:
+ switch (getType().getBasicType())
+ {
+ case EbtInt:
+ resultArray[i].setIConst(~operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(~operandArray[i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ break;
+
+ case EOpRadians:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
+ break;
+
+ case EOpDegrees:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
+ break;
+
+ case EOpSin:
+ foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
+ break;
+
+ case EOpCos:
+ foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
+ break;
+
+ case EOpTan:
+ foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
+ break;
+
+ case EOpAsin:
+ // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
+ // 0.
+ if (fabsf(operandArray[i].getFConst()) > 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
+ break;
+
+ case EOpAcos:
+ // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
+ // 0.
+ if (fabsf(operandArray[i].getFConst()) > 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
+ break;
+
+ case EOpAtan:
+ foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
+ break;
+
+ case EOpSinh:
+ foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
+ break;
+
+ case EOpCosh:
+ foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
+ break;
+
+ case EOpTanh:
+ foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
+ break;
+
+ case EOpAsinh:
+ foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
+ break;
+
+ case EOpAcosh:
+ // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
+ if (operandArray[i].getFConst() < 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
+ break;
+
+ case EOpAtanh:
+ // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
+ // 0.
+ if (fabsf(operandArray[i].getFConst()) >= 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
+ break;
+
+ case EOpAbs:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(abs(operandArray[i].getIConst()));
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ break;
+
+ case EOpSign:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ {
+ float fConst = operandArray[i].getFConst();
+ float fResult = 0.0f;
+ if (fConst > 0.0f)
+ fResult = 1.0f;
+ else if (fConst < 0.0f)
+ fResult = -1.0f;
+ resultArray[i].setFConst(fResult);
+ break;
+ }
+ case EbtInt:
+ {
+ int iConst = operandArray[i].getIConst();
+ int iResult = 0;
+ if (iConst > 0)
+ iResult = 1;
+ else if (iConst < 0)
+ iResult = -1;
+ resultArray[i].setIConst(iResult);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ break;
+
+ case EOpFloor:
+ foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
+ break;
+
+ case EOpTrunc:
+ foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
+ break;
+
+ case EOpRound:
+ foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
+ break;
+
+ case EOpRoundEven:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ float x = operandArray[i].getFConst();
+ float result;
+ float fractPart = modff(x, &result);
+ if (fabsf(fractPart) == 0.5f)
+ result = 2.0f * roundf(x / 2.0f);
+ else
+ result = roundf(x);
+ resultArray[i].setFConst(result);
+ break;
+ }
+
+ case EOpCeil:
+ foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
+ break;
+
+ case EOpFract:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ float x = operandArray[i].getFConst();
+ resultArray[i].setFConst(x - floorf(x));
+ break;
+ }
+
+ case EOpIsnan:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
+ break;
+
+ case EOpIsinf:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
+ break;
+
+ case EOpFloatBitsToInt:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
+ break;
+
+ case EOpFloatBitsToUint:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
+ break;
+
+ case EOpIntBitsToFloat:
+ ASSERT(getType().getBasicType() == EbtInt);
+ resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
+ break;
+
+ case EOpUintBitsToFloat:
+ ASSERT(getType().getBasicType() == EbtUInt);
+ resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
+ break;
+
+ case EOpExp:
+ foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
+ break;
+
+ case EOpLog:
+ // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ if (operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
+ break;
+
+ case EOpExp2:
+ foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
+ break;
+
+ case EOpLog2:
+ // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ // And log2f is not available on some plarforms like old android, so just using
+ // log(x)/log(2) here.
+ if (operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ {
+ foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
+ resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
+ }
+ break;
+
+ case EOpSqrt:
+ // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
+ if (operandArray[i].getFConst() < 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
+ break;
+
+ case EOpInversesqrt:
+ // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
+ // so getting the square root first using builtin function sqrt() and then taking
+ // its inverse.
+ // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
+ // result to 0.
+ if (operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ {
+ foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
+ resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
+ }
+ break;
+
+ case EOpLogicalNotComponentWise:
+ ASSERT(getType().getBasicType() == EbtBool);
+ resultArray[i].setBConst(!operandArray[i].getBConst());
+ break;
+
+ case EOpNormalize:
+ {
+ ASSERT(getType().getBasicType() == EbtFloat);
+ float x = operandArray[i].getFConst();
+ float length = VectorLength(operandArray, objectSize);
+ if (length)
+ resultArray[i].setFConst(x / length);
+ else
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ break;
+ }
+ case EOpBitfieldReverse:
+ {
+ uint32_t value;
+ if (getType().getBasicType() == EbtInt)
+ {
+ value = static_cast<uint32_t>(operandArray[i].getIConst());
+ }
+ else
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ value = operandArray[i].getUConst();
+ }
+ uint32_t result = gl::BitfieldReverse(value);
+ if (getType().getBasicType() == EbtInt)
+ {
+ resultArray[i].setIConst(static_cast<int32_t>(result));
+ }
+ else
+ {
+ resultArray[i].setUConst(result);
+ }
+ break;
+ }
+ case EOpBitCount:
+ {
+ uint32_t value;
+ if (getType().getBasicType() == EbtInt)
+ {
+ value = static_cast<uint32_t>(operandArray[i].getIConst());
+ }
+ else
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ value = operandArray[i].getUConst();
+ }
+ int result = gl::BitCount(value);
+ resultArray[i].setIConst(result);
+ break;
+ }
+ case EOpFindLSB:
+ {
+ uint32_t value;
+ if (getType().getBasicType() == EbtInt)
+ {
+ value = static_cast<uint32_t>(operandArray[i].getIConst());
+ }
+ else
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ value = operandArray[i].getUConst();
+ }
+ resultArray[i].setIConst(gl::FindLSB(value));
+ break;
+ }
+ case EOpFindMSB:
+ {
+ uint32_t value;
+ if (getType().getBasicType() == EbtInt)
+ {
+ int intValue = operandArray[i].getIConst();
+ value = static_cast<uint32_t>(intValue);
+ if (intValue < 0)
+ {
+ // Look for zero instead of one in value. This also handles the intValue ==
+ // -1 special case, where the return value needs to be -1.
+ value = ~value;
+ }
+ }
+ else
+ {
+ ASSERT(getType().getBasicType() == EbtUInt);
+ value = operandArray[i].getUConst();
+ }
+ resultArray[i].setIConst(gl::FindMSB(value));
+ break;
+ }
+ case EOpDFdx:
+ case EOpDFdy:
+ case EOpFwidth:
+ ASSERT(getType().getBasicType() == EbtFloat);
+ // Derivatives of constant arguments should be 0.
+ resultArray[i].setFConst(0.0f);
+ break;
+
+ default:
+ return nullptr;
+ }
+ }
+
+ return resultArray;
+}
+
+void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
+ FloatTypeUnaryFunc builtinFunc,
+ TConstantUnion *result) const
+{
+ ASSERT(builtinFunc);
+
+ ASSERT(getType().getBasicType() == EbtFloat);
+ result->setFConst(builtinFunc(parameter.getFConst()));
+}
+
+// static
+TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics)
+{
+ TOperator op = aggregate->getOp();
+ TIntermSequence *arguments = aggregate->getSequence();
+ unsigned int argsCount = static_cast<unsigned int>(arguments->size());
+ std::vector<const TConstantUnion *> unionArrays(argsCount);
+ std::vector<size_t> objectSizes(argsCount);
+ size_t maxObjectSize = 0;
+ TBasicType basicType = EbtVoid;
+ TSourceLoc loc;
+ for (unsigned int i = 0; i < argsCount; i++)
+ {
+ TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
+ ASSERT(argConstant != nullptr); // Should be checked already.
+
+ if (i == 0)
+ {
+ basicType = argConstant->getType().getBasicType();
+ loc = argConstant->getLine();
+ }
+ unionArrays[i] = argConstant->getConstantValue();
+ objectSizes[i] = argConstant->getType().getObjectSize();
+ if (objectSizes[i] > maxObjectSize)
+ maxObjectSize = objectSizes[i];
+ }
+
+ if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
+ {
+ for (unsigned int i = 0; i < argsCount; i++)
+ if (objectSizes[i] != maxObjectSize)
+ unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
+ }
+
+ TConstantUnion *resultArray = nullptr;
+
+ switch (op)
+ {
+ case EOpAtan:
+ {
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float y = unionArrays[0][i].getFConst();
+ float x = unionArrays[1][i].getFConst();
+ // Results are undefined if x and y are both 0.
+ if (x == 0.0f && y == 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
+ else
+ resultArray[i].setFConst(atan2f(y, x));
+ }
+ break;
+ }
+
+ case EOpPow:
+ {
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ // Results are undefined if x < 0.
+ // Results are undefined if x = 0 and y <= 0.
+ if (x < 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
+ else if (x == 0.0f && y <= 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
+ else
+ resultArray[i].setFConst(powf(x, y));
+ }
+ break;
+ }
+
+ case EOpMod:
+ {
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ resultArray[i].setFConst(x - y * floorf(x / y));
+ }
+ break;
+ }
+
+ case EOpMin:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(
+ std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(
+ std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(
+ std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpMax:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(
+ std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(
+ std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(
+ std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpStep:
+ {
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ resultArray[i].setFConst(
+ unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
+ break;
+ }
+
+ case EOpLessThanComponentWise:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() <
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() <
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() <
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpLessThanEqualComponentWise:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpGreaterThanComponentWise:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() >
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() >
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() >
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+ case EOpGreaterThanEqualComponentWise:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpEqualComponentWise:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
+ unionArrays[1][i].getUConst());
+ break;
+ case EbtBool:
+ resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
+ unionArrays[1][i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpNotEqualComponentWise:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
+ unionArrays[1][i].getUConst());
+ break;
+ case EbtBool:
+ resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
+ unionArrays[1][i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpDistance:
+ {
+ ASSERT(basicType == EbtFloat);
+ TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
+ resultArray = new TConstantUnion();
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ distanceArray[i].setFConst(x - y);
+ }
+ resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
+ break;
+ }
+
+ case EOpDot:
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
+ break;
+
+ case EOpCross:
+ {
+ ASSERT(basicType == EbtFloat && maxObjectSize == 3);
+ resultArray = new TConstantUnion[maxObjectSize];
+ float x0 = unionArrays[0][0].getFConst();
+ float x1 = unionArrays[0][1].getFConst();
+ float x2 = unionArrays[0][2].getFConst();
+ float y0 = unionArrays[1][0].getFConst();
+ float y1 = unionArrays[1][1].getFConst();
+ float y2 = unionArrays[1][2].getFConst();
+ resultArray[0].setFConst(x1 * y2 - y1 * x2);
+ resultArray[1].setFConst(x2 * y0 - y2 * x0);
+ resultArray[2].setFConst(x0 * y1 - y0 * x1);
+ break;
+ }
+
+ case EOpReflect:
+ {
+ ASSERT(basicType == EbtFloat);
+ // genType reflect (genType I, genType N) :
+ // For the incident vector I and surface orientation N, returns the reflection
+ // direction:
+ // I - 2 * dot(N, I) * N.
+ resultArray = new TConstantUnion[maxObjectSize];
+ float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float result = unionArrays[0][i].getFConst() -
+ 2.0f * dotProduct * unionArrays[1][i].getFConst();
+ resultArray[i].setFConst(result);
+ }
+ break;
+ }
+
+ case EOpMulMatrixComponentWise:
+ {
+ ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
+ (*arguments)[1]->getAsTyped()->isMatrix());
+ // Perform component-wise matrix multiplication.
+ resultArray = new TConstantUnion[maxObjectSize];
+ int rows = (*arguments)[0]->getAsTyped()->getRows();
+ int cols = (*arguments)[0]->getAsTyped()->getCols();
+ angle::Matrix<float> lhs = GetMatrix(unionArrays[0], rows, cols);
+ angle::Matrix<float> rhs = GetMatrix(unionArrays[1], rows, cols);
+ angle::Matrix<float> result = lhs.compMult(rhs);
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+
+ case EOpOuterProduct:
+ {
+ ASSERT(basicType == EbtFloat);
+ size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
+ size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
+ resultArray = new TConstantUnion[numRows * numCols];
+ angle::Matrix<float> result =
+ GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
+ .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+
+ case EOpClamp:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ {
+ float x = unionArrays[0][i].getFConst();
+ float min = unionArrays[1][i].getFConst();
+ float max = unionArrays[2][i].getFConst();
+ // Results are undefined if min > max.
+ if (min > max)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ else
+ resultArray[i].setFConst(gl::clamp(x, min, max));
+ break;
+ }
+
+ case EbtInt:
+ {
+ int x = unionArrays[0][i].getIConst();
+ int min = unionArrays[1][i].getIConst();
+ int max = unionArrays[2][i].getIConst();
+ // Results are undefined if min > max.
+ if (min > max)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ else
+ resultArray[i].setIConst(gl::clamp(x, min, max));
+ break;
+ }
+ case EbtUInt:
+ {
+ unsigned int x = unionArrays[0][i].getUConst();
+ unsigned int min = unionArrays[1][i].getUConst();
+ unsigned int max = unionArrays[2][i].getUConst();
+ // Results are undefined if min > max.
+ if (min > max)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ else
+ resultArray[i].setUConst(gl::clamp(x, min, max));
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ break;
+ }
+
+ case EOpMix:
+ {
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
+ if (type == EbtFloat)
+ {
+ // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
+ float a = unionArrays[2][i].getFConst();
+ resultArray[i].setFConst(x * (1.0f - a) + y * a);
+ }
+ else // 3rd parameter is EbtBool
+ {
+ ASSERT(type == EbtBool);
+ // Selects which vector each returned component comes from.
+ // For a component of a that is false, the corresponding component of x is
+ // returned.
+ // For a component of a that is true, the corresponding component of y is
+ // returned.
+ bool a = unionArrays[2][i].getBConst();
+ resultArray[i].setFConst(a ? y : x);
+ }
+ }
+ break;
+ }
+
+ case EOpSmoothstep:
+ {
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float edge0 = unionArrays[0][i].getFConst();
+ float edge1 = unionArrays[1][i].getFConst();
+ float x = unionArrays[2][i].getFConst();
+ // Results are undefined if edge0 >= edge1.
+ if (edge0 >= edge1)
+ {
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
+ }
+ else
+ {
+ // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
+ // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
+ float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
+ resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
+ }
+ }
+ break;
+ }
+
+ case EOpLdexp:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ int exp = unionArrays[1][i].getIConst();
+ if (exp > 128)
+ {
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
+ }
+ else
+ {
+ resultArray[i].setFConst(gl::Ldexp(x, exp));
+ }
+ }
+ break;
+ }
+
+ case EOpFaceforward:
+ {
+ ASSERT(basicType == EbtFloat);
+ // genType faceforward(genType N, genType I, genType Nref) :
+ // If dot(Nref, I) < 0 return N, otherwise return -N.
+ resultArray = new TConstantUnion[maxObjectSize];
+ float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ if (dotProduct < 0)
+ resultArray[i].setFConst(unionArrays[0][i].getFConst());
+ else
+ resultArray[i].setFConst(-unionArrays[0][i].getFConst());
+ }
+ break;
+ }
+
+ case EOpRefract:
+ {
+ ASSERT(basicType == EbtFloat);
+ // genType refract(genType I, genType N, float eta) :
+ // For the incident vector I and surface normal N, and the ratio of indices of
+ // refraction eta,
+ // return the refraction vector. The result is computed by
+ // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+ // if (k < 0.0)
+ // return genType(0.0)
+ // else
+ // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
+ resultArray = new TConstantUnion[maxObjectSize];
+ float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float eta = unionArrays[2][i].getFConst();
+ float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
+ if (k < 0.0f)
+ resultArray[i].setFConst(0.0f);
+ else
+ resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
+ (eta * dotProduct + sqrtf(k)) *
+ unionArrays[1][i].getFConst());
+ }
+ break;
+ }
+ case EOpBitfieldExtract:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; ++i)
+ {
+ int offset = unionArrays[1][0].getIConst();
+ int bits = unionArrays[2][0].getIConst();
+ if (bits == 0)
+ {
+ if (aggregate->getBasicType() == EbtInt)
+ {
+ resultArray[i].setIConst(0);
+ }
+ else
+ {
+ ASSERT(aggregate->getBasicType() == EbtUInt);
+ resultArray[i].setUConst(0);
+ }
+ }
+ else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
+ {
+ UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
+ &resultArray[i]);
+ }
+ else
+ {
+ // bits can be 32 here, so we need to avoid bit shift overflow.
+ uint32_t maskMsb = 1u << (bits - 1);
+ uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
+ if (aggregate->getBasicType() == EbtInt)
+ {
+ uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
+ uint32_t resultUnsigned = (value & mask) >> offset;
+ if ((resultUnsigned & maskMsb) != 0)
+ {
+ // The most significant bits (from bits+1 to the most significant bit)
+ // should be set to 1.
+ uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
+ resultUnsigned |= higherBitsMask;
+ }
+ resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
+ }
+ else
+ {
+ ASSERT(aggregate->getBasicType() == EbtUInt);
+ uint32_t value = unionArrays[0][i].getUConst();
+ resultArray[i].setUConst((value & mask) >> offset);
+ }
+ }
+ }
+ break;
+ }
+ case EOpBitfieldInsert:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; ++i)
+ {
+ int offset = unionArrays[2][0].getIConst();
+ int bits = unionArrays[3][0].getIConst();
+ if (bits == 0)
+ {
+ if (aggregate->getBasicType() == EbtInt)
+ {
+ int32_t base = unionArrays[0][i].getIConst();
+ resultArray[i].setIConst(base);
+ }
+ else
+ {
+ ASSERT(aggregate->getBasicType() == EbtUInt);
+ uint32_t base = unionArrays[0][i].getUConst();
+ resultArray[i].setUConst(base);
+ }
+ }
+ else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
+ {
+ UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
+ &resultArray[i]);
+ }
+ else
+ {
+ // bits can be 32 here, so we need to avoid bit shift overflow.
+ uint32_t maskMsb = 1u << (bits - 1);
+ uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
+ uint32_t baseMask = ~insertMask;
+ if (aggregate->getBasicType() == EbtInt)
+ {
+ uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
+ uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
+ uint32_t resultUnsigned =
+ (base & baseMask) | ((insert << offset) & insertMask);
+ resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
+ }
+ else
+ {
+ ASSERT(aggregate->getBasicType() == EbtUInt);
+ uint32_t base = unionArrays[0][i].getUConst();
+ uint32_t insert = unionArrays[1][i].getUConst();
+ resultArray[i].setUConst((base & baseMask) |
+ ((insert << offset) & insertMask));
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ return resultArray;
+}
+
+bool TIntermConstantUnion::IsFloatDivision(TBasicType t1, TBasicType t2)
+{
+ ImplicitTypeConversion conversion = GetConversion(t1, t2);
+ ASSERT(conversion != ImplicitTypeConversion::Invalid);
+ if (conversion == ImplicitTypeConversion::Same)
+ {
+ if (t1 == EbtFloat)
+ return true;
+ return false;
+ }
+ ASSERT(t1 == EbtFloat || t2 == EbtFloat);
+ return true;
+}
+
+// TIntermPreprocessorDirective implementation.
+TIntermPreprocessorDirective::TIntermPreprocessorDirective(PreprocessorDirective directive,
+ ImmutableString command)
+ : mDirective(directive), mCommand(std::move(command))
+{}
+
+TIntermPreprocessorDirective::~TIntermPreprocessorDirective() = default;
+
+size_t TIntermPreprocessorDirective::getChildCount() const
+{
+ return 0;
+}
+
+TIntermNode *TIntermPreprocessorDirective::getChildNode(size_t index) const
+{
+ UNREACHABLE();
+ return nullptr;
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/IntermNode.h b/gfx/angle/checkout/src/compiler/translator/IntermNode.h
new file mode 100644
index 0000000000..5667378b14
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.h
@@ -0,0 +1,936 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Definition of the in-memory high-level intermediate representation
+// of shaders. This is a tree that parser creates.
+//
+// Nodes in the tree are defined as a hierarchy of classes derived from
+// TIntermNode. Each is a node in a tree. There is no preset branching factor;
+// each node can have it's own type of list of children.
+//
+
+#ifndef COMPILER_TRANSLATOR_INTERMNODE_H_
+#define COMPILER_TRANSLATOR_INTERMNODE_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <algorithm>
+#include <queue>
+
+#include "common/angleutils.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/ConstantUnion.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/Operator.h"
+#include "compiler/translator/SymbolUniqueId.h"
+#include "compiler/translator/Types.h"
+#include "compiler/translator/tree_util/Visit.h"
+
+namespace sh
+{
+
+class TDiagnostics;
+
+class TIntermTraverser;
+class TIntermAggregate;
+class TIntermBlock;
+class TIntermInvariantDeclaration;
+class TIntermDeclaration;
+class TIntermFunctionPrototype;
+class TIntermFunctionDefinition;
+class TIntermSwizzle;
+class TIntermBinary;
+class TIntermUnary;
+class TIntermConstantUnion;
+class TIntermTernary;
+class TIntermIfElse;
+class TIntermSwitch;
+class TIntermCase;
+class TIntermTyped;
+class TIntermSymbol;
+class TIntermLoop;
+class TInfoSink;
+class TInfoSinkBase;
+class TIntermBranch;
+class TIntermPreprocessorDirective;
+
+class TSymbolTable;
+class TFunction;
+class TVariable;
+
+//
+// Base class for the tree nodes
+//
+class TIntermNode : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TIntermNode()
+ {
+ // TODO: Move this to TSourceLoc constructor
+ // after getting rid of TPublicType.
+ mLine.first_file = mLine.last_file = 0;
+ mLine.first_line = mLine.last_line = 0;
+ }
+ virtual ~TIntermNode() {}
+
+ const TSourceLoc &getLine() const { return mLine; }
+ void setLine(const TSourceLoc &l) { mLine = l; }
+
+ virtual void traverse(TIntermTraverser *it);
+ virtual bool visit(Visit visit, TIntermTraverser *it) = 0;
+
+ virtual TIntermTyped *getAsTyped() { return nullptr; }
+ virtual TIntermConstantUnion *getAsConstantUnion() { return nullptr; }
+ virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; }
+ virtual TIntermAggregate *getAsAggregate() { return nullptr; }
+ virtual TIntermBlock *getAsBlock() { return nullptr; }
+ virtual TIntermFunctionPrototype *getAsFunctionPrototypeNode() { return nullptr; }
+ virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() { return nullptr; }
+ virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; }
+ virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; }
+ virtual TIntermBinary *getAsBinaryNode() { return nullptr; }
+ virtual TIntermUnary *getAsUnaryNode() { return nullptr; }
+ virtual TIntermTernary *getAsTernaryNode() { return nullptr; }
+ virtual TIntermIfElse *getAsIfElseNode() { return nullptr; }
+ virtual TIntermSwitch *getAsSwitchNode() { return nullptr; }
+ virtual TIntermCase *getAsCaseNode() { return nullptr; }
+ virtual TIntermSymbol *getAsSymbolNode() { return nullptr; }
+ virtual TIntermLoop *getAsLoopNode() { return nullptr; }
+ virtual TIntermBranch *getAsBranchNode() { return nullptr; }
+ virtual TIntermPreprocessorDirective *getAsPreprocessorDirective() { return nullptr; }
+
+ virtual size_t getChildCount() const = 0;
+ virtual TIntermNode *getChildNode(size_t index) const = 0;
+ // Replace a child node. Return true if |original| is a child
+ // node and it is replaced; otherwise, return false.
+ virtual bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) = 0;
+
+ protected:
+ TSourceLoc mLine;
+};
+
+//
+// This is just to help yacc.
+//
+struct TIntermNodePair
+{
+ TIntermNode *node1;
+ TIntermNode *node2;
+};
+
+//
+// Intermediate class for nodes that have a type.
+//
+class TIntermTyped : public TIntermNode
+{
+ public:
+ TIntermTyped() {}
+
+ virtual TIntermTyped *deepCopy() const = 0;
+
+ TIntermTyped *getAsTyped() override { return this; }
+
+ virtual TIntermTyped *fold(TDiagnostics *diagnostics) { return this; }
+
+ // getConstantValue() returns the constant value that this node represents, if any. It
+ // should only be used after nodes have been replaced with their folded versions returned
+ // from fold(). hasConstantValue() returns true if getConstantValue() will return a value.
+ virtual bool hasConstantValue() const;
+ virtual const TConstantUnion *getConstantValue() const;
+
+ // True if executing the expression represented by this node affects state, like values of
+ // variables. False if the executing the expression only computes its return value without
+ // affecting state. May return true conservatively.
+ virtual bool hasSideEffects() const = 0;
+
+ virtual const TType &getType() const = 0;
+
+ TBasicType getBasicType() const { return getType().getBasicType(); }
+ TQualifier getQualifier() const { return getType().getQualifier(); }
+ TPrecision getPrecision() const { return getType().getPrecision(); }
+ TMemoryQualifier getMemoryQualifier() const { return getType().getMemoryQualifier(); }
+ int getCols() const { return getType().getCols(); }
+ int getRows() const { return getType().getRows(); }
+ int getNominalSize() const { return getType().getNominalSize(); }
+ int getSecondarySize() const { return getType().getSecondarySize(); }
+
+ bool isInterfaceBlock() const { return getType().isInterfaceBlock(); }
+ bool isMatrix() const { return getType().isMatrix(); }
+ bool isArray() const { return getType().isArray(); }
+ bool isVector() const { return getType().isVector(); }
+ bool isScalar() const { return getType().isScalar(); }
+ bool isScalarInt() const { return getType().isScalarInt(); }
+ const char *getBasicString() const { return getType().getBasicString(); }
+
+ unsigned int getOutermostArraySize() const { return getType().getOutermostArraySize(); }
+
+ protected:
+ TIntermTyped(const TIntermTyped &node);
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+enum TLoopType
+{
+ ELoopFor,
+ ELoopWhile,
+ ELoopDoWhile
+};
+
+class TIntermLoop : public TIntermNode
+{
+ public:
+ TIntermLoop(TLoopType type,
+ TIntermNode *init,
+ TIntermTyped *cond,
+ TIntermTyped *expr,
+ TIntermBlock *body);
+
+ TIntermLoop *getAsLoopNode() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TLoopType getType() const { return mType; }
+ TIntermNode *getInit() { return mInit; }
+ TIntermTyped *getCondition() { return mCond; }
+ TIntermTyped *getExpression() { return mExpr; }
+ TIntermBlock *getBody() { return mBody; }
+
+ void setInit(TIntermNode *init) { mInit = init; }
+ void setCondition(TIntermTyped *condition) { mCond = condition; }
+ void setExpression(TIntermTyped *expression) { mExpr = expression; }
+ void setBody(TIntermBlock *body) { mBody = body; }
+
+ protected:
+ TLoopType mType;
+ TIntermNode *mInit; // for-loop initialization
+ TIntermTyped *mCond; // loop exit condition
+ TIntermTyped *mExpr; // for-loop expression
+ TIntermBlock *mBody; // loop body
+};
+
+//
+// Handle break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode
+{
+ public:
+ TIntermBranch(TOperator op, TIntermTyped *e) : mFlowOp(op), mExpression(e) {}
+
+ TIntermBranch *getAsBranchNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TOperator getFlowOp() { return mFlowOp; }
+ TIntermTyped *getExpression() { return mExpression; }
+
+ protected:
+ TOperator mFlowOp;
+ TIntermTyped *mExpression; // zero except for "return exp;" statements
+};
+
+// Nodes that correspond to variable symbols in the source code. These may be regular variables or
+// interface block instances. In declarations that only declare a struct type but no variables, a
+// TIntermSymbol node with an empty variable is used to store the type.
+class TIntermSymbol : public TIntermTyped
+{
+ public:
+ TIntermSymbol(const TVariable *variable);
+
+ TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); }
+
+ bool hasConstantValue() const override;
+ const TConstantUnion *getConstantValue() const override;
+
+ bool hasSideEffects() const override { return false; }
+
+ const TType &getType() const override;
+
+ const TSymbolUniqueId &uniqueId() const;
+ ImmutableString getName() const;
+ const TVariable &variable() const { return *mVariable; }
+
+ TIntermSymbol *getAsSymbolNode() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
+
+ private:
+ TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private!
+
+ const TVariable *const mVariable; // Guaranteed to be non-null
+};
+
+// A typed expression that is not just representing a symbol table symbol.
+class TIntermExpression : public TIntermTyped
+{
+ public:
+ TIntermExpression(const TType &t);
+
+ const TType &getType() const override { return mType; }
+
+ protected:
+ TType *getTypePointer() { return &mType; }
+ void setType(const TType &t) { mType = t; }
+ void setTypePreservePrecision(const TType &t);
+
+ TIntermExpression(const TIntermExpression &node) = default;
+
+ TType mType;
+};
+
+// Constant folded node.
+// Note that nodes may be constant folded and not be constant expressions with the EvqConst
+// qualifier. This happens for example when the following expression is processed:
+// "true ? 1.0 : non_constant"
+// Other nodes than TIntermConstantUnion may also be constant expressions.
+//
+class TIntermConstantUnion : public TIntermExpression
+{
+ public:
+ TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
+ : TIntermExpression(type), mUnionArrayPointer(unionPointer)
+ {
+ ASSERT(unionPointer);
+ }
+
+ TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
+
+ bool hasConstantValue() const override;
+ const TConstantUnion *getConstantValue() const override;
+
+ bool hasSideEffects() const override { return false; }
+
+ int getIConst(size_t index) const
+ {
+ return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0;
+ }
+ unsigned int getUConst(size_t index) const
+ {
+ return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0;
+ }
+ float getFConst(size_t index) const
+ {
+ return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f;
+ }
+ bool getBConst(size_t index) const
+ {
+ return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
+ }
+
+ TIntermConstantUnion *getAsConstantUnion() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
+
+ TConstantUnion *foldUnaryNonComponentWise(TOperator op);
+ TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
+
+ static const TConstantUnion *FoldBinary(TOperator op,
+ const TConstantUnion *leftArray,
+ const TType &leftType,
+ const TConstantUnion *rightArray,
+ const TType &rightType,
+ TDiagnostics *diagnostics,
+ const TSourceLoc &line);
+
+ static const TConstantUnion *FoldIndexing(const TType &type,
+ const TConstantUnion *constArray,
+ int index);
+ static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics);
+ static bool IsFloatDivision(TBasicType t1, TBasicType t2);
+
+ protected:
+ // Same data may be shared between multiple constant unions, so it can't be modified.
+ const TConstantUnion *mUnionArrayPointer;
+
+ private:
+ typedef float (*FloatTypeUnaryFunc)(float);
+ void foldFloatTypeUnary(const TConstantUnion &parameter,
+ FloatTypeUnaryFunc builtinFunc,
+ TConstantUnion *result) const;
+
+ TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermExpression
+{
+ public:
+ TOperator getOp() const { return mOp; }
+
+ bool isAssignment() const;
+ bool isMultiplication() const;
+ bool isConstructor() const;
+
+ // Returns true for calls mapped to EOpCall*, false for built-ins that have their own specific
+ // ops.
+ bool isFunctionCall() const;
+
+ bool hasSideEffects() const override { return isAssignment(); }
+
+ protected:
+ TIntermOperator(TOperator op) : TIntermExpression(TType(EbtFloat, EbpUndefined)), mOp(op) {}
+ TIntermOperator(TOperator op, const TType &type) : TIntermExpression(type), mOp(op) {}
+
+ TIntermOperator(const TIntermOperator &) = default;
+
+ const TOperator mOp;
+};
+
+// Node for vector swizzles.
+class TIntermSwizzle : public TIntermExpression
+{
+ public:
+ // This constructor determines the type of the node based on the operand.
+ TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets);
+
+ TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); }
+
+ TIntermSwizzle *getAsSwizzleNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override { return mOperand->hasSideEffects(); }
+
+ TIntermTyped *getOperand() { return mOperand; }
+ void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
+
+ const TVector<int> &getSwizzleOffsets() { return mSwizzleOffsets; }
+
+ bool hasDuplicateOffsets() const;
+ void setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets);
+ bool offsetsMatch(int offset) const;
+
+ TIntermTyped *fold(TDiagnostics *diagnostics) override;
+
+ protected:
+ TIntermTyped *mOperand;
+ TVector<int> mSwizzleOffsets;
+ bool mHasFoldedDuplicateOffsets;
+
+ private:
+ void promote();
+
+ TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private!
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator
+{
+ public:
+ // This constructor determines the type of the binary node based on the operands and op.
+ TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right);
+ // Comma qualifier depends on the shader version, so use this to create comma nodes:
+ static TIntermBinary *CreateComma(TIntermTyped *left, TIntermTyped *right, int shaderVersion);
+
+ TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
+
+ bool hasConstantValue() const override;
+ const TConstantUnion *getConstantValue() const override;
+
+ static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right);
+ static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right);
+
+ TIntermBinary *getAsBinaryNode() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override
+ {
+ return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
+ }
+
+ TIntermTyped *getLeft() const { return mLeft; }
+ TIntermTyped *getRight() const { return mRight; }
+ TIntermTyped *fold(TDiagnostics *diagnostics) override;
+
+ void setAddIndexClamp() { mAddIndexClamp = true; }
+ bool getAddIndexClamp() const { return mAddIndexClamp; }
+
+ // This method is only valid for EOpIndexDirectStruct. It returns the name of the field.
+ const ImmutableString &getIndexStructFieldName() const;
+
+ protected:
+ TIntermTyped *mLeft;
+ TIntermTyped *mRight;
+
+ // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
+ bool mAddIndexClamp;
+
+ private:
+ void promote();
+
+ static TQualifier GetCommaQualifier(int shaderVersion,
+ const TIntermTyped *left,
+ const TIntermTyped *right);
+
+ TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private!
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator
+{
+ public:
+ TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function);
+
+ TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
+
+ TIntermUnary *getAsUnaryNode() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
+
+ TIntermTyped *getOperand() { return mOperand; }
+ TIntermTyped *fold(TDiagnostics *diagnostics) override;
+
+ const TFunction *getFunction() const { return mFunction; }
+
+ void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
+
+ protected:
+ TIntermTyped *mOperand;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool mUseEmulatedFunction;
+
+ const TFunction *const mFunction;
+
+ private:
+ void promote();
+
+ TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
+};
+
+typedef TVector<TIntermNode *> TIntermSequence;
+typedef TVector<int> TQualifierList;
+
+// Interface for node classes that have an arbitrarily sized set of children.
+class TIntermAggregateBase
+{
+ public:
+ virtual ~TIntermAggregateBase() {}
+
+ virtual TIntermSequence *getSequence() = 0;
+ virtual const TIntermSequence *getSequence() const = 0;
+
+ bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements);
+ bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions);
+
+ protected:
+ TIntermAggregateBase() {}
+
+ bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement);
+};
+
+//
+// Nodes that operate on an arbitrary sized set of children.
+//
+class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
+{
+ public:
+ static TIntermAggregate *CreateFunctionCall(const TFunction &func, TIntermSequence *arguments);
+
+ static TIntermAggregate *CreateRawFunctionCall(const TFunction &func,
+ TIntermSequence *arguments);
+
+ // This covers all built-in function calls - whether they are associated with an op or not.
+ static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func,
+ TIntermSequence *arguments);
+ static TIntermAggregate *CreateConstructor(const TType &type, TIntermSequence *arguments);
+ ~TIntermAggregate() {}
+
+ // Note: only supported for nodes that can be a part of an expression.
+ TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
+
+ TIntermAggregate *shallowCopy() const;
+
+ bool hasConstantValue() const override;
+ const TConstantUnion *getConstantValue() const override;
+
+ TIntermAggregate *getAsAggregate() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override;
+
+ TIntermTyped *fold(TDiagnostics *diagnostics) override;
+
+ TIntermSequence *getSequence() override { return &mArguments; }
+ const TIntermSequence *getSequence() const override { return &mArguments; }
+
+ void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
+
+ // Returns true if changing parameter precision may affect the return value.
+ bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
+
+ const TFunction *getFunction() const { return mFunction; }
+
+ // Get the function name to display to the user in an error message.
+ const char *functionName() const;
+
+ protected:
+ TIntermSequence mArguments;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs. Only for calls mapped to ops other than EOpCall*.
+ bool mUseEmulatedFunction;
+
+ bool mGotPrecisionFromChildren;
+
+ const TFunction *const mFunction;
+
+ private:
+ TIntermAggregate(const TFunction *func,
+ const TType &type,
+ TOperator op,
+ TIntermSequence *arguments);
+
+ TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
+
+ void setPrecisionAndQualifier();
+
+ bool areChildrenConstQualified();
+
+ void setPrecisionFromChildren();
+
+ void setPrecisionForBuiltInOp();
+
+ // Returns true if precision was set according to special rules for this built-in.
+ bool setPrecisionForSpecialBuiltInOp();
+
+ // Used for built-in functions under EOpCallBuiltInFunction. The function name in the symbol
+ // info needs to be set before calling this.
+ void setBuiltInFunctionPrecision();
+};
+
+// A list of statements. Either the root node which contains declarations and function definitions,
+// or a block that can be marked with curly braces {}.
+class TIntermBlock : public TIntermNode, public TIntermAggregateBase
+{
+ public:
+ TIntermBlock() : TIntermNode() {}
+ ~TIntermBlock() {}
+
+ TIntermBlock *getAsBlock() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ // Only intended for initially building the block.
+ void appendStatement(TIntermNode *statement);
+ void insertStatement(size_t insertPosition, TIntermNode *statement);
+
+ TIntermSequence *getSequence() override { return &mStatements; }
+ const TIntermSequence *getSequence() const override { return &mStatements; }
+
+ protected:
+ TIntermSequence mStatements;
+};
+
+// Function prototype. May be in the AST either as a function prototype declaration or as a part of
+// a function definition. The type of the node is the function return type.
+class TIntermFunctionPrototype : public TIntermTyped
+{
+ public:
+ TIntermFunctionPrototype(const TFunction *function);
+ ~TIntermFunctionPrototype() {}
+
+ TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ const TType &getType() const override;
+
+ TIntermTyped *deepCopy() const override
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+ bool hasSideEffects() const override
+ {
+ UNREACHABLE();
+ return true;
+ }
+
+ const TFunction *getFunction() const { return mFunction; }
+
+ protected:
+ const TFunction *const mFunction;
+};
+
+// Node for function definitions. The prototype child node stores the function header including
+// parameters, and the body child node stores the function body.
+class TIntermFunctionDefinition : public TIntermNode
+{
+ public:
+ TIntermFunctionDefinition(TIntermFunctionPrototype *prototype, TIntermBlock *body)
+ : TIntermNode(), mPrototype(prototype), mBody(body)
+ {
+ ASSERT(prototype != nullptr);
+ ASSERT(body != nullptr);
+ }
+
+ TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; }
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermFunctionPrototype *getFunctionPrototype() const { return mPrototype; }
+ TIntermBlock *getBody() const { return mBody; }
+
+ const TFunction *getFunction() const { return mPrototype->getFunction(); }
+
+ private:
+ TIntermFunctionPrototype *mPrototype;
+ TIntermBlock *mBody;
+};
+
+// Struct, interface block or variable declaration. Can contain multiple variable declarators.
+class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase
+{
+ public:
+ TIntermDeclaration() : TIntermNode() {}
+ ~TIntermDeclaration() {}
+
+ TIntermDeclaration *getAsDeclarationNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ // Only intended for initially building the declaration.
+ // The declarator node should be either TIntermSymbol or TIntermBinary with op set to
+ // EOpInitialize.
+ void appendDeclarator(TIntermTyped *declarator);
+
+ TIntermSequence *getSequence() override { return &mDeclarators; }
+ const TIntermSequence *getSequence() const override { return &mDeclarators; }
+
+ protected:
+ TIntermSequence mDeclarators;
+};
+
+// Specialized declarations for attributing invariance.
+class TIntermInvariantDeclaration : public TIntermNode
+{
+ public:
+ TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line);
+
+ virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ TIntermSymbol *getSymbol() { return mSymbol; }
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ private:
+ TIntermSymbol *mSymbol;
+};
+
+// For ternary operators like a ? b : c.
+class TIntermTernary : public TIntermExpression
+{
+ public:
+ TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
+
+ TIntermTernary *getAsTernaryNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *getCondition() const { return mCondition; }
+ TIntermTyped *getTrueExpression() const { return mTrueExpression; }
+ TIntermTyped *getFalseExpression() const { return mFalseExpression; }
+
+ TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); }
+
+ bool hasSideEffects() const override
+ {
+ return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() ||
+ mFalseExpression->hasSideEffects();
+ }
+
+ TIntermTyped *fold(TDiagnostics *diagnostics) override;
+
+ private:
+ TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private!
+
+ static TQualifier DetermineQualifier(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression);
+
+ TIntermTyped *mCondition;
+ TIntermTyped *mTrueExpression;
+ TIntermTyped *mFalseExpression;
+};
+
+class TIntermIfElse : public TIntermNode
+{
+ public:
+ TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB);
+
+ TIntermIfElse *getAsIfElseNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *getCondition() const { return mCondition; }
+ TIntermBlock *getTrueBlock() const { return mTrueBlock; }
+ TIntermBlock *getFalseBlock() const { return mFalseBlock; }
+
+ protected:
+ TIntermTyped *mCondition;
+ TIntermBlock *mTrueBlock;
+ TIntermBlock *mFalseBlock;
+};
+
+//
+// Switch statement.
+//
+class TIntermSwitch : public TIntermNode
+{
+ public:
+ TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList);
+
+ TIntermSwitch *getAsSwitchNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *getInit() { return mInit; }
+ TIntermBlock *getStatementList() { return mStatementList; }
+
+ // Must be called with a non-null statementList.
+ void setStatementList(TIntermBlock *statementList);
+
+ protected:
+ TIntermTyped *mInit;
+ TIntermBlock *mStatementList;
+};
+
+//
+// Case label.
+//
+class TIntermCase : public TIntermNode
+{
+ public:
+ TIntermCase(TIntermTyped *condition) : TIntermNode(), mCondition(condition) {}
+
+ TIntermCase *getAsCaseNode() override { return this; }
+ bool visit(Visit visit, TIntermTraverser *it) final;
+
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasCondition() const { return mCondition != nullptr; }
+ TIntermTyped *getCondition() const { return mCondition; }
+
+ protected:
+ TIntermTyped *mCondition;
+};
+
+//
+// Preprocessor Directive.
+// #ifdef, #define, #if, #endif, etc.
+//
+
+enum class PreprocessorDirective
+{
+ Define,
+ Ifdef,
+ If,
+ Endif,
+};
+
+class TIntermPreprocessorDirective : public TIntermNode
+{
+ public:
+ // This could also take an ImmutbleString as an argument.
+ TIntermPreprocessorDirective(PreprocessorDirective directive, ImmutableString command);
+ ~TIntermPreprocessorDirective() final;
+
+ void traverse(TIntermTraverser *it) final;
+ bool visit(Visit visit, TIntermTraverser *it) final;
+ bool replaceChildNode(TIntermNode *, TIntermNode *) final { return false; }
+
+ TIntermPreprocessorDirective *getAsPreprocessorDirective() final { return this; }
+ size_t getChildCount() const final;
+ TIntermNode *getChildNode(size_t index) const final;
+
+ PreprocessorDirective getDirective() const { return mDirective; }
+ const ImmutableString &getCommand() const { return mCommand; }
+
+ private:
+ PreprocessorDirective mDirective;
+ ImmutableString mCommand;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_INTERMNODE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp
new file mode 100644
index 0000000000..73cb9d1833
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/IsASTDepthBelowLimit.h"
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// Traverse the tree and compute max depth. Takes a maximum depth limit to prevent stack overflow.
+class MaxDepthTraverser : public TIntermTraverser
+{
+ public:
+ MaxDepthTraverser(int depthLimit) : TIntermTraverser(true, false, false, nullptr)
+ {
+ setMaxAllowedDepth(depthLimit);
+ }
+};
+
+} // anonymous namespace
+
+bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth)
+{
+ MaxDepthTraverser traverser(maxDepth + 1);
+ root->traverse(&traverser);
+
+ return traverser.getMaxDepth() <= maxDepth;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h
new file mode 100644
index 0000000000..ef2f02c974
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IsASTDepthBelowLimit: Check whether AST depth is below a specific limit.
+
+#ifndef COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
+#define COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
+
+namespace sh
+{
+
+class TIntermNode;
+
+bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Operator.cpp b/gfx/angle/checkout/src/compiler/translator/Operator.cpp
new file mode 100644
index 0000000000..ce6bf3d868
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Operator.cpp
@@ -0,0 +1,420 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/Operator.h"
+
+const char *GetOperatorString(TOperator op)
+{
+ switch (op)
+ {
+ // Note: EOpNull and EOpCall* can't be handled here.
+
+ case EOpNegative:
+ return "-";
+ case EOpPositive:
+ return "+";
+ case EOpLogicalNot:
+ return "!";
+ case EOpBitwiseNot:
+ return "~";
+
+ case EOpPostIncrement:
+ return "++";
+ case EOpPostDecrement:
+ return "--";
+ case EOpPreIncrement:
+ return "++";
+ case EOpPreDecrement:
+ return "--";
+
+ case EOpArrayLength:
+ return ".length()";
+
+ case EOpAdd:
+ return "+";
+ case EOpSub:
+ return "-";
+ case EOpMul:
+ return "*";
+ case EOpDiv:
+ return "/";
+ case EOpIMod:
+ return "%";
+
+ case EOpEqual:
+ return "==";
+ case EOpNotEqual:
+ return "!=";
+ case EOpLessThan:
+ return "<";
+ case EOpGreaterThan:
+ return ">";
+ case EOpLessThanEqual:
+ return "<=";
+ case EOpGreaterThanEqual:
+ return ">=";
+
+ case EOpEqualComponentWise:
+ return "equal";
+ case EOpNotEqualComponentWise:
+ return "notEqual";
+ case EOpLessThanComponentWise:
+ return "lessThan";
+ case EOpGreaterThanComponentWise:
+ return "greaterThan";
+ case EOpLessThanEqualComponentWise:
+ return "lessThanEqual";
+ case EOpGreaterThanEqualComponentWise:
+ return "greaterThanEqual";
+
+ case EOpComma:
+ return ",";
+
+ // Fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ return "*";
+
+ case EOpLogicalOr:
+ return "||";
+ case EOpLogicalXor:
+ return "^^";
+ case EOpLogicalAnd:
+ return "&&";
+
+ case EOpBitShiftLeft:
+ return "<<";
+ case EOpBitShiftRight:
+ return ">>";
+
+ case EOpBitwiseAnd:
+ return "&";
+ case EOpBitwiseXor:
+ return "^";
+ case EOpBitwiseOr:
+ return "|";
+
+ // Fall-through.
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ return "[]";
+
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ return ".";
+
+ case EOpRadians:
+ return "radians";
+ case EOpDegrees:
+ return "degrees";
+ case EOpSin:
+ return "sin";
+ case EOpCos:
+ return "cos";
+ case EOpTan:
+ return "tan";
+ case EOpAsin:
+ return "asin";
+ case EOpAcos:
+ return "acos";
+ case EOpAtan:
+ return "atan";
+
+ case EOpSinh:
+ return "sinh";
+ case EOpCosh:
+ return "cosh";
+ case EOpTanh:
+ return "tanh";
+ case EOpAsinh:
+ return "asinh";
+ case EOpAcosh:
+ return "acosh";
+ case EOpAtanh:
+ return "atanh";
+
+ case EOpPow:
+ return "pow";
+ case EOpExp:
+ return "exp";
+ case EOpLog:
+ return "log";
+ case EOpExp2:
+ return "exp2";
+ case EOpLog2:
+ return "log2";
+ case EOpSqrt:
+ return "sqrt";
+ case EOpInversesqrt:
+ return "inversesqrt";
+
+ case EOpAbs:
+ return "abs";
+ case EOpSign:
+ return "sign";
+ case EOpFloor:
+ return "floor";
+ case EOpTrunc:
+ return "trunc";
+ case EOpRound:
+ return "round";
+ case EOpRoundEven:
+ return "roundEven";
+ case EOpCeil:
+ return "ceil";
+ case EOpFract:
+ return "fract";
+ case EOpMod:
+ return "mod";
+ case EOpModf:
+ return "modf";
+ case EOpMin:
+ return "min";
+ case EOpMax:
+ return "max";
+ case EOpClamp:
+ return "clamp";
+ case EOpMix:
+ return "mix";
+ case EOpStep:
+ return "step";
+ case EOpSmoothstep:
+ return "smoothstep";
+ case EOpIsnan:
+ return "isnan";
+ case EOpIsinf:
+ return "isinf";
+
+ case EOpFloatBitsToInt:
+ return "floatBitsToInt";
+ case EOpFloatBitsToUint:
+ return "floatBitsToUint";
+ case EOpIntBitsToFloat:
+ return "intBitsToFloat";
+ case EOpUintBitsToFloat:
+ return "uintBitsToFloat";
+
+ case EOpFrexp:
+ return "frexp";
+ case EOpLdexp:
+ return "ldexp";
+
+ case EOpPackSnorm2x16:
+ return "packSnorm2x16";
+ case EOpPackUnorm2x16:
+ return "packUnorm2x16";
+ case EOpPackHalf2x16:
+ return "packHalf2x16";
+ case EOpUnpackSnorm2x16:
+ return "unpackSnorm2x16";
+ case EOpUnpackUnorm2x16:
+ return "unpackUnorm2x16";
+ case EOpUnpackHalf2x16:
+ return "unpackHalf2x16";
+
+ case EOpPackUnorm4x8:
+ return "packUnorm4x8";
+ case EOpPackSnorm4x8:
+ return "packSnorm4x8";
+ case EOpUnpackUnorm4x8:
+ return "unpackUnorm4x8";
+ case EOpUnpackSnorm4x8:
+ return "unpackSnorm4x8";
+
+ case EOpLength:
+ return "length";
+ case EOpDistance:
+ return "distance";
+ case EOpDot:
+ return "dot";
+ case EOpCross:
+ return "cross";
+ case EOpNormalize:
+ return "normalize";
+ case EOpFaceforward:
+ return "faceforward";
+ case EOpReflect:
+ return "reflect";
+ case EOpRefract:
+ return "refract";
+
+ case EOpDFdx:
+ return "dFdx";
+ case EOpDFdy:
+ return "dFdy";
+ case EOpFwidth:
+ return "fwidth";
+
+ case EOpMulMatrixComponentWise:
+ return "matrixCompMult";
+ case EOpOuterProduct:
+ return "outerProduct";
+ case EOpTranspose:
+ return "transpose";
+ case EOpDeterminant:
+ return "determinant";
+ case EOpInverse:
+ return "inverse";
+
+ case EOpAny:
+ return "any";
+ case EOpAll:
+ return "all";
+ case EOpLogicalNotComponentWise:
+ return "not";
+
+ case EOpBitfieldExtract:
+ return "bitfieldExtract";
+ case EOpBitfieldInsert:
+ return "bitfieldInsert";
+ case EOpBitfieldReverse:
+ return "bitfieldReverse";
+ case EOpBitCount:
+ return "bitCount";
+ case EOpFindLSB:
+ return "findLSB";
+ case EOpFindMSB:
+ return "findMSB";
+ case EOpUaddCarry:
+ return "uaddCarry";
+ case EOpUsubBorrow:
+ return "usubBorrow";
+ case EOpUmulExtended:
+ return "umulExtended";
+ case EOpImulExtended:
+ return "imulExtended";
+
+ case EOpKill:
+ return "kill";
+ case EOpReturn:
+ return "return";
+ case EOpBreak:
+ return "break";
+ case EOpContinue:
+ return "continue";
+
+ case EOpAssign:
+ return "=";
+ case EOpInitialize:
+ return "=";
+ case EOpAddAssign:
+ return "+=";
+ case EOpSubAssign:
+ return "-=";
+
+ // Fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ return "*=";
+
+ case EOpDivAssign:
+ return "/=";
+ case EOpIModAssign:
+ return "%=";
+ case EOpBitShiftLeftAssign:
+ return "<<=";
+ case EOpBitShiftRightAssign:
+ return ">>=";
+ case EOpBitwiseAndAssign:
+ return "&=";
+ case EOpBitwiseXorAssign:
+ return "^=";
+ case EOpBitwiseOrAssign:
+ return "|=";
+ case EOpBarrier:
+ return "barrier";
+ case EOpMemoryBarrier:
+ return "memoryBarrier";
+ case EOpMemoryBarrierAtomicCounter:
+ return "memoryBarrierAtomicCounter";
+ case EOpMemoryBarrierBuffer:
+ return "memoryBarrierBuffer";
+ case EOpMemoryBarrierImage:
+ return "memoryBarrierImage";
+ case EOpMemoryBarrierShared:
+ return "memoryBarrierShared";
+ case EOpGroupMemoryBarrier:
+ return "groupMemoryBarrier";
+
+ case EOpAtomicAdd:
+ return "atomicAdd";
+ case EOpAtomicMin:
+ return "atomicMin";
+ case EOpAtomicMax:
+ return "atomicMax";
+ case EOpAtomicAnd:
+ return "atomicAnd";
+ case EOpAtomicOr:
+ return "atomicOr";
+ case EOpAtomicXor:
+ return "atomicXor";
+ case EOpAtomicExchange:
+ return "atomicExchange";
+ case EOpAtomicCompSwap:
+ return "atomicCompSwap";
+
+ case EOpEmitVertex:
+ return "EmitVertex";
+ case EOpEndPrimitive:
+ return "EndPrimitive";
+ default:
+ break;
+ }
+ return "";
+}
+
+bool IsAssignment(TOperator op)
+{
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpAssign:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IsAtomicFunction(TOperator op)
+{
+ switch (op)
+ {
+ case EOpAtomicAdd:
+ case EOpAtomicMin:
+ case EOpAtomicMax:
+ case EOpAtomicAnd:
+ case EOpAtomicOr:
+ case EOpAtomicXor:
+ case EOpAtomicExchange:
+ case EOpAtomicCompSwap:
+ return true;
+ default:
+ return false;
+ }
+} \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/Operator.h b/gfx/angle/checkout/src/compiler/translator/Operator.h
new file mode 100644
index 0000000000..e1540faa44
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Operator.h
@@ -0,0 +1,268 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_OPERATOR_H_
+#define COMPILER_TRANSLATOR_OPERATOR_H_
+
+//
+// Operators used by the high-level (parse tree) representation.
+//
+enum TOperator
+{
+ EOpNull, // if in a node, should only mean a node is still being built
+
+ // Call a function defined in the AST. This might be a user-defined function or a function
+ // inserted by an AST transformation.
+ EOpCallFunctionInAST,
+
+ // Call an internal helper function with a raw implementation - the implementation can't be
+ // subject to AST transformations. Raw functions have a few constraints to keep them compatible
+ // with AST traversers:
+ // * They should not return arrays.
+ // * They should not have out parameters.
+ EOpCallInternalRawFunction,
+
+ // Call a built-in function like a texture or image function.
+ EOpCallBuiltInFunction,
+
+ //
+ // Unary operators
+ //
+
+ EOpNegative,
+ EOpPositive,
+ EOpLogicalNot,
+ EOpBitwiseNot,
+
+ EOpPostIncrement,
+ EOpPostDecrement,
+ EOpPreIncrement,
+ EOpPreDecrement,
+
+ EOpArrayLength,
+
+ //
+ // binary operations (ones with special GLSL syntax are used in TIntermBinary nodes, others in
+ // TIntermAggregate nodes)
+ //
+
+ EOpAdd,
+ EOpSub,
+ EOpMul,
+ EOpDiv,
+ EOpIMod,
+
+ EOpEqual,
+ EOpNotEqual,
+ EOpLessThan,
+ EOpGreaterThan,
+ EOpLessThanEqual,
+ EOpGreaterThanEqual,
+
+ EOpEqualComponentWise,
+ EOpNotEqualComponentWise,
+ EOpLessThanComponentWise,
+ EOpLessThanEqualComponentWise,
+ EOpGreaterThanComponentWise,
+ EOpGreaterThanEqualComponentWise,
+
+ EOpComma,
+
+ EOpVectorTimesScalar,
+ EOpVectorTimesMatrix,
+ EOpMatrixTimesVector,
+ EOpMatrixTimesScalar,
+ EOpMatrixTimesMatrix,
+
+ EOpLogicalOr,
+ EOpLogicalXor,
+ EOpLogicalAnd,
+
+ EOpBitShiftLeft,
+ EOpBitShiftRight,
+
+ EOpBitwiseAnd,
+ EOpBitwiseXor,
+ EOpBitwiseOr,
+
+ EOpIndexDirect,
+ EOpIndexIndirect,
+ EOpIndexDirectStruct,
+ EOpIndexDirectInterfaceBlock,
+
+ //
+ // Built-in functions mapped to operators (either unary or with multiple parameters)
+ //
+
+ EOpRadians,
+ EOpDegrees,
+ EOpSin,
+ EOpCos,
+ EOpTan,
+ EOpAsin,
+ EOpAcos,
+ EOpAtan,
+
+ EOpSinh,
+ EOpCosh,
+ EOpTanh,
+ EOpAsinh,
+ EOpAcosh,
+ EOpAtanh,
+
+ EOpPow,
+ EOpExp,
+ EOpLog,
+ EOpExp2,
+ EOpLog2,
+ EOpSqrt,
+ EOpInversesqrt,
+
+ EOpAbs,
+ EOpSign,
+ EOpFloor,
+ EOpTrunc,
+ EOpRound,
+ EOpRoundEven,
+ EOpCeil,
+ EOpFract,
+ EOpMod,
+ EOpModf,
+ EOpMin,
+ EOpMax,
+ EOpClamp,
+ EOpMix,
+ EOpStep,
+ EOpSmoothstep,
+ EOpIsnan,
+ EOpIsinf,
+
+ EOpFloatBitsToInt,
+ EOpFloatBitsToUint,
+ EOpIntBitsToFloat,
+ EOpUintBitsToFloat,
+
+ EOpFrexp,
+ EOpLdexp,
+
+ EOpPackSnorm2x16,
+ EOpPackUnorm2x16,
+ EOpPackHalf2x16,
+ EOpUnpackSnorm2x16,
+ EOpUnpackUnorm2x16,
+ EOpUnpackHalf2x16,
+
+ EOpPackUnorm4x8,
+ EOpPackSnorm4x8,
+ EOpUnpackUnorm4x8,
+ EOpUnpackSnorm4x8,
+
+ EOpLength,
+ EOpDistance,
+ EOpDot,
+ EOpCross,
+ EOpNormalize,
+ EOpFaceforward,
+ EOpReflect,
+ EOpRefract,
+
+ EOpDFdx, // Fragment only, OES_standard_derivatives extension
+ EOpDFdy, // Fragment only, OES_standard_derivatives extension
+ EOpFwidth, // Fragment only, OES_standard_derivatives extension
+
+ EOpMulMatrixComponentWise,
+ EOpOuterProduct,
+ EOpTranspose,
+ EOpDeterminant,
+ EOpInverse,
+
+ EOpAny,
+ EOpAll,
+ EOpLogicalNotComponentWise,
+
+ EOpBitfieldExtract,
+ EOpBitfieldInsert,
+ EOpBitfieldReverse,
+ EOpBitCount,
+ EOpFindLSB,
+ EOpFindMSB,
+ EOpUaddCarry,
+ EOpUsubBorrow,
+ EOpUmulExtended,
+ EOpImulExtended,
+
+ //
+ // Branch
+ //
+
+ EOpKill, // Fragment only
+ EOpReturn,
+ EOpBreak,
+ EOpContinue,
+
+ //
+ // Constructor
+ //
+
+ EOpConstruct,
+
+ //
+ // moves
+ //
+
+ EOpAssign,
+ EOpInitialize,
+ EOpAddAssign,
+ EOpSubAssign,
+
+ EOpMulAssign,
+ EOpVectorTimesMatrixAssign,
+ EOpVectorTimesScalarAssign,
+ EOpMatrixTimesScalarAssign,
+ EOpMatrixTimesMatrixAssign,
+
+ EOpDivAssign,
+ EOpIModAssign,
+ EOpBitShiftLeftAssign,
+ EOpBitShiftRightAssign,
+ EOpBitwiseAndAssign,
+ EOpBitwiseXorAssign,
+ EOpBitwiseOrAssign,
+
+ // barriers
+ EOpBarrier,
+ EOpMemoryBarrier,
+ EOpMemoryBarrierAtomicCounter,
+ EOpMemoryBarrierBuffer,
+ EOpMemoryBarrierImage,
+ EOpMemoryBarrierShared,
+ EOpGroupMemoryBarrier,
+
+ // Atomic functions
+ EOpAtomicAdd,
+ EOpAtomicMin,
+ EOpAtomicMax,
+ EOpAtomicAnd,
+ EOpAtomicOr,
+ EOpAtomicXor,
+ EOpAtomicExchange,
+ EOpAtomicCompSwap,
+
+ // Geometry only
+ EOpEmitVertex,
+ EOpEndPrimitive
+};
+
+// Returns the string corresponding to the operator in GLSL
+const char *GetOperatorString(TOperator op);
+
+// Say whether or not a binary or unary operation changes the value of a variable.
+bool IsAssignment(TOperator op);
+
+// Say whether or not an operator represents an atomic function.
+bool IsAtomicFunction(TOperator op);
+
+#endif // COMPILER_TRANSLATOR_OPERATOR_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp b/gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp
new file mode 100644
index 0000000000..8d57eeae84
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp
@@ -0,0 +1,46 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputESSL.h"
+
+namespace sh
+{
+
+TOutputESSL::TOutputESSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ bool forceHighp,
+ ShCompileOptions compileOptions)
+ : TOutputGLSLBase(objSink,
+ clampingStrategy,
+ hashFunction,
+ nameMap,
+ symbolTable,
+ shaderType,
+ shaderVersion,
+ SH_ESSL_OUTPUT,
+ compileOptions),
+ mForceHighp(forceHighp)
+{}
+
+bool TOutputESSL::writeVariablePrecision(TPrecision precision)
+{
+ if (precision == EbpUndefined)
+ return false;
+
+ TInfoSinkBase &out = objSink();
+ if (mForceHighp)
+ out << getPrecisionString(EbpHigh);
+ else
+ out << getPrecisionString(precision);
+ return true;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputESSL.h b/gfx/angle/checkout/src/compiler/translator/OutputESSL.h
new file mode 100644
index 0000000000..e0c7bf2ae6
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputESSL.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_OUTPUTESSL_H_
+#define COMPILER_TRANSLATOR_OUTPUTESSL_H_
+
+#include "compiler/translator/OutputGLSLBase.h"
+
+namespace sh
+{
+
+class TOutputESSL : public TOutputGLSLBase
+{
+ public:
+ TOutputESSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ bool forceHighp,
+ ShCompileOptions compileOptions);
+
+ protected:
+ bool writeVariablePrecision(TPrecision precision) override;
+
+ private:
+ bool mForceHighp;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp
new file mode 100644
index 0000000000..ced5020ba3
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp
@@ -0,0 +1,118 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputGLSL.h"
+
+#include "compiler/translator/Compiler.h"
+
+namespace sh
+{
+
+TOutputGLSL::TOutputGLSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput output,
+ ShCompileOptions compileOptions)
+ : TOutputGLSLBase(objSink,
+ clampingStrategy,
+ hashFunction,
+ nameMap,
+ symbolTable,
+ shaderType,
+ shaderVersion,
+ output,
+ compileOptions)
+{}
+
+bool TOutputGLSL::writeVariablePrecision(TPrecision)
+{
+ return false;
+}
+
+void TOutputGLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ // All the special cases are built-ins, so if it's not a built-in we can return early.
+ if (node->variable().symbolType() != SymbolType::BuiltIn)
+ {
+ TOutputGLSLBase::visitSymbol(node);
+ return;
+ }
+
+ // Some built-ins get a special translation.
+ const ImmutableString &name = node->getName();
+ if (name == "gl_FragDepthEXT")
+ {
+ out << "gl_FragDepth";
+ }
+ else if (name == "gl_FragColor" && sh::IsGLSL130OrNewer(getShaderOutput()))
+ {
+ out << "webgl_FragColor";
+ }
+ else if (name == "gl_FragData" && sh::IsGLSL130OrNewer(getShaderOutput()))
+ {
+ out << "webgl_FragData";
+ }
+ else if (name == "gl_SecondaryFragColorEXT")
+ {
+ out << "angle_SecondaryFragColor";
+ }
+ else if (name == "gl_SecondaryFragDataEXT")
+ {
+ out << "angle_SecondaryFragData";
+ }
+ else
+ {
+ TOutputGLSLBase::visitSymbol(node);
+ }
+}
+
+ImmutableString TOutputGLSL::translateTextureFunction(const ImmutableString &name)
+{
+ static const char *simpleRename[] = {"texture2DLodEXT",
+ "texture2DLod",
+ "texture2DProjLodEXT",
+ "texture2DProjLod",
+ "textureCubeLodEXT",
+ "textureCubeLod",
+ "texture2DGradEXT",
+ "texture2DGradARB",
+ "texture2DProjGradEXT",
+ "texture2DProjGradARB",
+ "textureCubeGradEXT",
+ "textureCubeGradARB",
+ nullptr,
+ nullptr};
+ static const char *legacyToCoreRename[] = {
+ "texture2D", "texture", "texture2DProj", "textureProj", "texture2DLod", "textureLod",
+ "texture2DProjLod", "textureProjLod", "texture2DRect", "texture", "texture2DRectProj",
+ "textureProj", "textureCube", "texture", "textureCubeLod", "textureLod",
+ // Extensions
+ "texture2DLodEXT", "textureLod", "texture2DProjLodEXT", "textureProjLod",
+ "textureCubeLodEXT", "textureLod", "texture2DGradEXT", "textureGrad",
+ "texture2DProjGradEXT", "textureProjGrad", "textureCubeGradEXT", "textureGrad", "texture3D",
+ "texture", "texture3DProj", "textureProj", "texture3DLod", "textureLod", "texture3DProjLod",
+ "textureProjLod", nullptr, nullptr};
+ const char **mapping =
+ (sh::IsGLSL130OrNewer(getShaderOutput())) ? legacyToCoreRename : simpleRename;
+
+ for (int i = 0; mapping[i] != nullptr; i += 2)
+ {
+ if (name == mapping[i])
+ {
+ return ImmutableString(mapping[i + 1]);
+ }
+ }
+
+ return name;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSL.h b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.h
new file mode 100644
index 0000000000..b676a79932
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.h
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_OUTPUTGLSL_H_
+#define COMPILER_TRANSLATOR_OUTPUTGLSL_H_
+
+#include "compiler/translator/OutputGLSLBase.h"
+
+namespace sh
+{
+
+class TOutputGLSL : public TOutputGLSLBase
+{
+ public:
+ TOutputGLSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput output,
+ ShCompileOptions compileOptions);
+
+ protected:
+ bool writeVariablePrecision(TPrecision) override;
+ void visitSymbol(TIntermSymbol *node) override;
+ ImmutableString translateTextureFunction(const ImmutableString &name) override;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_OUTPUTGLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp
new file mode 100644
index 0000000000..eb830612ff
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp
@@ -0,0 +1,1433 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputGLSLBase.h"
+
+#include "angle_gl.h"
+#include "common/debug.h"
+#include "common/mathutil.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/util.h"
+
+#include <cfloat>
+
+namespace sh
+{
+
+namespace
+{
+
+bool isSingleStatement(TIntermNode *node)
+{
+ if (node->getAsFunctionDefinition())
+ {
+ return false;
+ }
+ else if (node->getAsBlock())
+ {
+ return false;
+ }
+ else if (node->getAsIfElseNode())
+ {
+ return false;
+ }
+ else if (node->getAsLoopNode())
+ {
+ return false;
+ }
+ else if (node->getAsSwitchNode())
+ {
+ return false;
+ }
+ else if (node->getAsCaseNode())
+ {
+ return false;
+ }
+ else if (node->getAsPreprocessorDirective())
+ {
+ return false;
+ }
+ return true;
+}
+
+class CommaSeparatedListItemPrefixGenerator
+{
+ public:
+ CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
+
+ private:
+ bool mFirst;
+
+ template <typename Stream>
+ friend Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen);
+};
+
+template <typename Stream>
+Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen)
+{
+ if (gen.mFirst)
+ {
+ gen.mFirst = false;
+ }
+ else
+ {
+ out << ", ";
+ }
+ return out;
+}
+
+} // namespace
+
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput output,
+ ShCompileOptions compileOptions)
+ : TIntermTraverser(true, true, true, symbolTable),
+ mObjSink(objSink),
+ mDeclaringVariable(false),
+ mClampingStrategy(clampingStrategy),
+ mHashFunction(hashFunction),
+ mNameMap(nameMap),
+ mShaderType(shaderType),
+ mShaderVersion(shaderVersion),
+ mOutput(output),
+ mCompileOptions(compileOptions)
+{}
+
+void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
+{
+ if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
+ {
+ TInfoSinkBase &out = objSink();
+ out << "invariant ";
+ }
+}
+
+void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
+{
+ if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
+ {
+ out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
+ }
+ else
+ {
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
+ }
+}
+
+void TOutputGLSLBase::writeTriplet(Visit visit,
+ const char *preStr,
+ const char *inStr,
+ const char *postStr)
+{
+ TInfoSinkBase &out = objSink();
+ if (visit == PreVisit && preStr)
+ out << preStr;
+ else if (visit == InVisit && inStr)
+ out << inStr;
+ else if (visit == PostVisit && postStr)
+ out << postStr;
+}
+
+void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
+ TOperator op,
+ bool useEmulatedFunction)
+{
+ TInfoSinkBase &out = objSink();
+ if (visit == PreVisit)
+ {
+ const char *opStr(GetOperatorString(op));
+ if (useEmulatedFunction)
+ {
+ BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
+ }
+ else
+ {
+ out << opStr;
+ }
+ out << "(";
+ }
+ else
+ {
+ writeTriplet(visit, nullptr, ", ", ")");
+ }
+}
+
+// Outputs what goes inside layout(), except for location and binding qualifiers, as they are
+// handled differently between GL GLSL and Vulkan GLSL.
+std::string TOutputGLSLBase::getCommonLayoutQualifiers(TIntermTyped *variable)
+{
+ std::ostringstream out;
+ CommaSeparatedListItemPrefixGenerator listItemPrefix;
+
+ const TType &type = variable->getType();
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+
+ if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
+ IsVarying(type.getQualifier()))
+ {
+ if (type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0)
+ {
+ out << listItemPrefix << "index = " << layoutQualifier.index;
+ }
+ }
+
+ if (type.getQualifier() == EvqFragmentOut)
+ {
+ if (layoutQualifier.yuv == true)
+ {
+ out << listItemPrefix << "yuv";
+ }
+ }
+
+ if (IsImage(type.getBasicType()))
+ {
+ if (layoutQualifier.imageInternalFormat != EiifUnspecified)
+ {
+ ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
+ out << listItemPrefix
+ << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
+ }
+ }
+
+ if (IsAtomicCounter(type.getBasicType()))
+ {
+ out << listItemPrefix << "offset = " << layoutQualifier.offset;
+ }
+
+ return out.str();
+}
+
+// Outputs what comes after in/out/uniform/buffer storage qualifier.
+std::string TOutputGLSLBase::getMemoryQualifiers(const TType &type)
+{
+ std::ostringstream out;
+
+ const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
+ if (memoryQualifier.readonly)
+ {
+ ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier()));
+ out << "readonly ";
+ }
+
+ if (memoryQualifier.writeonly)
+ {
+ ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier()));
+ out << "writeonly ";
+ }
+
+ if (memoryQualifier.coherent)
+ {
+ ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier()));
+ out << "coherent ";
+ }
+
+ if (memoryQualifier.restrictQualifier)
+ {
+ ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier()));
+ out << "restrict ";
+ }
+
+ if (memoryQualifier.volatileQualifier)
+ {
+ ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier()));
+ out << "volatile ";
+ }
+
+ return out.str();
+}
+
+void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable)
+{
+ const TType &type = variable->getType();
+
+ if (!NeedsToWriteLayoutQualifier(type))
+ {
+ return;
+ }
+
+ if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ declareInterfaceBlockLayout(interfaceBlock);
+ return;
+ }
+
+ TInfoSinkBase &out = objSink();
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+ out << "layout(";
+
+ CommaSeparatedListItemPrefixGenerator listItemPrefix;
+
+ if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
+ IsVarying(type.getQualifier()))
+ {
+ if (layoutQualifier.location >= 0)
+ {
+ out << listItemPrefix << "location = " << layoutQualifier.location;
+ }
+ }
+
+ if (IsOpaqueType(type.getBasicType()))
+ {
+ if (layoutQualifier.binding >= 0)
+ {
+ out << listItemPrefix << "binding = " << layoutQualifier.binding;
+ }
+ }
+
+ std::string otherQualifiers = getCommonLayoutQualifiers(variable);
+ if (!otherQualifiers.empty())
+ {
+ out << listItemPrefix << otherQualifiers;
+ }
+
+ out << ") ";
+}
+
+void TOutputGLSLBase::writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol)
+{
+ const char *result = mapQualifierToString(qualifier);
+ if (result && result[0] != '\0')
+ {
+ objSink() << result << " ";
+ }
+
+ objSink() << getMemoryQualifiers(type);
+}
+
+const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
+{
+ if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
+ (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
+ {
+ switch (qualifier)
+ {
+ // The return string is consistent with sh::getQualifierString() from
+ // BaseTypes.h minus the "centroid" keyword.
+ case EvqCentroid:
+ return "";
+ case EvqCentroidIn:
+ return "smooth in";
+ case EvqCentroidOut:
+ return "smooth out";
+ default:
+ break;
+ }
+ }
+ if (sh::IsGLSL130OrNewer(mOutput))
+ {
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ return "in";
+ case EvqVaryingIn:
+ return "in";
+ case EvqVaryingOut:
+ return "out";
+ default:
+ break;
+ }
+ }
+ return sh::getQualifierString(qualifier);
+}
+
+void TOutputGLSLBase::writeVariableType(const TType &type, const TSymbol *symbol)
+{
+ TQualifier qualifier = type.getQualifier();
+ TInfoSinkBase &out = objSink();
+ if (type.isInvariant())
+ {
+ writeInvariantQualifier(type);
+ }
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ {
+ writeQualifier(qualifier, type, symbol);
+ }
+
+ // Declare the struct if we have not done so already.
+ if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
+ {
+ const TStructure *structure = type.getStruct();
+
+ declareStruct(structure);
+ }
+ else if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ declareInterfaceBlock(interfaceBlock);
+ }
+ else
+ {
+ if (writeVariablePrecision(type.getPrecision()))
+ out << " ";
+ out << getTypeName(type);
+ }
+}
+
+void TOutputGLSLBase::writeFunctionParameters(const TFunction *func)
+{
+ TInfoSinkBase &out = objSink();
+ size_t paramCount = func->getParamCount();
+ for (size_t i = 0; i < paramCount; ++i)
+ {
+ const TVariable *param = func->getParam(i);
+ const TType &type = param->getType();
+ writeVariableType(type, param);
+
+ if (param->symbolType() != SymbolType::Empty)
+ out << " " << hashName(param);
+ if (type.isArray())
+ out << ArrayString(type);
+
+ // Put a comma if this is not the last argument.
+ if (i != paramCount - 1)
+ out << ", ";
+ }
+}
+
+const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
+ const TConstantUnion *pConstUnion)
+{
+ TInfoSinkBase &out = objSink();
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ const TStructure *structure = type.getStruct();
+ out << hashName(structure) << "(";
+
+ const TFieldList &fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TType *fieldType = fields[i]->type();
+ ASSERT(fieldType != nullptr);
+ pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
+ if (i != fields.size() - 1)
+ out << ", ";
+ }
+ out << ")";
+ }
+ else
+ {
+ size_t size = type.getObjectSize();
+ bool writeType = size > 1;
+ if (writeType)
+ out << getTypeName(type) << "(";
+ for (size_t i = 0; i < size; ++i, ++pConstUnion)
+ {
+ switch (pConstUnion->getType())
+ {
+ case EbtFloat:
+ writeFloat(out, pConstUnion->getFConst());
+ break;
+ case EbtInt:
+ out << pConstUnion->getIConst();
+ break;
+ case EbtUInt:
+ out << pConstUnion->getUConst() << "u";
+ break;
+ case EbtBool:
+ out << pConstUnion->getBConst();
+ break;
+ case EbtYuvCscStandardEXT:
+ out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ if (i != size - 1)
+ out << ", ";
+ }
+ if (writeType)
+ out << ")";
+ }
+ return pConstUnion;
+}
+
+void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
+{
+ TInfoSinkBase &out = objSink();
+ if (visit == PreVisit)
+ {
+ if (type.isArray())
+ {
+ out << getTypeName(type);
+ out << ArrayString(type);
+ out << "(";
+ }
+ else
+ {
+ out << getTypeName(type) << "(";
+ }
+ }
+ else
+ {
+ writeTriplet(visit, nullptr, ", ", ")");
+ }
+}
+
+void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = objSink();
+ out << hashName(&node->variable());
+
+ if (mDeclaringVariable && node->getType().isArray())
+ out << ArrayString(node->getType());
+}
+
+void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getConstantValue());
+}
+
+bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+ TInfoSinkBase &out = objSink();
+ if (visit == PostVisit)
+ {
+ out << ".";
+ node->writeOffsetsAsXYZW(&out);
+ }
+ return true;
+}
+
+bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase &out = objSink();
+ switch (node->getOp())
+ {
+ case EOpComma:
+ writeTriplet(visit, "(", ", ", ")");
+ break;
+ case EOpInitialize:
+ if (visit == InVisit)
+ {
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariable = false;
+ }
+ break;
+ case EOpAssign:
+ writeTriplet(visit, "(", " = ", ")");
+ break;
+ case EOpAddAssign:
+ writeTriplet(visit, "(", " += ", ")");
+ break;
+ case EOpSubAssign:
+ writeTriplet(visit, "(", " -= ", ")");
+ break;
+ case EOpDivAssign:
+ writeTriplet(visit, "(", " /= ", ")");
+ break;
+ case EOpIModAssign:
+ writeTriplet(visit, "(", " %= ", ")");
+ break;
+ // Notice the fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ writeTriplet(visit, "(", " *= ", ")");
+ break;
+ case EOpBitShiftLeftAssign:
+ writeTriplet(visit, "(", " <<= ", ")");
+ break;
+ case EOpBitShiftRightAssign:
+ writeTriplet(visit, "(", " >>= ", ")");
+ break;
+ case EOpBitwiseAndAssign:
+ writeTriplet(visit, "(", " &= ", ")");
+ break;
+ case EOpBitwiseXorAssign:
+ writeTriplet(visit, "(", " ^= ", ")");
+ break;
+ case EOpBitwiseOrAssign:
+ writeTriplet(visit, "(", " |= ", ")");
+ break;
+
+ case EOpIndexDirect:
+ writeTriplet(visit, nullptr, "[", "]");
+ break;
+ case EOpIndexIndirect:
+ if (node->getAddIndexClamp())
+ {
+ if (visit == InVisit)
+ {
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "[int(clamp(float(";
+ else
+ out << "[webgl_int_clamp(";
+ }
+ else if (visit == PostVisit)
+ {
+ TIntermTyped *left = node->getLeft();
+ TType leftType = left->getType();
+
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "), 0.0, float(";
+ else
+ out << ", 0, ";
+
+ if (leftType.isUnsizedArray())
+ {
+ // For runtime-sized arrays in ESSL 3.10 we need to call the length method
+ // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note
+ // that a runtime-sized array expression is guaranteed not to have side
+ // effects, so it's fine to add the expression to the output twice.
+ ASSERT(mShaderVersion >= 310);
+ ASSERT(!left->hasSideEffects());
+ left->traverse(this);
+ out << ".length() - 1";
+ }
+ else
+ {
+ int maxSize;
+ if (leftType.isArray())
+ {
+ maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
+ }
+ else
+ {
+ maxSize = leftType.getNominalSize() - 1;
+ }
+ out << maxSize;
+ }
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << ")))]";
+ else
+ out << ")]";
+ }
+ }
+ else
+ {
+ writeTriplet(visit, nullptr, "[", "]");
+ }
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ // Here we are writing out "foo.bar", where "foo" is struct
+ // and "bar" is field. In AST, it is represented as a binary
+ // node, where left child represents "foo" and right child "bar".
+ // The node itself represents ".". The struct field "bar" is
+ // actually stored as an index into TStructure::fields.
+ out << ".";
+ const TStructure *structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+
+ out << hashFieldName(field);
+ visitChildren = false;
+ }
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ if (visit == InVisit)
+ {
+ out << ".";
+ const TInterfaceBlock *interfaceBlock =
+ node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+ out << hashFieldName(field);
+ visitChildren = false;
+ }
+ break;
+
+ case EOpAdd:
+ writeTriplet(visit, "(", " + ", ")");
+ break;
+ case EOpSub:
+ writeTriplet(visit, "(", " - ", ")");
+ break;
+ case EOpMul:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+ case EOpDiv:
+ writeTriplet(visit, "(", " / ", ")");
+ break;
+ case EOpIMod:
+ writeTriplet(visit, "(", " % ", ")");
+ break;
+ case EOpBitShiftLeft:
+ writeTriplet(visit, "(", " << ", ")");
+ break;
+ case EOpBitShiftRight:
+ writeTriplet(visit, "(", " >> ", ")");
+ break;
+ case EOpBitwiseAnd:
+ writeTriplet(visit, "(", " & ", ")");
+ break;
+ case EOpBitwiseXor:
+ writeTriplet(visit, "(", " ^ ", ")");
+ break;
+ case EOpBitwiseOr:
+ writeTriplet(visit, "(", " | ", ")");
+ break;
+
+ case EOpEqual:
+ writeTriplet(visit, "(", " == ", ")");
+ break;
+ case EOpNotEqual:
+ writeTriplet(visit, "(", " != ", ")");
+ break;
+ case EOpLessThan:
+ writeTriplet(visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThan:
+ writeTriplet(visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqual:
+ writeTriplet(visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqual:
+ writeTriplet(visit, "(", " >= ", ")");
+ break;
+
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+
+ case EOpLogicalOr:
+ writeTriplet(visit, "(", " || ", ")");
+ break;
+ case EOpLogicalXor:
+ writeTriplet(visit, "(", " ^^ ", ")");
+ break;
+ case EOpLogicalAnd:
+ writeTriplet(visit, "(", " && ", ")");
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
+{
+ const char *preString = "";
+ const char *postString = ")";
+
+ switch (node->getOp())
+ {
+ case EOpNegative:
+ preString = "(-";
+ break;
+ case EOpPositive:
+ preString = "(+";
+ break;
+ case EOpLogicalNot:
+ preString = "(!";
+ break;
+ case EOpBitwiseNot:
+ preString = "(~";
+ break;
+
+ case EOpPostIncrement:
+ preString = "(";
+ postString = "++)";
+ break;
+ case EOpPostDecrement:
+ preString = "(";
+ postString = "--)";
+ break;
+ case EOpPreIncrement:
+ preString = "(++";
+ break;
+ case EOpPreDecrement:
+ preString = "(--";
+ break;
+ case EOpArrayLength:
+ preString = "((";
+ postString = ").length())";
+ break;
+
+ case EOpRadians:
+ case EOpDegrees:
+ case EOpSin:
+ case EOpCos:
+ case EOpTan:
+ case EOpAsin:
+ case EOpAcos:
+ case EOpAtan:
+ case EOpSinh:
+ case EOpCosh:
+ case EOpTanh:
+ case EOpAsinh:
+ case EOpAcosh:
+ case EOpAtanh:
+ case EOpExp:
+ case EOpLog:
+ case EOpExp2:
+ case EOpLog2:
+ case EOpSqrt:
+ case EOpInversesqrt:
+ case EOpAbs:
+ case EOpSign:
+ case EOpFloor:
+ case EOpTrunc:
+ case EOpRound:
+ case EOpRoundEven:
+ case EOpCeil:
+ case EOpFract:
+ case EOpIsnan:
+ case EOpIsinf:
+ case EOpFloatBitsToInt:
+ case EOpFloatBitsToUint:
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpUnpackHalf2x16:
+ case EOpPackUnorm4x8:
+ case EOpPackSnorm4x8:
+ case EOpUnpackUnorm4x8:
+ case EOpUnpackSnorm4x8:
+ case EOpLength:
+ case EOpNormalize:
+ case EOpDFdx:
+ case EOpDFdy:
+ case EOpFwidth:
+ case EOpTranspose:
+ case EOpDeterminant:
+ case EOpInverse:
+ case EOpAny:
+ case EOpAll:
+ case EOpLogicalNotComponentWise:
+ case EOpBitfieldReverse:
+ case EOpBitCount:
+ case EOpFindLSB:
+ case EOpFindMSB:
+ writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
+ return true;
+ default:
+ UNREACHABLE();
+ }
+
+ writeTriplet(visit, preString, nullptr, postString);
+
+ return true;
+}
+
+bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
+{
+ TInfoSinkBase &out = objSink();
+ // Notice two brackets at the beginning and end. The outer ones
+ // encapsulate the whole ternary expression. This preserves the
+ // order of precedence when ternary expressions are used in a
+ // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
+ out << "((";
+ node->getCondition()->traverse(this);
+ out << ") ? (";
+ node->getTrueExpression()->traverse(this);
+ out << ") : (";
+ node->getFalseExpression()->traverse(this);
+ out << "))";
+ return false;
+}
+
+bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ ASSERT(node->getStatementList());
+ writeTriplet(visit, "switch (", ") ", nullptr);
+ // The curly braces get written when visiting the statementList aggregate
+ return true;
+}
+
+bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
+{
+ if (node->hasCondition())
+ {
+ writeTriplet(visit, "case (", nullptr, "):\n");
+ return true;
+ }
+ else
+ {
+ TInfoSinkBase &out = objSink();
+ out << "default:\n";
+ return false;
+ }
+}
+
+bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
+{
+ TInfoSinkBase &out = objSink();
+ // Scope the blocks except when at the global scope.
+ if (getCurrentTraversalDepth() > 0)
+ {
+ out << "{\n";
+ }
+
+ for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
+ iter != node->getSequence()->end(); ++iter)
+ {
+ TIntermNode *curNode = *iter;
+ ASSERT(curNode != nullptr);
+ curNode->traverse(this);
+
+ if (isSingleStatement(curNode))
+ out << ";\n";
+ }
+
+ // Scope the blocks except when at the global scope.
+ if (getCurrentTraversalDepth() > 0)
+ {
+ out << "}\n";
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
+ prototype->traverse(this);
+ visitCodeBlock(node->getBody());
+
+ // Fully processed; no need to visit children.
+ return false;
+}
+
+bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+ TInfoSinkBase &out = objSink();
+ ASSERT(visit == PreVisit);
+ const TIntermSymbol *symbol = node->getSymbol();
+ out << "invariant " << hashName(&symbol->variable());
+ return false;
+}
+
+void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ const TType &type = node->getType();
+ writeVariableType(type, node->getFunction());
+ if (type.isArray())
+ out << ArrayString(type);
+
+ out << " " << hashFunctionNameIfNeeded(node->getFunction());
+
+ out << "(";
+ writeFunctionParameters(node->getFunction());
+ out << ")";
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase &out = objSink();
+ switch (node->getOp())
+ {
+ case EOpCallFunctionInAST:
+ case EOpCallInternalRawFunction:
+ case EOpCallBuiltInFunction:
+ // Function call.
+ if (visit == PreVisit)
+ {
+ if (node->getOp() == EOpCallBuiltInFunction)
+ {
+ out << translateTextureFunction(node->getFunction()->name());
+ }
+ else
+ {
+ out << hashFunctionNameIfNeeded(node->getFunction());
+ }
+ out << "(";
+ }
+ else if (visit == InVisit)
+ out << ", ";
+ else
+ out << ")";
+ break;
+ case EOpConstruct:
+ writeConstructorTriplet(visit, node->getType());
+ break;
+
+ case EOpEqualComponentWise:
+ case EOpNotEqualComponentWise:
+ case EOpLessThanComponentWise:
+ case EOpGreaterThanComponentWise:
+ case EOpLessThanEqualComponentWise:
+ case EOpGreaterThanEqualComponentWise:
+ case EOpMod:
+ case EOpModf:
+ case EOpPow:
+ case EOpAtan:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothstep:
+ case EOpFrexp:
+ case EOpLdexp:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceforward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpMulMatrixComponentWise:
+ case EOpOuterProduct:
+ case EOpBitfieldExtract:
+ case EOpBitfieldInsert:
+ case EOpUaddCarry:
+ case EOpUsubBorrow:
+ case EOpUmulExtended:
+ case EOpImulExtended:
+ case EOpBarrier:
+ case EOpMemoryBarrier:
+ case EOpMemoryBarrierAtomicCounter:
+ case EOpMemoryBarrierBuffer:
+ case EOpMemoryBarrierImage:
+ case EOpMemoryBarrierShared:
+ case EOpGroupMemoryBarrier:
+ case EOpAtomicAdd:
+ case EOpAtomicMin:
+ case EOpAtomicMax:
+ case EOpAtomicAnd:
+ case EOpAtomicOr:
+ case EOpAtomicXor:
+ case EOpAtomicExchange:
+ case EOpAtomicCompSwap:
+ case EOpEmitVertex:
+ case EOpEndPrimitive:
+ writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ TIntermTyped *variable = sequence.front()->getAsTyped();
+ writeLayoutQualifier(variable);
+ TIntermSymbol *symbolNode = variable->getAsSymbolNode();
+ writeVariableType(variable->getType(), symbolNode ? &symbolNode->variable() : nullptr);
+ if (variable->getAsSymbolNode() == nullptr ||
+ variable->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty)
+ {
+ out << " ";
+ }
+ mDeclaringVariable = true;
+ }
+ else if (visit == InVisit)
+ {
+ UNREACHABLE();
+ }
+ else
+ {
+ mDeclaringVariable = false;
+ }
+ return true;
+}
+
+bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ TLoopType loopType = node->getType();
+
+ if (loopType == ELoopFor) // for loop
+ {
+ out << "for (";
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ out << "; ";
+
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+ out << "; ";
+
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+ out << ")\n";
+
+ visitCodeBlock(node->getBody());
+ }
+ else if (loopType == ELoopWhile) // while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != nullptr);
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ visitCodeBlock(node->getBody());
+ }
+ else // do-while loop
+ {
+ ASSERT(loopType == ELoopDoWhile);
+ out << "do\n";
+
+ visitCodeBlock(node->getBody());
+
+ out << "while (";
+ ASSERT(node->getCondition() != nullptr);
+ node->getCondition()->traverse(this);
+ out << ");\n";
+ }
+
+ // No need to visit children. They have been already processed in
+ // this function.
+ return false;
+}
+
+bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
+{
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ writeTriplet(visit, "discard", nullptr, nullptr);
+ break;
+ case EOpBreak:
+ writeTriplet(visit, "break", nullptr, nullptr);
+ break;
+ case EOpContinue:
+ writeTriplet(visit, "continue", nullptr, nullptr);
+ break;
+ case EOpReturn:
+ writeTriplet(visit, "return ", nullptr, nullptr);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
+{
+ TInfoSinkBase &out = objSink();
+ if (node != nullptr)
+ {
+ node->traverse(this);
+ // Single statements not part of a sequence need to be terminated
+ // with semi-colon.
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ else
+ {
+ out << "{\n}\n"; // Empty code block.
+ }
+}
+
+void TOutputGLSLBase::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "\n";
+
+ switch (node->getDirective())
+ {
+ case PreprocessorDirective::Define:
+ out << "#define";
+ break;
+ case PreprocessorDirective::Endif:
+ out << "#endif";
+ break;
+ case PreprocessorDirective::If:
+ out << "#if";
+ break;
+ case PreprocessorDirective::Ifdef:
+ out << "#ifdef";
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ if (!node->getCommand().empty())
+ {
+ out << " " << node->getCommand();
+ }
+
+ out << "\n";
+}
+
+ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
+{
+ return GetTypeName(type, mHashFunction, &mNameMap);
+}
+
+ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
+{
+ return HashName(symbol, mHashFunction, &mNameMap);
+}
+
+ImmutableString TOutputGLSLBase::hashFieldName(const TField *field)
+{
+ ASSERT(field->symbolType() != SymbolType::Empty);
+ if (field->symbolType() == SymbolType::UserDefined)
+ {
+ return HashName(field->name(), mHashFunction, &mNameMap);
+ }
+
+ return field->name();
+}
+
+ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
+{
+ if (func->isMain())
+ {
+ return func->name();
+ }
+ else
+ {
+ return hashName(func);
+ }
+}
+
+bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
+{
+ ASSERT(structure);
+ if (structure->symbolType() == SymbolType::Empty)
+ {
+ return false;
+ }
+
+ return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
+}
+
+void TOutputGLSLBase::declareStruct(const TStructure *structure)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "struct ";
+
+ if (structure->symbolType() != SymbolType::Empty)
+ {
+ out << hashName(structure) << " ";
+ }
+ out << "{\n";
+ const TFieldList &fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TField *field = fields[i];
+ if (writeVariablePrecision(field->type()->getPrecision()))
+ out << " ";
+ out << getTypeName(*field->type()) << " " << hashFieldName(field);
+ if (field->type()->isArray())
+ out << ArrayString(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+
+ if (structure->symbolType() != SymbolType::Empty)
+ {
+ mDeclaredStructs.insert(structure->uniqueId().get());
+ }
+}
+
+void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "layout(";
+
+ switch (interfaceBlock->blockStorage())
+ {
+ case EbsUnspecified:
+ case EbsShared:
+ // Default block storage is shared.
+ out << "shared";
+ break;
+
+ case EbsPacked:
+ out << "packed";
+ break;
+
+ case EbsStd140:
+ out << "std140";
+ break;
+
+ case EbsStd430:
+ out << "std430";
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ if (interfaceBlock->blockBinding() >= 0)
+ {
+ out << ", ";
+ out << "binding = " << interfaceBlock->blockBinding();
+ }
+
+ out << ") ";
+}
+
+void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << hashName(interfaceBlock) << "{\n";
+ const TFieldList &fields = interfaceBlock->fields();
+ for (const TField *field : fields)
+ {
+ if (field->type()->isMatrix() || field->type()->isStructureContainingMatrices())
+ {
+ out << "layout(";
+ switch (field->type()->getLayoutQualifier().matrixPacking)
+ {
+ case EmpUnspecified:
+ case EmpColumnMajor:
+ // Default matrix packing is column major.
+ out << "column_major";
+ break;
+
+ case EmpRowMajor:
+ out << "row_major";
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ out << ") ";
+ }
+
+ if (writeVariablePrecision(field->type()->getPrecision()))
+ out << " ";
+ out << getTypeName(*field->type()) << " " << hashFieldName(field);
+ if (field->type()->isArray())
+ out << ArrayString(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+}
+
+void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
+ sh::TLayoutPrimitiveType inputPrimitive,
+ int invocations,
+ sh::TLayoutPrimitiveType outputPrimitive,
+ int maxVertices)
+{
+ // Omit 'invocations = 1'
+ if (inputPrimitive != EptUndefined || invocations > 1)
+ {
+ out << "layout (";
+
+ if (inputPrimitive != EptUndefined)
+ {
+ out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
+ }
+
+ if (invocations > 1)
+ {
+ if (inputPrimitive != EptUndefined)
+ {
+ out << ", ";
+ }
+ out << "invocations = " << invocations;
+ }
+ out << ") in;\n";
+ }
+
+ if (outputPrimitive != EptUndefined || maxVertices != -1)
+ {
+ out << "layout (";
+
+ if (outputPrimitive != EptUndefined)
+ {
+ out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
+ }
+
+ if (maxVertices != -1)
+ {
+ if (outputPrimitive != EptUndefined)
+ {
+ out << ", ";
+ }
+ out << "max_vertices = " << maxVertices;
+ }
+ out << ") out;\n";
+ }
+}
+
+// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
+// variables with specified layout qualifiers are copied. Additional checks are needed against the
+// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
+// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
+// NeedsToWriteLayoutQualifier.
+bool NeedsToWriteLayoutQualifier(const TType &type)
+{
+ if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ return true;
+ }
+
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+
+ if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
+ IsVarying(type.getQualifier())) &&
+ layoutQualifier.location >= 0)
+ {
+ return true;
+ }
+
+ if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
+ {
+ return true;
+ }
+
+ if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
+ {
+ return true;
+ }
+
+ if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
+ {
+ return true;
+ }
+ return false;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h
new file mode 100644
index 0000000000..d6f9416f33
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h
@@ -0,0 +1,125 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
+#define COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
+
+#include <set>
+
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+class TOutputGLSLBase : public TIntermTraverser
+{
+ public:
+ TOutputGLSLBase(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput output,
+ ShCompileOptions compileOptions);
+
+ ShShaderOutput getShaderOutput() const { return mOutput; }
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name. Has special handling for internal names and built-ins,
+ // which are not hashed.
+ ImmutableString hashName(const TSymbol *symbol);
+
+ protected:
+ TInfoSinkBase &objSink() { return mObjSink; }
+ void writeFloat(TInfoSinkBase &out, float f);
+ void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
+ std::string getCommonLayoutQualifiers(TIntermTyped *variable);
+ std::string getMemoryQualifiers(const TType &type);
+ virtual void writeLayoutQualifier(TIntermTyped *variable);
+ void writeInvariantQualifier(const TType &type);
+ virtual void writeVariableType(const TType &type, const TSymbol *symbol);
+ virtual bool writeVariablePrecision(TPrecision precision) = 0;
+ void writeFunctionParameters(const TFunction *func);
+ const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion);
+ void writeConstructorTriplet(Visit visit, const TType &type);
+ ImmutableString getTypeName(const TType &type);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+ bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+ bool visitIfElse(Visit visit, TIntermIfElse *node) override;
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+ bool visitCase(Visit visit, TIntermCase *node) override;
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *node) override;
+ bool visitBranch(Visit visit, TIntermBranch *node) override;
+ void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override;
+
+ void visitCodeBlock(TIntermBlock *node);
+
+ ImmutableString hashFieldName(const TField *field);
+ // Same as hashName(), but without hashing "main".
+ ImmutableString hashFunctionNameIfNeeded(const TFunction *func);
+ // Used to translate function names for differences between ESSL and GLSL
+ virtual ImmutableString translateTextureFunction(const ImmutableString &name) { return name; }
+
+ void declareStruct(const TStructure *structure);
+ virtual void writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol);
+ bool structDeclared(const TStructure *structure) const;
+
+ private:
+ void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock);
+ void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock);
+
+ void writeBuiltInFunctionTriplet(Visit visit, TOperator op, bool useEmulatedFunction);
+
+ const char *mapQualifierToString(TQualifier qualifier);
+
+ TInfoSinkBase &mObjSink;
+ bool mDeclaringVariable;
+
+ // This set contains all the ids of the structs from every scope.
+ std::set<int> mDeclaredStructs;
+
+ ShArrayIndexClampingStrategy mClampingStrategy;
+
+ // name hashing.
+ ShHashFunction64 mHashFunction;
+
+ NameMap &mNameMap;
+
+ sh::GLenum mShaderType;
+
+ const int mShaderVersion;
+
+ ShShaderOutput mOutput;
+
+ ShCompileOptions mCompileOptions;
+};
+
+void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
+ sh::TLayoutPrimitiveType inputPrimitive,
+ int invocations,
+ sh::TLayoutPrimitiveType outputPrimitive,
+ int maxVertices);
+
+bool NeedsToWriteLayoutQualifier(const TType &type);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp
new file mode 100644
index 0000000000..3ff3ffdd2a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp
@@ -0,0 +1,3568 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputHLSL.h"
+
+#include <stdio.h>
+#include <algorithm>
+#include <cfloat>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "common/utilities.h"
+#include "compiler/translator/AtomicCounterFunctionHLSL.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
+#include "compiler/translator/ImageFunctionHLSL.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/ResourcesHLSL.h"
+#include "compiler/translator/StructureHLSL.h"
+#include "compiler/translator/TextureFunctionHLSL.h"
+#include "compiler/translator/TranslatorHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/blocklayout.h"
+#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
+#include "compiler/translator/tree_util/FindSymbolNode.h"
+#include "compiler/translator/tree_util/NodeSearch.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@";
+
+TString ArrayHelperFunctionName(const char *prefix, const TType &type)
+{
+ TStringStream fnName = sh::InitializeStream<TStringStream>();
+ fnName << prefix << "_";
+ if (type.isArray())
+ {
+ for (unsigned int arraySize : *type.getArraySizes())
+ {
+ fnName << arraySize << "_";
+ }
+ }
+ fnName << TypeString(type);
+ return fnName.str();
+}
+
+bool IsDeclarationWrittenOut(TIntermDeclaration *node)
+{
+ TIntermSequence *sequence = node->getSequence();
+ TIntermTyped *variable = (*sequence)[0]->getAsTyped();
+ ASSERT(sequence->size() == 1);
+ ASSERT(variable);
+ return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
+ variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
+}
+
+bool IsInStd140UniformBlock(TIntermTyped *node)
+{
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode)
+ {
+ return IsInStd140UniformBlock(binaryNode->getLeft());
+ }
+
+ const TType &type = node->getType();
+
+ if (type.getQualifier() == EvqUniform)
+ {
+ // determine if we are in the standard layout
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ if (interfaceBlock)
+ {
+ return (interfaceBlock->blockStorage() == EbsStd140);
+ }
+ }
+
+ return false;
+}
+
+const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
+{
+ switch (op)
+ {
+ case EOpAtomicAdd:
+ return "InterlockedAdd(";
+ case EOpAtomicMin:
+ return "InterlockedMin(";
+ case EOpAtomicMax:
+ return "InterlockedMax(";
+ case EOpAtomicAnd:
+ return "InterlockedAnd(";
+ case EOpAtomicOr:
+ return "InterlockedOr(";
+ case EOpAtomicXor:
+ return "InterlockedXor(";
+ case EOpAtomicExchange:
+ return "InterlockedExchange(";
+ case EOpAtomicCompSwap:
+ return "InterlockedCompareExchange(";
+ default:
+ UNREACHABLE();
+ return "";
+ }
+}
+
+bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node)
+{
+ TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate();
+ if (aggregateNode == nullptr)
+ {
+ return false;
+ }
+
+ if (node.getOp() == EOpAssign && IsAtomicFunction(aggregateNode->getOp()))
+ {
+ return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped());
+ }
+
+ return false;
+}
+
+const char *kZeros = "_ANGLE_ZEROS_";
+constexpr int kZeroCount = 256;
+std::string DefineZeroArray()
+{
+ std::stringstream ss = sh::InitializeStream<std::stringstream>();
+ // For 'static', if the declaration does not include an initializer, the value is set to zero.
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
+ ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
+ return ss.str();
+}
+
+std::string GetZeroInitializer(size_t size)
+{
+ std::stringstream ss = sh::InitializeStream<std::stringstream>();
+ size_t quotient = size / kZeroCount;
+ size_t reminder = size % kZeroCount;
+
+ for (size_t i = 0; i < quotient; ++i)
+ {
+ if (i != 0)
+ {
+ ss << ", ";
+ }
+ ss << kZeros;
+ }
+
+ for (size_t i = 0; i < reminder; ++i)
+ {
+ if (quotient != 0 || i != 0)
+ {
+ ss << ", ";
+ }
+ ss << "0";
+ }
+
+ return ss.str();
+}
+
+} // anonymous namespace
+
+TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
+ const TVariable *aInstanceVariable)
+ : block(aBlock), instanceVariable(aInstanceVariable)
+{}
+
+bool OutputHLSL::needStructMapping(TIntermTyped *node)
+{
+ ASSERT(node->getBasicType() == EbtStruct);
+ for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
+ {
+ TIntermNode *ancestor = getAncestorNode(n);
+ const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
+ if (ancestorBinary)
+ {
+ switch (ancestorBinary->getOp())
+ {
+ case EOpIndexDirectStruct:
+ {
+ const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index =
+ ancestorBinary->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+ if (field->type()->getStruct() == nullptr)
+ {
+ return false;
+ }
+ break;
+ }
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ break;
+ default:
+ return true;
+ }
+ }
+ else
+ {
+ const TIntermAggregate *ancestorAggregate = ancestor->getAsAggregate();
+ if (ancestorAggregate)
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
+{
+ // This is known not to work for NaN on all drivers but make the best effort to output NaNs
+ // regardless.
+ if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
+ mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
+ }
+ else
+ {
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
+ }
+}
+
+void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
+{
+ ASSERT(constUnion != nullptr);
+ switch (constUnion->getType())
+ {
+ case EbtFloat:
+ writeFloat(out, constUnion->getFConst());
+ break;
+ case EbtInt:
+ out << constUnion->getIConst();
+ break;
+ case EbtUInt:
+ out << constUnion->getUConst();
+ break;
+ case EbtBool:
+ out << constUnion->getBConst();
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
+ const TConstantUnion *const constUnion,
+ const size_t size)
+{
+ const TConstantUnion *constUnionIterated = constUnion;
+ for (size_t i = 0; i < size; i++, constUnionIterated++)
+ {
+ writeSingleConstant(out, constUnionIterated);
+
+ if (i != size - 1)
+ {
+ out << ", ";
+ }
+ }
+ return constUnionIterated;
+}
+
+OutputHLSL::OutputHLSL(sh::GLenum shaderType,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ const char *sourcePath,
+ ShShaderOutput outputType,
+ int numRenderTargets,
+ int maxDualSourceDrawBuffers,
+ const std::vector<Uniform> &uniforms,
+ ShCompileOptions compileOptions,
+ sh::WorkGroupSize workGroupSize,
+ TSymbolTable *symbolTable,
+ PerformanceDiagnostics *perfDiagnostics,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks)
+ : TIntermTraverser(true, true, true, symbolTable),
+ mShaderType(shaderType),
+ mShaderVersion(shaderVersion),
+ mExtensionBehavior(extensionBehavior),
+ mSourcePath(sourcePath),
+ mOutputType(outputType),
+ mCompileOptions(compileOptions),
+ mInsideFunction(false),
+ mInsideMain(false),
+ mNumRenderTargets(numRenderTargets),
+ mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers),
+ mCurrentFunctionMetadata(nullptr),
+ mWorkGroupSize(workGroupSize),
+ mPerfDiagnostics(perfDiagnostics),
+ mNeedStructMapping(false)
+{
+ mUsesFragColor = false;
+ mUsesFragData = false;
+ mUsesDepthRange = false;
+ mUsesFragCoord = false;
+ mUsesPointCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesInstanceID = false;
+ mHasMultiviewExtensionEnabled =
+ IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview) ||
+ IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2);
+ mUsesViewID = false;
+ mUsesVertexID = false;
+ mUsesFragDepth = false;
+ mUsesNumWorkGroups = false;
+ mUsesWorkGroupID = false;
+ mUsesLocalInvocationID = false;
+ mUsesGlobalInvocationID = false;
+ mUsesLocalInvocationIndex = false;
+ mUsesXor = false;
+ mUsesDiscardRewriting = false;
+ mUsesNestedBreak = false;
+ mRequiresIEEEStrictCompiling = false;
+ mUseZeroArray = false;
+ mUsesSecondaryColor = false;
+
+ mUniqueIndex = 0;
+
+ mOutputLod0Function = false;
+ mInsideDiscontinuousLoop = false;
+ mNestedLoopDepth = 0;
+
+ mExcessiveLoopIndex = nullptr;
+
+ mStructureHLSL = new StructureHLSL;
+ mTextureFunctionHLSL = new TextureFunctionHLSL;
+ mImageFunctionHLSL = new ImageFunctionHLSL;
+ mAtomicCounterFunctionHLSL =
+ new AtomicCounterFunctionHLSL((compileOptions & SH_FORCE_ATOMIC_VALUE_RESOLUTION) != 0);
+
+ unsigned int firstUniformRegister =
+ ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
+ mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
+
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
+ {
+ // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
+ // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
+ // dx_ViewAdjust.
+ // In both cases total 3 uniform registers need to be reserved.
+ mResourcesHLSL->reserveUniformRegisters(3);
+ }
+
+ // Reserve registers for the default uniform block and driver constants
+ mResourcesHLSL->reserveUniformBlockRegisters(2);
+
+ mSSBOOutputHLSL =
+ new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL, shaderStorageBlocks);
+}
+
+OutputHLSL::~OutputHLSL()
+{
+ SafeDelete(mSSBOOutputHLSL);
+ SafeDelete(mStructureHLSL);
+ SafeDelete(mResourcesHLSL);
+ SafeDelete(mTextureFunctionHLSL);
+ SafeDelete(mImageFunctionHLSL);
+ SafeDelete(mAtomicCounterFunctionHLSL);
+ for (auto &eqFunction : mStructEqualityFunctions)
+ {
+ SafeDelete(eqFunction);
+ }
+ for (auto &eqFunction : mArrayEqualityFunctions)
+ {
+ SafeDelete(eqFunction);
+ }
+}
+
+void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
+{
+ BuiltInFunctionEmulator builtInFunctionEmulator;
+ InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
+ if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
+ {
+ InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
+ mShaderVersion);
+ }
+
+ builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
+
+ // Now that we are done changing the AST, do the analyses need for HLSL generation
+ CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
+ ASSERT(success == CallDAG::INITDAG_SUCCESS);
+ mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
+
+ const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
+ // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
+ // the shader code. When we add shader storage blocks we might also consider an alternative
+ // solution, since the struct mapping won't work very well for shader storage blocks.
+
+ // Output the body and footer first to determine what has to go in the header
+ mInfoSinkStack.push(&mBody);
+ treeRoot->traverse(this);
+ mInfoSinkStack.pop();
+
+ mInfoSinkStack.push(&mFooter);
+ mInfoSinkStack.pop();
+
+ mInfoSinkStack.push(&mHeader);
+ header(mHeader, std140Structs, &builtInFunctionEmulator);
+ mInfoSinkStack.pop();
+
+ objSink << mHeader.c_str();
+ objSink << mBody.c_str();
+ objSink << mFooter.c_str();
+
+ builtInFunctionEmulator.cleanup();
+}
+
+const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
+{
+ return mResourcesHLSL->getShaderStorageBlockRegisterMap();
+}
+
+const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
+{
+ return mResourcesHLSL->getUniformBlockRegisterMap();
+}
+
+const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
+{
+ return mResourcesHLSL->getUniformRegisterMap();
+}
+
+unsigned int OutputHLSL::getReadonlyImage2DRegisterIndex() const
+{
+ return mResourcesHLSL->getReadonlyImage2DRegisterIndex();
+}
+
+unsigned int OutputHLSL::getImage2DRegisterIndex() const
+{
+ return mResourcesHLSL->getImage2DRegisterIndex();
+}
+
+const std::set<std::string> &OutputHLSL::getUsedImage2DFunctionNames() const
+{
+ return mImageFunctionHLSL->getUsedImage2DFunctionNames();
+}
+
+TString OutputHLSL::structInitializerString(int indent,
+ const TType &type,
+ const TString &name) const
+{
+ TString init;
+
+ TString indentString;
+ for (int spaces = 0; spaces < indent; spaces++)
+ {
+ indentString += " ";
+ }
+
+ if (type.isArray())
+ {
+ init += indentString + "{\n";
+ for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
+ {
+ TStringStream indexedString = sh::InitializeStream<TStringStream>();
+ indexedString << name << "[" << arrayIndex << "]";
+ TType elementType = type;
+ elementType.toArrayElementType();
+ init += structInitializerString(indent + 1, elementType, indexedString.str());
+ if (arrayIndex < type.getOutermostArraySize() - 1)
+ {
+ init += ",";
+ }
+ init += "\n";
+ }
+ init += indentString + "}";
+ }
+ else if (type.getBasicType() == EbtStruct)
+ {
+ init += indentString + "{\n";
+ const TStructure &structure = *type.getStruct();
+ const TFieldList &fields = structure.fields();
+ for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ const TField &field = *fields[fieldIndex];
+ const TString &fieldName = name + "." + Decorate(field.name());
+ const TType &fieldType = *field.type();
+
+ init += structInitializerString(indent + 1, fieldType, fieldName);
+ if (fieldIndex < fields.size() - 1)
+ {
+ init += ",";
+ }
+ init += "\n";
+ }
+ init += indentString + "}";
+ }
+ else
+ {
+ init += indentString + name;
+ }
+
+ return init;
+}
+
+TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
+{
+ TString mappedStructs;
+
+ for (auto &mappedStruct : std140Structs)
+ {
+ const TInterfaceBlock *interfaceBlock =
+ mappedStruct.blockDeclarator->getType().getInterfaceBlock();
+ TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
+ switch (qualifier)
+ {
+ case EvqUniform:
+ if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ continue;
+ }
+ break;
+ case EvqBuffer:
+ continue;
+ default:
+ UNREACHABLE();
+ return mappedStructs;
+ }
+
+ unsigned int instanceCount = 1u;
+ bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
+ if (isInstanceArray)
+ {
+ instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
+ }
+
+ for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
+ ++instanceArrayIndex)
+ {
+ TString originalName;
+ TString mappedName("map");
+
+ if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
+ {
+ const ImmutableString &instanceName =
+ mappedStruct.blockDeclarator->variable().name();
+ unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
+ if (isInstanceArray)
+ instanceStringArrayIndex = instanceArrayIndex;
+ TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
+ instanceName, instanceStringArrayIndex);
+ originalName += instanceString;
+ mappedName += instanceString;
+ originalName += ".";
+ mappedName += "_";
+ }
+
+ TString fieldName = Decorate(mappedStruct.field->name());
+ originalName += fieldName;
+ mappedName += fieldName;
+
+ TType *structType = mappedStruct.field->type();
+ mappedStructs +=
+ "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
+
+ if (structType->isArray())
+ {
+ mappedStructs += ArrayString(*mappedStruct.field->type()).data();
+ }
+
+ mappedStructs += " =\n";
+ mappedStructs += structInitializerString(0, *structType, originalName);
+ mappedStructs += ";\n";
+ }
+ }
+ return mappedStructs;
+}
+
+void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
+{
+ for (const auto &attribute : mReferencedAttributes)
+ {
+ const TType &type = attribute.second->getType();
+ const ImmutableString &name = attribute.second->name();
+
+ out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
+ << zeroInitializer(type) << ";\n";
+ }
+}
+
+void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
+{
+ for (const auto &varying : mReferencedVaryings)
+ {
+ const TType &type = varying.second->getType();
+
+ // Program linking depends on this exact format
+ out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
+ << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
+ << zeroInitializer(type) << ";\n";
+ }
+}
+
+void OutputHLSL::header(TInfoSinkBase &out,
+ const std::vector<MappedStruct> &std140Structs,
+ const BuiltInFunctionEmulator *builtInFunctionEmulator) const
+{
+ TString mappedStructs;
+ if (mNeedStructMapping)
+ {
+ mappedStructs = generateStructMapping(std140Structs);
+ }
+
+ out << mStructureHLSL->structsHeader();
+
+ mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
+ out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
+ mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
+
+ if (!mEqualityFunctions.empty())
+ {
+ out << "\n// Equality functions\n\n";
+ for (const auto &eqFunction : mEqualityFunctions)
+ {
+ out << eqFunction->functionDefinition << "\n";
+ }
+ }
+ if (!mArrayAssignmentFunctions.empty())
+ {
+ out << "\n// Assignment functions\n\n";
+ for (const auto &assignmentFunction : mArrayAssignmentFunctions)
+ {
+ out << assignmentFunction.functionDefinition << "\n";
+ }
+ }
+ if (!mArrayConstructIntoFunctions.empty())
+ {
+ out << "\n// Array constructor functions\n\n";
+ for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
+ {
+ out << constructIntoFunction.functionDefinition << "\n";
+ }
+ }
+
+ if (mUsesDiscardRewriting)
+ {
+ out << "#define ANGLE_USES_DISCARD_REWRITING\n";
+ }
+
+ if (mUsesNestedBreak)
+ {
+ out << "#define ANGLE_USES_NESTED_BREAK\n";
+ }
+
+ if (mRequiresIEEEStrictCompiling)
+ {
+ out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
+ }
+
+ out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
+ "#define LOOP [loop]\n"
+ "#define FLATTEN [flatten]\n"
+ "#else\n"
+ "#define LOOP\n"
+ "#define FLATTEN\n"
+ "#endif\n";
+
+ // array stride for atomic counter buffers is always 4 per original extension
+ // ARB_shader_atomic_counters and discussion on
+ // https://github.com/KhronosGroup/OpenGL-API/issues/5
+ out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
+
+ if (mUseZeroArray)
+ {
+ out << DefineZeroArray() << "\n";
+ }
+
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ const bool usingMRTExtension =
+ IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
+ const bool usingBFEExtension =
+ IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_blend_func_extended);
+
+ out << "// Varyings\n";
+ writeReferencedVaryings(out);
+ out << "\n";
+
+ if (mShaderVersion >= 300)
+ {
+ for (const auto &outputVariable : mReferencedOutputVariables)
+ {
+ const ImmutableString &variableName = outputVariable.second->name();
+ const TType &variableType = outputVariable.second->getType();
+
+ out << "static " << TypeString(variableType) << " out_" << variableName
+ << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
+ }
+ }
+ else
+ {
+ const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
+
+ out << "static float4 gl_Color[" << numColorValues
+ << "] =\n"
+ "{\n";
+ for (unsigned int i = 0; i < numColorValues; i++)
+ {
+ out << " float4(0, 0, 0, 0)";
+ if (i + 1 != numColorValues)
+ {
+ out << ",";
+ }
+ out << "\n";
+ }
+
+ out << "};\n";
+
+ if (usingBFEExtension && mUsesSecondaryColor)
+ {
+ out << "static float4 gl_SecondaryColor[" << mMaxDualSourceDrawBuffers
+ << "] = \n"
+ "{\n";
+ for (int i = 0; i < mMaxDualSourceDrawBuffers; i++)
+ {
+ out << " float4(0, 0, 0, 0)";
+ if (i + 1 != mMaxDualSourceDrawBuffers)
+ {
+ out << ",";
+ }
+ out << "\n";
+ }
+ out << "};\n";
+ }
+ }
+
+ if (mUsesFragDepth)
+ {
+ out << "static float gl_Depth = 0.0;\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "static bool gl_FrontFacing = false;\n";
+ }
+
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n";
+ }
+
+ if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n";
+
+ if (mUsesDepthRange)
+ {
+ out << " float3 dx_DepthRange : packoffset(c0);\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << " float4 dx_ViewCoords : packoffset(c1);\n";
+ }
+
+ if (mUsesFragCoord || mUsesFrontFacing)
+ {
+ out << " float3 dx_DepthFront : packoffset(c2);\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ // dx_ViewScale is only used in the fragment shader to correct
+ // the value for glFragCoord if necessary
+ out << " float2 dx_ViewScale : packoffset(c3);\n";
+ }
+
+ if (mHasMultiviewExtensionEnabled)
+ {
+ // We have to add a value which we can use to keep track of which multi-view code
+ // path is to be selected in the GS.
+ out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
+ }
+
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ mResourcesHLSL->samplerMetadataUniforms(out, 4);
+ }
+
+ out << "};\n";
+ }
+ else
+ {
+ if (mUsesDepthRange)
+ {
+ out << "uniform float3 dx_DepthRange : register(c0);";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "uniform float4 dx_ViewCoords : register(c1);\n";
+ }
+
+ if (mUsesFragCoord || mUsesFrontFacing)
+ {
+ out << "uniform float3 dx_DepthFront : register(c2);\n";
+ }
+ }
+
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
+ "dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ if (usingMRTExtension && mNumRenderTargets > 1)
+ {
+ out << "#define GL_USES_MRT\n";
+ }
+
+ if (mUsesFragColor)
+ {
+ out << "#define GL_USES_FRAG_COLOR\n";
+ }
+
+ if (mUsesFragData)
+ {
+ out << "#define GL_USES_FRAG_DATA\n";
+ }
+
+ if (mShaderVersion < 300 && usingBFEExtension && mUsesSecondaryColor)
+ {
+ out << "#define GL_USES_SECONDARY_COLOR\n";
+ }
+ }
+ else if (mShaderType == GL_VERTEX_SHADER)
+ {
+ out << "// Attributes\n";
+ writeReferencedAttributes(out);
+ out << "\n"
+ "static float4 gl_Position = float4(0, 0, 0, 0);\n";
+
+ if (mUsesPointSize)
+ {
+ out << "static float gl_PointSize = float(1);\n";
+ }
+
+ if (mUsesInstanceID)
+ {
+ out << "static int gl_InstanceID;";
+ }
+
+ if (mUsesVertexID)
+ {
+ out << "static int gl_VertexID;";
+ }
+
+ out << "\n"
+ "// Varyings\n";
+ writeReferencedVaryings(out);
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n";
+ }
+
+ if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n";
+
+ if (mUsesDepthRange)
+ {
+ out << " float3 dx_DepthRange : packoffset(c0);\n";
+ }
+
+ // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
+ // shaders. However, we declare it for all shaders (including Feature Level 10+).
+ // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
+ // if it's unused.
+ out << " float4 dx_ViewAdjust : packoffset(c1);\n";
+ out << " float2 dx_ViewCoords : packoffset(c2);\n";
+ out << " float2 dx_ViewScale : packoffset(c3);\n";
+
+ if (mHasMultiviewExtensionEnabled)
+ {
+ // We have to add a value which we can use to keep track of which multi-view code
+ // path is to be selected in the GS.
+ out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
+ }
+
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ mResourcesHLSL->samplerMetadataUniforms(out, 4);
+ }
+
+ if (mUsesVertexID)
+ {
+ out << " uint dx_VertexID : packoffset(c3.w);\n";
+ }
+
+ out << "};\n"
+ "\n";
+ }
+ else
+ {
+ if (mUsesDepthRange)
+ {
+ out << "uniform float3 dx_DepthRange : register(c0);\n";
+ }
+
+ out << "uniform float4 dx_ViewAdjust : register(c1);\n";
+ out << "uniform float2 dx_ViewCoords : register(c2);\n"
+ "\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
+ "dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+ }
+ else // Compute shader
+ {
+ ASSERT(mShaderType == GL_COMPUTE_SHADER);
+
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n";
+ if (mUsesNumWorkGroups)
+ {
+ out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
+ }
+ ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
+ unsigned int registerIndex = 1;
+ mResourcesHLSL->samplerMetadataUniforms(out, registerIndex);
+ // Sampler metadata struct must be two 4-vec, 32 bytes.
+ registerIndex += mResourcesHLSL->getSamplerCount() * 2;
+ mResourcesHLSL->imageMetadataUniforms(out, registerIndex);
+ out << "};\n";
+
+ out << kImage2DFunctionString << "\n";
+
+ std::ostringstream systemValueDeclaration = sh::InitializeStream<std::ostringstream>();
+ std::ostringstream glBuiltinInitialization = sh::InitializeStream<std::ostringstream>();
+
+ systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
+ glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
+ << "{\n";
+
+ if (mUsesWorkGroupID)
+ {
+ out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
+ systemValueDeclaration << " uint3 dx_WorkGroupID : "
+ << "SV_GroupID;\n";
+ glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
+ }
+
+ if (mUsesLocalInvocationID)
+ {
+ out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
+ systemValueDeclaration << " uint3 dx_LocalInvocationID : "
+ << "SV_GroupThreadID;\n";
+ glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
+ }
+
+ if (mUsesGlobalInvocationID)
+ {
+ out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
+ systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
+ << "SV_DispatchThreadID;\n";
+ glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
+ }
+
+ if (mUsesLocalInvocationIndex)
+ {
+ out << "static uint gl_LocalInvocationIndex = uint(0);\n";
+ systemValueDeclaration << " uint dx_LocalInvocationIndex : "
+ << "SV_GroupIndex;\n";
+ glBuiltinInitialization
+ << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
+ }
+
+ systemValueDeclaration << "};\n\n";
+ glBuiltinInitialization << "};\n\n";
+
+ out << systemValueDeclaration.str();
+ out << glBuiltinInitialization.str();
+ }
+
+ if (!mappedStructs.empty())
+ {
+ out << "// Structures from std140 blocks with padding removed\n";
+ out << "\n";
+ out << mappedStructs;
+ out << "\n";
+ }
+
+ bool getDimensionsIgnoresBaseLevel =
+ (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
+ mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
+ mImageFunctionHLSL->imageFunctionHeader(out);
+ mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
+
+ if (mUsesFragCoord)
+ {
+ out << "#define GL_USES_FRAG_COORD\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "#define GL_USES_POINT_COORD\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "#define GL_USES_FRONT_FACING\n";
+ }
+
+ if (mUsesPointSize)
+ {
+ out << "#define GL_USES_POINT_SIZE\n";
+ }
+
+ if (mHasMultiviewExtensionEnabled)
+ {
+ out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
+ }
+
+ if (mUsesVertexID)
+ {
+ out << "#define GL_USES_VERTEX_ID\n";
+ }
+
+ if (mUsesViewID)
+ {
+ out << "#define GL_USES_VIEW_ID\n";
+ }
+
+ if (mUsesFragDepth)
+ {
+ out << "#define GL_USES_FRAG_DEPTH\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "#define GL_USES_DEPTH_RANGE\n";
+ }
+
+ if (mUsesXor)
+ {
+ out << "bool xor(bool p, bool q)\n"
+ "{\n"
+ " return (p || q) && !(p && q);\n"
+ "}\n"
+ "\n";
+ }
+
+ builtInFunctionEmulator->outputEmulatedFunctions(out);
+}
+
+void OutputHLSL::visitSymbol(TIntermSymbol *node)
+{
+ const TVariable &variable = node->variable();
+
+ // Empty symbols can only appear in declarations and function arguments, and in either of those
+ // cases the symbol nodes are not visited.
+ ASSERT(variable.symbolType() != SymbolType::Empty);
+
+ TInfoSinkBase &out = getInfoSink();
+
+ // Handle accessing std140 structs by value
+ if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct &&
+ needStructMapping(node))
+ {
+ mNeedStructMapping = true;
+ out << "map";
+ }
+
+ const ImmutableString &name = variable.name();
+ const TSymbolUniqueId &uniqueId = variable.uniqueId();
+
+ if (name == "gl_DepthRange")
+ {
+ mUsesDepthRange = true;
+ out << name;
+ }
+ else if (IsAtomicCounter(variable.getType().getBasicType()))
+ {
+ const TType &variableType = variable.getType();
+ if (variableType.getQualifier() == EvqUniform)
+ {
+ TLayoutQualifier layout = variableType.getLayoutQualifier();
+ mReferencedUniforms[uniqueId.get()] = &variable;
+ out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
+ }
+ else
+ {
+ TString varName = DecorateVariableIfNeeded(variable);
+ out << varName << ", " << varName << "_offset";
+ }
+ }
+ else
+ {
+ const TType &variableType = variable.getType();
+ TQualifier qualifier = variable.getType().getQualifier();
+
+ ensureStructDefined(variableType);
+
+ if (qualifier == EvqUniform)
+ {
+ const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
+
+ if (interfaceBlock)
+ {
+ if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ const TVariable *instanceVariable = nullptr;
+ if (variableType.isInterfaceBlock())
+ {
+ instanceVariable = &variable;
+ }
+ mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
+ new TReferencedBlock(interfaceBlock, instanceVariable);
+ }
+ }
+ else
+ {
+ mReferencedUniforms[uniqueId.get()] = &variable;
+ }
+
+ out << DecorateVariableIfNeeded(variable);
+ }
+ else if (qualifier == EvqBuffer)
+ {
+ UNREACHABLE();
+ }
+ else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
+ {
+ mReferencedAttributes[uniqueId.get()] = &variable;
+ out << Decorate(name);
+ }
+ else if (IsVarying(qualifier))
+ {
+ mReferencedVaryings[uniqueId.get()] = &variable;
+ out << DecorateVariableIfNeeded(variable);
+ if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
+ {
+ mUsesViewID = true;
+ }
+ }
+ else if (qualifier == EvqFragmentOut)
+ {
+ mReferencedOutputVariables[uniqueId.get()] = &variable;
+ out << "out_" << name;
+ }
+ else if (qualifier == EvqFragColor)
+ {
+ out << "gl_Color[0]";
+ mUsesFragColor = true;
+ }
+ else if (qualifier == EvqFragData)
+ {
+ out << "gl_Color";
+ mUsesFragData = true;
+ }
+ else if (qualifier == EvqSecondaryFragColorEXT)
+ {
+ out << "gl_SecondaryColor[0]";
+ mUsesSecondaryColor = true;
+ }
+ else if (qualifier == EvqSecondaryFragDataEXT)
+ {
+ out << "gl_SecondaryColor";
+ mUsesSecondaryColor = true;
+ }
+ else if (qualifier == EvqFragCoord)
+ {
+ mUsesFragCoord = true;
+ out << name;
+ }
+ else if (qualifier == EvqPointCoord)
+ {
+ mUsesPointCoord = true;
+ out << name;
+ }
+ else if (qualifier == EvqFrontFacing)
+ {
+ mUsesFrontFacing = true;
+ out << name;
+ }
+ else if (qualifier == EvqPointSize)
+ {
+ mUsesPointSize = true;
+ out << name;
+ }
+ else if (qualifier == EvqInstanceID)
+ {
+ mUsesInstanceID = true;
+ out << name;
+ }
+ else if (qualifier == EvqVertexID)
+ {
+ mUsesVertexID = true;
+ out << name;
+ }
+ else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
+ {
+ mUsesFragDepth = true;
+ out << "gl_Depth";
+ }
+ else if (qualifier == EvqNumWorkGroups)
+ {
+ mUsesNumWorkGroups = true;
+ out << name;
+ }
+ else if (qualifier == EvqWorkGroupID)
+ {
+ mUsesWorkGroupID = true;
+ out << name;
+ }
+ else if (qualifier == EvqLocalInvocationID)
+ {
+ mUsesLocalInvocationID = true;
+ out << name;
+ }
+ else if (qualifier == EvqGlobalInvocationID)
+ {
+ mUsesGlobalInvocationID = true;
+ out << name;
+ }
+ else if (qualifier == EvqLocalInvocationIndex)
+ {
+ mUsesLocalInvocationIndex = true;
+ out << name;
+ }
+ else
+ {
+ out << DecorateVariableIfNeeded(variable);
+ }
+ }
+}
+
+void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
+{
+ if (type.isScalar() && !type.isArray())
+ {
+ if (op == EOpEqual)
+ {
+ outputTriplet(out, visit, "(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(out, visit, "(", " != ", ")");
+ }
+ }
+ else
+ {
+ if (visit == PreVisit && op == EOpNotEqual)
+ {
+ out << "!";
+ }
+
+ if (type.isArray())
+ {
+ const TString &functionName = addArrayEqualityFunction(type);
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
+ }
+ else if (type.getBasicType() == EbtStruct)
+ {
+ const TStructure &structure = *type.getStruct();
+ const TString &functionName = addStructEqualityFunction(structure);
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
+ }
+ else
+ {
+ ASSERT(type.isMatrix() || type.isVector());
+ outputTriplet(out, visit, "all(", " == ", ")");
+ }
+ }
+}
+
+void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
+{
+ if (type.isArray())
+ {
+ const TString &functionName = addArrayAssignmentFunction(type);
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
+ }
+ else
+ {
+ outputTriplet(out, visit, "(", " = ", ")");
+ }
+}
+
+bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
+{
+ for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
+ {
+ TIntermNode *ancestor = getAncestorNode(n);
+ const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
+ if (ancestorBinary == nullptr)
+ {
+ return false;
+ }
+ switch (ancestorBinary->getOp())
+ {
+ case EOpIndexDirectStruct:
+ {
+ const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index =
+ ancestorBinary->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+ if (IsSampler(field->type()->getBasicType()))
+ {
+ return true;
+ }
+ break;
+ }
+ case EOpIndexDirect:
+ break;
+ default:
+ // Returning a sampler from indirect indexing is not supported.
+ return false;
+ }
+ }
+ return false;
+}
+
+bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+ if (visit == PostVisit)
+ {
+ out << ".";
+ node->writeOffsetsAsXYZW(&out);
+ }
+ return true;
+}
+
+bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ switch (node->getOp())
+ {
+ case EOpComma:
+ outputTriplet(out, visit, "(", ", ", ")");
+ break;
+ case EOpAssign:
+ if (node->isArray())
+ {
+ TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
+ if (rightAgg != nullptr && rightAgg->isConstructor())
+ {
+ const TString &functionName = addArrayConstructIntoFunction(node->getType());
+ out << functionName << "(";
+ node->getLeft()->traverse(this);
+ TIntermSequence *seq = rightAgg->getSequence();
+ for (auto &arrayElement : *seq)
+ {
+ out << ", ";
+ arrayElement->traverse(this);
+ }
+ out << ")";
+ return false;
+ }
+ // ArrayReturnValueToOutParameter should have eliminated expressions where a
+ // function call is assigned.
+ ASSERT(rightAgg == nullptr);
+ }
+ // Assignment expressions with atomic functions should be transformed into atomic
+ // function calls in HLSL.
+ // e.g. original_value = atomicAdd(dest, value) should be translated into
+ // InterlockedAdd(dest, value, original_value);
+ else if (IsAtomicFunctionForSharedVariableDirectAssign(*node))
+ {
+ TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
+ TOperator atomicFunctionOp = atomicFunctionNode->getOp();
+ out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
+ TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
+ ASSERT(argumentSeq->size() >= 2u);
+ for (auto &argument : *argumentSeq)
+ {
+ argument->traverse(this);
+ out << ", ";
+ }
+ node->getLeft()->traverse(this);
+ out << ")";
+ return false;
+ }
+ else if (IsInShaderStorageBlock(node->getLeft()))
+ {
+ mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
+ out << ", ";
+ if (IsInShaderStorageBlock(node->getRight()))
+ {
+ mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
+ }
+ else
+ {
+ node->getRight()->traverse(this);
+ }
+
+ out << ")";
+ return false;
+ }
+ else if (IsInShaderStorageBlock(node->getRight()))
+ {
+ node->getLeft()->traverse(this);
+ out << " = ";
+ mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
+ return false;
+ }
+
+ outputAssign(visit, node->getType(), out);
+ break;
+ case EOpInitialize:
+ if (visit == PreVisit)
+ {
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ ASSERT(symbolNode);
+ TIntermTyped *initializer = node->getRight();
+
+ // Global initializers must be constant at this point.
+ ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
+
+ // GLSL allows to write things like "float x = x;" where a new variable x is defined
+ // and the value of an existing variable x is assigned. HLSL uses C semantics (the
+ // new variable is created before the assignment is evaluated), so we need to
+ // convert
+ // this to "float t = x, x = t;".
+ if (writeSameSymbolInitializer(out, symbolNode, initializer))
+ {
+ // Skip initializing the rest of the expression
+ return false;
+ }
+ else if (writeConstantInitialization(out, symbolNode, initializer))
+ {
+ return false;
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << " = ";
+ if (IsInShaderStorageBlock(node->getRight()))
+ {
+ mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
+ return false;
+ }
+ }
+ break;
+ case EOpAddAssign:
+ outputTriplet(out, visit, "(", " += ", ")");
+ break;
+ case EOpSubAssign:
+ outputTriplet(out, visit, "(", " -= ", ")");
+ break;
+ case EOpMulAssign:
+ outputTriplet(out, visit, "(", " *= ", ")");
+ break;
+ case EOpVectorTimesScalarAssign:
+ outputTriplet(out, visit, "(", " *= ", ")");
+ break;
+ case EOpMatrixTimesScalarAssign:
+ outputTriplet(out, visit, "(", " *= ", ")");
+ break;
+ case EOpVectorTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", transpose(";
+ }
+ else
+ {
+ out << ")))";
+ }
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = transpose(mul(transpose(";
+ node->getLeft()->traverse(this);
+ out << "), transpose(";
+ }
+ else
+ {
+ out << "))))";
+ }
+ break;
+ case EOpDivAssign:
+ outputTriplet(out, visit, "(", " /= ", ")");
+ break;
+ case EOpIModAssign:
+ outputTriplet(out, visit, "(", " %= ", ")");
+ break;
+ case EOpBitShiftLeftAssign:
+ outputTriplet(out, visit, "(", " <<= ", ")");
+ break;
+ case EOpBitShiftRightAssign:
+ outputTriplet(out, visit, "(", " >>= ", ")");
+ break;
+ case EOpBitwiseAndAssign:
+ outputTriplet(out, visit, "(", " &= ", ")");
+ break;
+ case EOpBitwiseXorAssign:
+ outputTriplet(out, visit, "(", " ^= ", ")");
+ break;
+ case EOpBitwiseOrAssign:
+ outputTriplet(out, visit, "(", " |= ", ")");
+ break;
+ case EOpIndexDirect:
+ {
+ const TType &leftType = node->getLeft()->getType();
+ if (leftType.isInterfaceBlock())
+ {
+ if (visit == PreVisit)
+ {
+ TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
+ const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
+
+ ASSERT(leftType.getQualifier() == EvqUniform);
+ if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
+ new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
+ }
+ const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
+ out << mResourcesHLSL->InterfaceBlockInstanceString(
+ instanceArraySymbol->getName(), arrayIndex);
+ return false;
+ }
+ }
+ else if (ancestorEvaluatesToSamplerInStruct())
+ {
+ // All parts of an expression that access a sampler in a struct need to use _ as
+ // separator to access the sampler variable that has been moved out of the struct.
+ outputTriplet(out, visit, "", "_", "");
+ }
+ else if (IsAtomicCounter(leftType.getBasicType()))
+ {
+ outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
+ }
+ else
+ {
+ outputTriplet(out, visit, "", "[", "]");
+ }
+ }
+ break;
+ case EOpIndexIndirect:
+ {
+ // We do not currently support indirect references to interface blocks
+ ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
+
+ const TType &leftType = node->getLeft()->getType();
+ if (IsAtomicCounter(leftType.getBasicType()))
+ {
+ outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
+ }
+ else
+ {
+ outputTriplet(out, visit, "", "[", "]");
+ }
+ break;
+ }
+ case EOpIndexDirectStruct:
+ {
+ const TStructure *structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+
+ // In cases where indexing returns a sampler, we need to access the sampler variable
+ // that has been moved out of the struct.
+ bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
+ if (visit == PreVisit && indexingReturnsSampler)
+ {
+ // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
+ // This prefix is only output at the beginning of the indexing expression, which
+ // may have multiple parts.
+ out << "angle";
+ }
+ if (!indexingReturnsSampler)
+ {
+ // All parts of an expression that access a sampler in a struct need to use _ as
+ // separator to access the sampler variable that has been moved out of the struct.
+ indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
+ }
+ if (visit == InVisit)
+ {
+ if (indexingReturnsSampler)
+ {
+ out << "_" << field->name();
+ }
+ else
+ {
+ out << "." << DecorateField(field->name(), *structure);
+ }
+
+ return false;
+ }
+ }
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ {
+ ASSERT(!IsInShaderStorageBlock(node->getLeft()));
+ bool structInStd140UniformBlock = node->getBasicType() == EbtStruct &&
+ IsInStd140UniformBlock(node->getLeft()) &&
+ needStructMapping(node);
+ if (visit == PreVisit && structInStd140UniformBlock)
+ {
+ mNeedStructMapping = true;
+ out << "map";
+ }
+ if (visit == InVisit)
+ {
+ const TInterfaceBlock *interfaceBlock =
+ node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+ if (structInStd140UniformBlock)
+ {
+ out << "_";
+ }
+ else
+ {
+ out << ".";
+ }
+ out << Decorate(field->name());
+
+ return false;
+ }
+ break;
+ }
+ case EOpAdd:
+ outputTriplet(out, visit, "(", " + ", ")");
+ break;
+ case EOpSub:
+ outputTriplet(out, visit, "(", " - ", ")");
+ break;
+ case EOpMul:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpDiv:
+ outputTriplet(out, visit, "(", " / ", ")");
+ break;
+ case EOpIMod:
+ outputTriplet(out, visit, "(", " % ", ")");
+ break;
+ case EOpBitShiftLeft:
+ outputTriplet(out, visit, "(", " << ", ")");
+ break;
+ case EOpBitShiftRight:
+ outputTriplet(out, visit, "(", " >> ", ")");
+ break;
+ case EOpBitwiseAnd:
+ outputTriplet(out, visit, "(", " & ", ")");
+ break;
+ case EOpBitwiseXor:
+ outputTriplet(out, visit, "(", " ^ ", ")");
+ break;
+ case EOpBitwiseOr:
+ outputTriplet(out, visit, "(", " | ", ")");
+ break;
+ case EOpEqual:
+ case EOpNotEqual:
+ outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
+ break;
+ case EOpLessThan:
+ outputTriplet(out, visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThan:
+ outputTriplet(out, visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqual:
+ outputTriplet(out, visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqual:
+ outputTriplet(out, visit, "(", " >= ", ")");
+ break;
+ case EOpVectorTimesScalar:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpMatrixTimesScalar:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpVectorTimesMatrix:
+ outputTriplet(out, visit, "mul(", ", transpose(", "))");
+ break;
+ case EOpMatrixTimesVector:
+ outputTriplet(out, visit, "mul(transpose(", "), ", ")");
+ break;
+ case EOpMatrixTimesMatrix:
+ outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
+ break;
+ case EOpLogicalOr:
+ // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
+ // been unfolded.
+ ASSERT(!node->getRight()->hasSideEffects());
+ outputTriplet(out, visit, "(", " || ", ")");
+ return true;
+ case EOpLogicalXor:
+ mUsesXor = true;
+ outputTriplet(out, visit, "xor(", ", ", ")");
+ break;
+ case EOpLogicalAnd:
+ // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
+ // been unfolded.
+ ASSERT(!node->getRight()->hasSideEffects());
+ outputTriplet(out, visit, "(", " && ", ")");
+ return true;
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ switch (node->getOp())
+ {
+ case EOpNegative:
+ outputTriplet(out, visit, "(-", "", ")");
+ break;
+ case EOpPositive:
+ outputTriplet(out, visit, "(+", "", ")");
+ break;
+ case EOpLogicalNot:
+ outputTriplet(out, visit, "(!", "", ")");
+ break;
+ case EOpBitwiseNot:
+ outputTriplet(out, visit, "(~", "", ")");
+ break;
+ case EOpPostIncrement:
+ outputTriplet(out, visit, "(", "", "++)");
+ break;
+ case EOpPostDecrement:
+ outputTriplet(out, visit, "(", "", "--)");
+ break;
+ case EOpPreIncrement:
+ outputTriplet(out, visit, "(++", "", ")");
+ break;
+ case EOpPreDecrement:
+ outputTriplet(out, visit, "(--", "", ")");
+ break;
+ case EOpRadians:
+ outputTriplet(out, visit, "radians(", "", ")");
+ break;
+ case EOpDegrees:
+ outputTriplet(out, visit, "degrees(", "", ")");
+ break;
+ case EOpSin:
+ outputTriplet(out, visit, "sin(", "", ")");
+ break;
+ case EOpCos:
+ outputTriplet(out, visit, "cos(", "", ")");
+ break;
+ case EOpTan:
+ outputTriplet(out, visit, "tan(", "", ")");
+ break;
+ case EOpAsin:
+ outputTriplet(out, visit, "asin(", "", ")");
+ break;
+ case EOpAcos:
+ outputTriplet(out, visit, "acos(", "", ")");
+ break;
+ case EOpAtan:
+ outputTriplet(out, visit, "atan(", "", ")");
+ break;
+ case EOpSinh:
+ outputTriplet(out, visit, "sinh(", "", ")");
+ break;
+ case EOpCosh:
+ outputTriplet(out, visit, "cosh(", "", ")");
+ break;
+ case EOpTanh:
+ case EOpAsinh:
+ case EOpAcosh:
+ case EOpAtanh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpExp:
+ outputTriplet(out, visit, "exp(", "", ")");
+ break;
+ case EOpLog:
+ outputTriplet(out, visit, "log(", "", ")");
+ break;
+ case EOpExp2:
+ outputTriplet(out, visit, "exp2(", "", ")");
+ break;
+ case EOpLog2:
+ outputTriplet(out, visit, "log2(", "", ")");
+ break;
+ case EOpSqrt:
+ outputTriplet(out, visit, "sqrt(", "", ")");
+ break;
+ case EOpInversesqrt:
+ outputTriplet(out, visit, "rsqrt(", "", ")");
+ break;
+ case EOpAbs:
+ outputTriplet(out, visit, "abs(", "", ")");
+ break;
+ case EOpSign:
+ outputTriplet(out, visit, "sign(", "", ")");
+ break;
+ case EOpFloor:
+ outputTriplet(out, visit, "floor(", "", ")");
+ break;
+ case EOpTrunc:
+ outputTriplet(out, visit, "trunc(", "", ")");
+ break;
+ case EOpRound:
+ outputTriplet(out, visit, "round(", "", ")");
+ break;
+ case EOpRoundEven:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpCeil:
+ outputTriplet(out, visit, "ceil(", "", ")");
+ break;
+ case EOpFract:
+ outputTriplet(out, visit, "frac(", "", ")");
+ break;
+ case EOpIsnan:
+ if (node->getUseEmulatedFunction())
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ else
+ outputTriplet(out, visit, "isnan(", "", ")");
+ mRequiresIEEEStrictCompiling = true;
+ break;
+ case EOpIsinf:
+ outputTriplet(out, visit, "isinf(", "", ")");
+ break;
+ case EOpFloatBitsToInt:
+ outputTriplet(out, visit, "asint(", "", ")");
+ break;
+ case EOpFloatBitsToUint:
+ outputTriplet(out, visit, "asuint(", "", ")");
+ break;
+ case EOpIntBitsToFloat:
+ outputTriplet(out, visit, "asfloat(", "", ")");
+ break;
+ case EOpUintBitsToFloat:
+ outputTriplet(out, visit, "asfloat(", "", ")");
+ break;
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpUnpackHalf2x16:
+ case EOpPackUnorm4x8:
+ case EOpPackSnorm4x8:
+ case EOpUnpackUnorm4x8:
+ case EOpUnpackSnorm4x8:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpLength:
+ outputTriplet(out, visit, "length(", "", ")");
+ break;
+ case EOpNormalize:
+ outputTriplet(out, visit, "normalize(", "", ")");
+ break;
+ case EOpDFdx:
+ if (mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(out, visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(out, visit, "ddx(", "", ")");
+ }
+ break;
+ case EOpDFdy:
+ if (mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(out, visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(out, visit, "ddy(", "", ")");
+ }
+ break;
+ case EOpFwidth:
+ if (mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(out, visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(out, visit, "fwidth(", "", ")");
+ }
+ break;
+ case EOpTranspose:
+ outputTriplet(out, visit, "transpose(", "", ")");
+ break;
+ case EOpDeterminant:
+ outputTriplet(out, visit, "determinant(transpose(", "", "))");
+ break;
+ case EOpInverse:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+
+ case EOpAny:
+ outputTriplet(out, visit, "any(", "", ")");
+ break;
+ case EOpAll:
+ outputTriplet(out, visit, "all(", "", ")");
+ break;
+ case EOpLogicalNotComponentWise:
+ outputTriplet(out, visit, "(!", "", ")");
+ break;
+ case EOpBitfieldReverse:
+ outputTriplet(out, visit, "reversebits(", "", ")");
+ break;
+ case EOpBitCount:
+ outputTriplet(out, visit, "countbits(", "", ")");
+ break;
+ case EOpFindLSB:
+ // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
+ // in GLSLTest and results are consistent with GL.
+ outputTriplet(out, visit, "firstbitlow(", "", ")");
+ break;
+ case EOpFindMSB:
+ // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
+ // tested in GLSLTest and results are consistent with GL.
+ outputTriplet(out, visit, "firstbithigh(", "", ")");
+ break;
+ case EOpArrayLength:
+ {
+ TIntermTyped *operand = node->getOperand();
+ ASSERT(IsInShaderStorageBlock(operand));
+ mSSBOOutputHLSL->outputLengthFunctionCall(operand);
+ return false;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
+{
+ if (node->getAsSymbolNode())
+ {
+ ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
+ return node->getAsSymbolNode()->getName();
+ }
+ TIntermBinary *nodeBinary = node->getAsBinaryNode();
+ switch (nodeBinary->getOp())
+ {
+ case EOpIndexDirect:
+ {
+ int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
+
+ std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
+ prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
+ return ImmutableString(prefixSink.str());
+ }
+ case EOpIndexDirectStruct:
+ {
+ const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
+ int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
+ const TField *field = s->fields()[index];
+
+ std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
+ prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
+ << field->name();
+ return ImmutableString(prefixSink.str());
+ }
+ default:
+ UNREACHABLE();
+ return kEmptyImmutableString;
+ }
+}
+
+bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(out, node->getLine().first_line);
+ out << "{\n";
+ if (isMainBlock)
+ {
+ if (mShaderType == GL_COMPUTE_SHADER)
+ {
+ out << "initGLBuiltins(input);\n";
+ }
+ else
+ {
+ out << "@@ MAIN PROLOGUE @@\n";
+ }
+ }
+ }
+
+ for (TIntermNode *statement : *node->getSequence())
+ {
+ outputLineDirective(out, statement->getLine().first_line);
+
+ statement->traverse(this);
+
+ // Don't output ; after case labels, they're terminated by :
+ // This is needed especially since outputting a ; after a case statement would turn empty
+ // case statements into non-empty case statements, disallowing fall-through from them.
+ // Also the output code is clearer if we don't output ; after statements where it is not
+ // needed:
+ // * if statements
+ // * switch statements
+ // * blocks
+ // * function definitions
+ // * loops (do-while loops output the semicolon in VisitLoop)
+ // * declarations that don't generate output.
+ if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
+ statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
+ statement->getAsSwitchNode() == nullptr &&
+ statement->getAsFunctionDefinition() == nullptr &&
+ (statement->getAsDeclarationNode() == nullptr ||
+ IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
+ statement->getAsInvariantDeclarationNode() == nullptr)
+ {
+ out << ";\n";
+ }
+ }
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(out, node->getLine().last_line);
+ if (isMainBlock && shaderNeedsGenerateOutput())
+ {
+ // We could have an empty main, a main function without a branch at the end, or a main
+ // function with a discard statement at the end. In these cases we need to add a return
+ // statement.
+ bool needReturnStatement =
+ node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
+ node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
+ if (needReturnStatement)
+ {
+ out << "return " << generateOutputCall() << ";\n";
+ }
+ }
+ out << "}\n";
+ }
+
+ return false;
+}
+
+bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ ASSERT(mCurrentFunctionMetadata == nullptr);
+
+ size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
+ ASSERT(index != CallDAG::InvalidIndex);
+ mCurrentFunctionMetadata = &mASTMetadataList[index];
+
+ const TFunction *func = node->getFunction();
+
+ if (func->isMain())
+ {
+ // The stub strings below are replaced when shader is dynamically defined by its layout:
+ switch (mShaderType)
+ {
+ case GL_VERTEX_SHADER:
+ out << "@@ VERTEX ATTRIBUTES @@\n\n"
+ << "@@ VERTEX OUTPUT @@\n\n"
+ << "VS_OUTPUT main(VS_INPUT input)";
+ break;
+ case GL_FRAGMENT_SHADER:
+ out << "@@ PIXEL OUTPUT @@\n\n"
+ << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
+ break;
+ case GL_COMPUTE_SHADER:
+ out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
+ << mWorkGroupSize[2] << ")]\n";
+ out << "void main(CS_INPUT input)";
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ else
+ {
+ out << TypeString(node->getFunctionPrototype()->getType()) << " ";
+ out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
+ << (mOutputLod0Function ? "Lod0(" : "(");
+
+ size_t paramCount = func->getParamCount();
+ for (unsigned int i = 0; i < paramCount; i++)
+ {
+ const TVariable *param = func->getParam(i);
+ ensureStructDefined(param->getType());
+
+ writeParameter(param, out);
+
+ if (i < paramCount - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")\n";
+ }
+
+ mInsideFunction = true;
+ if (func->isMain())
+ {
+ mInsideMain = true;
+ }
+ // The function body node will output braces.
+ node->getBody()->traverse(this);
+ mInsideFunction = false;
+ mInsideMain = false;
+
+ mCurrentFunctionMetadata = nullptr;
+
+ bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
+ if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ ASSERT(!node->getFunction()->isMain());
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+
+ return false;
+}
+
+bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ if (visit == PreVisit)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
+ ASSERT(sequence->size() == 1);
+ ASSERT(declarator);
+
+ if (IsDeclarationWrittenOut(node))
+ {
+ TInfoSinkBase &out = getInfoSink();
+ ensureStructDefined(declarator->getType());
+
+ if (!declarator->getAsSymbolNode() ||
+ declarator->getAsSymbolNode()->variable().symbolType() !=
+ SymbolType::Empty) // Variable declaration
+ {
+ if (declarator->getQualifier() == EvqShared)
+ {
+ out << "groupshared ";
+ }
+ else if (!mInsideFunction)
+ {
+ out << "static ";
+ }
+
+ out << TypeString(declarator->getType()) + " ";
+
+ TIntermSymbol *symbol = declarator->getAsSymbolNode();
+
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << ArrayString(symbol->getType());
+ // Temporarily disable shadred memory initialization. It is very slow for D3D11
+ // drivers to compile a compute shader if we add code to initialize a
+ // groupshared array variable with a large array size. And maybe produce
+ // incorrect result. See http://anglebug.com/3226.
+ if (declarator->getQualifier() != EvqShared)
+ {
+ out << " = " + zeroInitializer(symbol->getType());
+ }
+ }
+ else
+ {
+ declarator->traverse(this);
+ }
+ }
+ }
+ else if (IsVaryingOut(declarator->getQualifier()))
+ {
+ TIntermSymbol *symbol = declarator->getAsSymbolNode();
+ ASSERT(symbol); // Varying declarations can't have initializers.
+
+ const TVariable &variable = symbol->variable();
+
+ if (variable.symbolType() != SymbolType::Empty)
+ {
+ // Vertex outputs which are declared but not written to should still be declared to
+ // allow successful linking.
+ mReferencedVaryings[symbol->uniqueId().get()] = &variable;
+ }
+ }
+ }
+ return false;
+}
+
+bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+ // Do not do any translation
+ return false;
+}
+
+void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
+ // Skip the prototype if it is not implemented (and thus not used)
+ if (index == CallDAG::InvalidIndex)
+ {
+ return;
+ }
+
+ const TFunction *func = node->getFunction();
+
+ TString name = DecorateFunctionIfNeeded(func);
+ out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
+ << (mOutputLod0Function ? "Lod0(" : "(");
+
+ size_t paramCount = func->getParamCount();
+ for (unsigned int i = 0; i < paramCount; i++)
+ {
+ writeParameter(func->getParam(i), out);
+
+ if (i < paramCount - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ");\n";
+
+ // Also prototype the Lod0 variant if needed
+ bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
+ if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+}
+
+bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ switch (node->getOp())
+ {
+ case EOpCallBuiltInFunction:
+ case EOpCallFunctionInAST:
+ case EOpCallInternalRawFunction:
+ {
+ TIntermSequence *arguments = node->getSequence();
+
+ bool lod0 = (mInsideDiscontinuousLoop || mOutputLod0Function) &&
+ mShaderType == GL_FRAGMENT_SHADER;
+ if (node->getOp() == EOpCallFunctionInAST)
+ {
+ if (node->isArray())
+ {
+ UNIMPLEMENTED();
+ }
+ size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
+ ASSERT(index != CallDAG::InvalidIndex);
+ lod0 &= mASTMetadataList[index].mNeedsLod0;
+
+ out << DecorateFunctionIfNeeded(node->getFunction());
+ out << DisambiguateFunctionName(node->getSequence());
+ out << (lod0 ? "Lod0(" : "(");
+ }
+ else if (node->getOp() == EOpCallInternalRawFunction)
+ {
+ // This path is used for internal functions that don't have their definitions in the
+ // AST, such as precision emulation functions.
+ out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
+ }
+ else if (node->getFunction()->isImageFunction())
+ {
+ const ImmutableString &name = node->getFunction()->name();
+ TType type = (*arguments)[0]->getAsTyped()->getType();
+ const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
+ name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
+ type.getMemoryQualifier().readonly);
+ out << imageFunctionName << "(";
+ }
+ else if (node->getFunction()->isAtomicCounterFunction())
+ {
+ const ImmutableString &name = node->getFunction()->name();
+ ImmutableString atomicFunctionName =
+ mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
+ out << atomicFunctionName << "(";
+ }
+ else
+ {
+ const ImmutableString &name = node->getFunction()->name();
+ TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
+ int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
+ if (arguments->size() > 1)
+ {
+ coords = (*arguments)[1]->getAsTyped()->getNominalSize();
+ }
+ const ImmutableString &textureFunctionName =
+ mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
+ arguments->size(), lod0, mShaderType);
+ out << textureFunctionName << "(";
+ }
+
+ for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
+ {
+ TIntermTyped *typedArg = (*arg)->getAsTyped();
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
+ {
+ out << "texture_";
+ (*arg)->traverse(this);
+ out << ", sampler_";
+ }
+
+ (*arg)->traverse(this);
+
+ if (typedArg->getType().isStructureContainingSamplers())
+ {
+ const TType &argType = typedArg->getType();
+ TVector<const TVariable *> samplerSymbols;
+ ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
+ std::string namePrefix = "angle_";
+ namePrefix += structName.data();
+ argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
+ nullptr, mSymbolTable);
+ for (const TVariable *sampler : samplerSymbols)
+ {
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ out << ", texture_" << sampler->name();
+ out << ", sampler_" << sampler->name();
+ }
+ else
+ {
+ // In case of HLSL 4.1+, this symbol is the sampler index, and in case
+ // of D3D9, it's the sampler variable.
+ out << ", " << sampler->name();
+ }
+ }
+ }
+
+ if (arg < arguments->end() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ case EOpConstruct:
+ outputConstructor(out, visit, node);
+ break;
+ case EOpEqualComponentWise:
+ outputTriplet(out, visit, "(", " == ", ")");
+ break;
+ case EOpNotEqualComponentWise:
+ outputTriplet(out, visit, "(", " != ", ")");
+ break;
+ case EOpLessThanComponentWise:
+ outputTriplet(out, visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThanComponentWise:
+ outputTriplet(out, visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqualComponentWise:
+ outputTriplet(out, visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqualComponentWise:
+ outputTriplet(out, visit, "(", " >= ", ")");
+ break;
+ case EOpMod:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpModf:
+ outputTriplet(out, visit, "modf(", ", ", ")");
+ break;
+ case EOpPow:
+ outputTriplet(out, visit, "pow(", ", ", ")");
+ break;
+ case EOpAtan:
+ ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpMin:
+ outputTriplet(out, visit, "min(", ", ", ")");
+ break;
+ case EOpMax:
+ outputTriplet(out, visit, "max(", ", ", ")");
+ break;
+ case EOpClamp:
+ outputTriplet(out, visit, "clamp(", ", ", ")");
+ break;
+ case EOpMix:
+ {
+ TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
+ if (lastParamNode->getType().getBasicType() == EbtBool)
+ {
+ // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
+ // y, genBType a)",
+ // so use emulated version.
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ }
+ else
+ {
+ outputTriplet(out, visit, "lerp(", ", ", ")");
+ }
+ break;
+ }
+ case EOpStep:
+ outputTriplet(out, visit, "step(", ", ", ")");
+ break;
+ case EOpSmoothstep:
+ outputTriplet(out, visit, "smoothstep(", ", ", ")");
+ break;
+ case EOpFrexp:
+ case EOpLdexp:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpDistance:
+ outputTriplet(out, visit, "distance(", ", ", ")");
+ break;
+ case EOpDot:
+ outputTriplet(out, visit, "dot(", ", ", ")");
+ break;
+ case EOpCross:
+ outputTriplet(out, visit, "cross(", ", ", ")");
+ break;
+ case EOpFaceforward:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpReflect:
+ outputTriplet(out, visit, "reflect(", ", ", ")");
+ break;
+ case EOpRefract:
+ outputTriplet(out, visit, "refract(", ", ", ")");
+ break;
+ case EOpOuterProduct:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpMulMatrixComponentWise:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpBitfieldExtract:
+ case EOpBitfieldInsert:
+ case EOpUaddCarry:
+ case EOpUsubBorrow:
+ case EOpUmulExtended:
+ case EOpImulExtended:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, node->getOp());
+ break;
+ case EOpBarrier:
+ // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
+ // cheapest *WithGroupSync() function, without any functionality loss, but
+ // with the potential for severe performance loss.
+ outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
+ break;
+ case EOpMemoryBarrierShared:
+ outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
+ break;
+ case EOpMemoryBarrierAtomicCounter:
+ case EOpMemoryBarrierBuffer:
+ case EOpMemoryBarrierImage:
+ outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
+ break;
+ case EOpGroupMemoryBarrier:
+ case EOpMemoryBarrier:
+ outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
+ break;
+
+ // Single atomic function calls without return value.
+ // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
+ case EOpAtomicAdd:
+ case EOpAtomicMin:
+ case EOpAtomicMax:
+ case EOpAtomicAnd:
+ case EOpAtomicOr:
+ case EOpAtomicXor:
+ // The parameter 'original_value' of InterlockedExchange(dest, value, original_value)
+ // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not
+ // optional.
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
+ // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest,
+ // compare_value, value) should all be modified into the form of "int temp; temp =
+ // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest,
+ // compare_value, value);" in the intermediate tree before traversing outputHLSL.
+ case EOpAtomicExchange:
+ case EOpAtomicCompSwap:
+ {
+ ASSERT(node->getChildCount() > 1);
+ TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped();
+ if (IsInShaderStorageBlock(memNode))
+ {
+ // Atomic memory functions for SSBO.
+ // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|.
+ mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp());
+ // Write the rest argument list to |out|.
+ for (size_t i = 1; i < node->getChildCount(); i++)
+ {
+ out << ", ";
+ TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped();
+ if (IsInShaderStorageBlock(argument))
+ {
+ mSSBOOutputHLSL->outputLoadFunctionCall(argument);
+ }
+ else
+ {
+ argument->traverse(this);
+ }
+ }
+
+ out << ")";
+ return false;
+ }
+ else
+ {
+ // Atomic memory functions for shared variable.
+ if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap)
+ {
+ outputTriplet(out, visit,
+ GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",",
+ ")");
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
+{
+ out << "if (";
+
+ node->getCondition()->traverse(this);
+
+ out << ")\n";
+
+ outputLineDirective(out, node->getLine().first_line);
+
+ bool discard = false;
+
+ if (node->getTrueBlock())
+ {
+ // The trueBlock child node will output braces.
+ node->getTrueBlock()->traverse(this);
+
+ // Detect true discard
+ discard = (discard || FindDiscard::search(node->getTrueBlock()));
+ }
+ else
+ {
+ // TODO(oetuaho): Check if the semicolon inside is necessary.
+ // It's there as a result of conservative refactoring of the output.
+ out << "{;}\n";
+ }
+
+ outputLineDirective(out, node->getLine().first_line);
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+
+ outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
+
+ // The falseBlock child node will output braces.
+ node->getFalseBlock()->traverse(this);
+
+ outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
+
+ // Detect false discard
+ discard = (discard || FindDiscard::search(node->getFalseBlock()));
+ }
+
+ // ANGLE issue 486: Detect problematic conditional discard
+ if (discard)
+ {
+ mUsesDiscardRewriting = true;
+ }
+}
+
+bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
+{
+ // Ternary ops should have been already converted to something else in the AST. HLSL ternary
+ // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
+ UNREACHABLE();
+ return false;
+}
+
+bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ ASSERT(mInsideFunction);
+
+ // D3D errors when there is a gradient operation in a loop in an unflattened if.
+ if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
+ {
+ out << "FLATTEN ";
+ }
+
+ writeIfElse(out, node);
+
+ return false;
+}
+
+bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ ASSERT(node->getStatementList());
+ if (visit == PreVisit)
+ {
+ node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
+ }
+ outputTriplet(out, visit, "switch (", ") ", "");
+ // The curly braces get written when visiting the statementList block.
+ return true;
+}
+
+bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ if (node->hasCondition())
+ {
+ outputTriplet(out, visit, "case (", "", "):\n");
+ return true;
+ }
+ else
+ {
+ out << "default:\n";
+ return false;
+ }
+}
+
+void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+ writeConstantUnion(out, node->getType(), node->getConstantValue());
+}
+
+bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
+{
+ mNestedLoopDepth++;
+
+ bool wasDiscontinuous = mInsideDiscontinuousLoop;
+ mInsideDiscontinuousLoop =
+ mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
+
+ TInfoSinkBase &out = getInfoSink();
+
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
+ {
+ if (handleExcessiveLoop(out, node))
+ {
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+ mNestedLoopDepth--;
+
+ return false;
+ }
+ }
+
+ const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
+ if (node->getType() == ELoopDoWhile)
+ {
+ out << "{" << unroll << " do\n";
+
+ outputLineDirective(out, node->getLine().first_line);
+ }
+ else
+ {
+ out << "{" << unroll << " for(";
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ out << ")\n";
+
+ outputLineDirective(out, node->getLine().first_line);
+ }
+
+ if (node->getBody())
+ {
+ // The loop body node will output braces.
+ node->getBody()->traverse(this);
+ }
+ else
+ {
+ // TODO(oetuaho): Check if the semicolon inside is necessary.
+ // It's there as a result of conservative refactoring of the output.
+ out << "{;}\n";
+ }
+
+ outputLineDirective(out, node->getLine().first_line);
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ outputLineDirective(out, node->getCondition()->getLine().first_line);
+ out << "while (";
+
+ node->getCondition()->traverse(this);
+
+ out << ");\n";
+ }
+
+ out << "}\n";
+
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+ mNestedLoopDepth--;
+
+ return false;
+}
+
+bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (visit == PreVisit)
+ {
+ TInfoSinkBase &out = getInfoSink();
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ out << "discard";
+ break;
+ case EOpBreak:
+ if (mNestedLoopDepth > 1)
+ {
+ mUsesNestedBreak = true;
+ }
+
+ if (mExcessiveLoopIndex)
+ {
+ out << "{Break";
+ mExcessiveLoopIndex->traverse(this);
+ out << " = true; break;}\n";
+ }
+ else
+ {
+ out << "break";
+ }
+ break;
+ case EOpContinue:
+ out << "continue";
+ break;
+ case EOpReturn:
+ if (node->getExpression())
+ {
+ ASSERT(!mInsideMain);
+ out << "return ";
+ }
+ else
+ {
+ if (mInsideMain && shaderNeedsGenerateOutput())
+ {
+ out << "return " << generateOutputCall();
+ }
+ else
+ {
+ out << "return";
+ }
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ return true;
+}
+
+// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
+// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
+// 254).
+bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
+{
+ const int MAX_LOOP_ITERATIONS = 254;
+
+ // Parse loops of the form:
+ // for(int index = initial; index [comparator] limit; index += increment)
+ TIntermSymbol *index = nullptr;
+ TOperator comparator = EOpNull;
+ int initial = 0;
+ int limit = 0;
+ int increment = 0;
+
+ // Parse index name and intial value
+ if (node->getInit())
+ {
+ TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
+
+ if (init)
+ {
+ TIntermSequence *sequence = init->getSequence();
+ TIntermTyped *variable = (*sequence)[0]->getAsTyped();
+
+ if (variable && variable->getQualifier() == EvqTemporary)
+ {
+ TIntermBinary *assign = variable->getAsBinaryNode();
+
+ if (assign->getOp() == EOpInitialize)
+ {
+ TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
+ TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
+
+ if (symbol && constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ index = symbol;
+ initial = constant->getIConst(0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Parse comparator and limit value
+ if (index != nullptr && node->getCondition())
+ {
+ TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+
+ if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
+ {
+ TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ comparator = test->getOp();
+ limit = constant->getIConst(0);
+ }
+ }
+ }
+ }
+
+ // Parse increment
+ if (index != nullptr && comparator != EOpNull && node->getExpression())
+ {
+ TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
+ TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
+
+ if (binaryTerminal)
+ {
+ TOperator op = binaryTerminal->getOp();
+ TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ int value = constant->getIConst(0);
+
+ switch (op)
+ {
+ case EOpAddAssign:
+ increment = value;
+ break;
+ case EOpSubAssign:
+ increment = -value;
+ break;
+ default:
+ UNIMPLEMENTED();
+ }
+ }
+ }
+ }
+ else if (unaryTerminal)
+ {
+ TOperator op = unaryTerminal->getOp();
+
+ switch (op)
+ {
+ case EOpPostIncrement:
+ increment = 1;
+ break;
+ case EOpPostDecrement:
+ increment = -1;
+ break;
+ case EOpPreIncrement:
+ increment = 1;
+ break;
+ case EOpPreDecrement:
+ increment = -1;
+ break;
+ default:
+ UNIMPLEMENTED();
+ }
+ }
+ }
+
+ if (index != nullptr && comparator != EOpNull && increment != 0)
+ {
+ if (comparator == EOpLessThanEqual)
+ {
+ comparator = EOpLessThan;
+ limit += 1;
+ }
+
+ if (comparator == EOpLessThan)
+ {
+ int iterations = (limit - initial) / increment;
+
+ if (iterations <= MAX_LOOP_ITERATIONS)
+ {
+ return false; // Not an excessive loop
+ }
+
+ TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
+ mExcessiveLoopIndex = index;
+
+ out << "{int ";
+ index->traverse(this);
+ out << ";\n"
+ "bool Break";
+ index->traverse(this);
+ out << " = false;\n";
+
+ bool firstLoopFragment = true;
+
+ while (iterations > 0)
+ {
+ int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
+
+ if (!firstLoopFragment)
+ {
+ out << "if (!Break";
+ index->traverse(this);
+ out << ") {\n";
+ }
+
+ if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
+ {
+ mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
+ }
+
+ // for(int index = initial; index < clampedLimit; index += increment)
+ const char *unroll =
+ mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
+
+ out << unroll << " for(";
+ index->traverse(this);
+ out << " = ";
+ out << initial;
+
+ out << "; ";
+ index->traverse(this);
+ out << " < ";
+ out << clampedLimit;
+
+ out << "; ";
+ index->traverse(this);
+ out << " += ";
+ out << increment;
+ out << ")\n";
+
+ outputLineDirective(out, node->getLine().first_line);
+ out << "{\n";
+
+ if (node->getBody())
+ {
+ node->getBody()->traverse(this);
+ }
+
+ outputLineDirective(out, node->getLine().first_line);
+ out << ";}\n";
+
+ if (!firstLoopFragment)
+ {
+ out << "}\n";
+ }
+
+ firstLoopFragment = false;
+
+ initial += MAX_LOOP_ITERATIONS * increment;
+ iterations -= MAX_LOOP_ITERATIONS;
+ }
+
+ out << "}";
+
+ mExcessiveLoopIndex = restoreIndex;
+
+ return true;
+ }
+ else
+ UNIMPLEMENTED();
+ }
+
+ return false; // Not handled as an excessive loop
+}
+
+void OutputHLSL::outputTriplet(TInfoSinkBase &out,
+ Visit visit,
+ const char *preString,
+ const char *inString,
+ const char *postString)
+{
+ if (visit == PreVisit)
+ {
+ out << preString;
+ }
+ else if (visit == InVisit)
+ {
+ out << inString;
+ }
+ else if (visit == PostVisit)
+ {
+ out << postString;
+ }
+}
+
+void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
+{
+ if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
+ {
+ out << "\n";
+ out << "#line " << line;
+
+ if (mSourcePath)
+ {
+ out << " \"" << mSourcePath << "\"";
+ }
+
+ out << "\n";
+ }
+}
+
+void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
+{
+ const TType &type = param->getType();
+ TQualifier qualifier = type.getQualifier();
+
+ TString nameStr = DecorateVariableIfNeeded(*param);
+ ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
+
+ if (IsSampler(type.getBasicType()))
+ {
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ // Samplers are passed as indices to the sampler array.
+ ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
+ out << "const uint " << nameStr << ArrayString(type);
+ return;
+ }
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
+ << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
+ << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
+ << ArrayString(type);
+ return;
+ }
+ }
+
+ // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
+ // buffer offset.
+ if (IsAtomicCounter(type.getBasicType()))
+ {
+ out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
+ << nameStr << "_offset";
+ }
+ else
+ {
+ out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
+ << ArrayString(type);
+ }
+
+ // If the structure parameter contains samplers, they need to be passed into the function as
+ // separate parameters. HLSL doesn't natively support samplers in structs.
+ if (type.isStructureContainingSamplers())
+ {
+ ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
+ TVector<const TVariable *> samplerSymbols;
+ std::string namePrefix = "angle";
+ namePrefix += nameStr.c_str();
+ type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
+ mSymbolTable);
+ for (const TVariable *sampler : samplerSymbols)
+ {
+ const TType &samplerType = sampler->getType();
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ out << ", const uint " << sampler->name() << ArrayString(samplerType);
+ }
+ else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ ASSERT(IsSampler(samplerType.getBasicType()));
+ out << ", " << QualifierString(qualifier) << " "
+ << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
+ << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
+ << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
+ << ArrayString(samplerType);
+ }
+ else
+ {
+ ASSERT(IsSampler(samplerType.getBasicType()));
+ out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
+ << sampler->name() << ArrayString(samplerType);
+ }
+ }
+ }
+}
+
+TString OutputHLSL::zeroInitializer(const TType &type) const
+{
+ TString string;
+
+ size_t size = type.getObjectSize();
+ if (size >= kZeroCount)
+ {
+ mUseZeroArray = true;
+ }
+ string = GetZeroInitializer(size).c_str();
+
+ return "{" + string + "}";
+}
+
+void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
+{
+ // Array constructors should have been already pruned from the code.
+ ASSERT(!node->getType().isArray());
+
+ if (visit == PreVisit)
+ {
+ TString constructorName;
+ if (node->getBasicType() == EbtStruct)
+ {
+ constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
+ }
+ else
+ {
+ constructorName =
+ mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
+ }
+ out << constructorName << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else if (visit == PostVisit)
+ {
+ out << ")";
+ }
+}
+
+const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
+ const TType &type,
+ const TConstantUnion *const constUnion)
+{
+ ASSERT(!type.isArray());
+
+ const TConstantUnion *constUnionIterated = constUnion;
+
+ const TStructure *structure = type.getStruct();
+ if (structure)
+ {
+ out << mStructureHLSL->addStructConstructor(*structure) << "(";
+
+ const TFieldList &fields = structure->fields();
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TType *fieldType = fields[i]->type();
+ constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
+
+ if (i != fields.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+ }
+ else
+ {
+ size_t size = type.getObjectSize();
+ bool writeType = size > 1;
+
+ if (writeType)
+ {
+ out << TypeString(type) << "(";
+ }
+ constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
+ if (writeType)
+ {
+ out << ")";
+ }
+ }
+
+ return constUnionIterated;
+}
+
+void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
+{
+ if (visit == PreVisit)
+ {
+ const char *opStr = GetOperatorString(op);
+ BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
+ out << "(";
+ }
+ else
+ {
+ outputTriplet(out, visit, nullptr, ", ", ")");
+ }
+}
+
+bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *expression)
+{
+ ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
+ const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
+
+ if (symbolInInitializer)
+ {
+ // Type already printed
+ out << "t" + str(mUniqueIndex) + " = ";
+ expression->traverse(this);
+ out << ", ";
+ symbolNode->traverse(this);
+ out << " = t" + str(mUniqueIndex);
+
+ mUniqueIndex++;
+ return true;
+ }
+
+ return false;
+}
+
+bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *initializer)
+{
+ if (initializer->hasConstantValue())
+ {
+ symbolNode->traverse(this);
+ out << ArrayString(symbolNode->getType());
+ out << " = {";
+ writeConstantUnionArray(out, initializer->getConstantValue(),
+ initializer->getType().getObjectSize());
+ out << "}";
+ return true;
+ }
+ return false;
+}
+
+TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
+{
+ const TFieldList &fields = structure.fields();
+
+ for (const auto &eqFunction : mStructEqualityFunctions)
+ {
+ if (eqFunction->structure == &structure)
+ {
+ return eqFunction->functionName;
+ }
+ }
+
+ const TString &structNameString = StructNameString(structure);
+
+ StructEqualityFunction *function = new StructEqualityFunction();
+ function->structure = &structure;
+ function->functionName = "angle_eq_" + structNameString;
+
+ TInfoSinkBase fnOut;
+
+ fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
+ << structNameString + " b)\n"
+ << "{\n"
+ " return ";
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TField *field = fields[i];
+ const TType *fieldType = field->type();
+
+ const TString &fieldNameA = "a." + Decorate(field->name());
+ const TString &fieldNameB = "b." + Decorate(field->name());
+
+ if (i > 0)
+ {
+ fnOut << " && ";
+ }
+
+ fnOut << "(";
+ outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
+ fnOut << fieldNameA;
+ outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
+ fnOut << fieldNameB;
+ outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
+ fnOut << ")";
+ }
+
+ fnOut << ";\n"
+ << "}\n";
+
+ function->functionDefinition = fnOut.c_str();
+
+ mStructEqualityFunctions.push_back(function);
+ mEqualityFunctions.push_back(function);
+
+ return function->functionName;
+}
+
+TString OutputHLSL::addArrayEqualityFunction(const TType &type)
+{
+ for (const auto &eqFunction : mArrayEqualityFunctions)
+ {
+ if (eqFunction->type == type)
+ {
+ return eqFunction->functionName;
+ }
+ }
+
+ TType elementType(type);
+ elementType.toArrayElementType();
+
+ ArrayHelperFunction *function = new ArrayHelperFunction();
+ function->type = type;
+
+ function->functionName = ArrayHelperFunctionName("angle_eq", type);
+
+ TInfoSinkBase fnOut;
+
+ const TString &typeName = TypeString(type);
+ fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
+ << ", " << typeName << " b" << ArrayString(type) << ")\n"
+ << "{\n"
+ " for (int i = 0; i < "
+ << type.getOutermostArraySize()
+ << "; ++i)\n"
+ " {\n"
+ " if (";
+
+ outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
+ fnOut << "a[i]";
+ outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
+ fnOut << "b[i]";
+ outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
+
+ fnOut << ") { return false; }\n"
+ " }\n"
+ " return true;\n"
+ "}\n";
+
+ function->functionDefinition = fnOut.c_str();
+
+ mArrayEqualityFunctions.push_back(function);
+ mEqualityFunctions.push_back(function);
+
+ return function->functionName;
+}
+
+TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
+{
+ for (const auto &assignFunction : mArrayAssignmentFunctions)
+ {
+ if (assignFunction.type == type)
+ {
+ return assignFunction.functionName;
+ }
+ }
+
+ TType elementType(type);
+ elementType.toArrayElementType();
+
+ ArrayHelperFunction function;
+ function.type = type;
+
+ function.functionName = ArrayHelperFunctionName("angle_assign", type);
+
+ TInfoSinkBase fnOut;
+
+ const TString &typeName = TypeString(type);
+ fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
+ << ", " << typeName << " b" << ArrayString(type) << ")\n"
+ << "{\n"
+ " for (int i = 0; i < "
+ << type.getOutermostArraySize()
+ << "; ++i)\n"
+ " {\n"
+ " ";
+
+ outputAssign(PreVisit, elementType, fnOut);
+ fnOut << "a[i]";
+ outputAssign(InVisit, elementType, fnOut);
+ fnOut << "b[i]";
+ outputAssign(PostVisit, elementType, fnOut);
+
+ fnOut << ";\n"
+ " }\n"
+ "}\n";
+
+ function.functionDefinition = fnOut.c_str();
+
+ mArrayAssignmentFunctions.push_back(function);
+
+ return function.functionName;
+}
+
+TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
+{
+ for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
+ {
+ if (constructIntoFunction.type == type)
+ {
+ return constructIntoFunction.functionName;
+ }
+ }
+
+ TType elementType(type);
+ elementType.toArrayElementType();
+
+ ArrayHelperFunction function;
+ function.type = type;
+
+ function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
+
+ TInfoSinkBase fnOut;
+
+ const TString &typeName = TypeString(type);
+ fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
+ for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
+ {
+ fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
+ }
+ fnOut << ")\n"
+ "{\n";
+
+ for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
+ {
+ fnOut << " ";
+ outputAssign(PreVisit, elementType, fnOut);
+ fnOut << "a[" << i << "]";
+ outputAssign(InVisit, elementType, fnOut);
+ fnOut << "b" << i;
+ outputAssign(PostVisit, elementType, fnOut);
+ fnOut << ";\n";
+ }
+ fnOut << "}\n";
+
+ function.functionDefinition = fnOut.c_str();
+
+ mArrayConstructIntoFunctions.push_back(function);
+
+ return function.functionName;
+}
+
+void OutputHLSL::ensureStructDefined(const TType &type)
+{
+ const TStructure *structure = type.getStruct();
+ if (structure)
+ {
+ ASSERT(type.getBasicType() == EbtStruct);
+ mStructureHLSL->ensureStructDefined(*structure);
+ }
+}
+
+bool OutputHLSL::shaderNeedsGenerateOutput() const
+{
+ return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
+}
+
+const char *OutputHLSL::generateOutputCall() const
+{
+ if (mShaderType == GL_VERTEX_SHADER)
+ {
+ return "generateOutput(input)";
+ }
+ else
+ {
+ return "generateOutput()";
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputHLSL.h b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.h
new file mode 100644
index 0000000000..7aaa303e5d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.h
@@ -0,0 +1,279 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_OUTPUTHLSL_H_
+#define COMPILER_TRANSLATOR_OUTPUTHLSL_H_
+
+#include <list>
+#include <map>
+#include <stack>
+
+#include "angle_gl.h"
+#include "compiler/translator/ASTMetadataHLSL.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/FlagStd140Structs.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/ShaderStorageBlockOutputHLSL.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+class BuiltInFunctionEmulator;
+
+namespace sh
+{
+class AtomicCounterFunctionHLSL;
+class ImageFunctionHLSL;
+class ResourcesHLSL;
+class StructureHLSL;
+class TextureFunctionHLSL;
+class TSymbolTable;
+class TVariable;
+class UnfoldShortCircuit;
+
+using ReferencedVariables = std::map<int, const TVariable *>;
+
+class OutputHLSL : public TIntermTraverser
+{
+ public:
+ OutputHLSL(sh::GLenum shaderType,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ const char *sourcePath,
+ ShShaderOutput outputType,
+ int numRenderTargets,
+ int maxDualSourceDrawBuffers,
+ const std::vector<Uniform> &uniforms,
+ ShCompileOptions compileOptions,
+ sh::WorkGroupSize workGroupSize,
+ TSymbolTable *symbolTable,
+ PerformanceDiagnostics *perfDiagnostics,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks);
+
+ ~OutputHLSL();
+
+ void output(TIntermNode *treeRoot, TInfoSinkBase &objSink);
+
+ const std::map<std::string, unsigned int> &getShaderStorageBlockRegisterMap() const;
+ const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const;
+ const std::map<std::string, unsigned int> &getUniformRegisterMap() const;
+ unsigned int getReadonlyImage2DRegisterIndex() const;
+ unsigned int getImage2DRegisterIndex() const;
+ const std::set<std::string> &getUsedImage2DFunctionNames() const;
+
+ TInfoSinkBase &getInfoSink()
+ {
+ ASSERT(!mInfoSinkStack.empty());
+ return *mInfoSinkStack.top();
+ }
+
+ protected:
+ friend class ShaderStorageBlockOutputHLSL;
+
+ TString zeroInitializer(const TType &type) const;
+
+ void writeReferencedAttributes(TInfoSinkBase &out) const;
+ void writeReferencedVaryings(TInfoSinkBase &out) const;
+ void header(TInfoSinkBase &out,
+ const std::vector<MappedStruct> &std140Structs,
+ const BuiltInFunctionEmulator *builtInFunctionEmulator) const;
+
+ void writeFloat(TInfoSinkBase &out, float f);
+ void writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion);
+ const TConstantUnion *writeConstantUnionArray(TInfoSinkBase &out,
+ const TConstantUnion *const constUnion,
+ const size_t size);
+
+ // Visit AST nodes and output their code to the body stream
+ void visitSymbol(TIntermSymbol *) override;
+ void visitConstantUnion(TIntermConstantUnion *) override;
+ bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+ bool visitUnary(Visit visit, TIntermUnary *) override;
+ bool visitTernary(Visit visit, TIntermTernary *) override;
+ bool visitIfElse(Visit visit, TIntermIfElse *) override;
+ bool visitSwitch(Visit visit, TIntermSwitch *) override;
+ bool visitCase(Visit visit, TIntermCase *) override;
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *) override;
+ bool visitBranch(Visit visit, TIntermBranch *) override;
+
+ bool handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node);
+
+ // Emit one of three strings depending on traverse phase. Called with literal strings so using
+ // const char* instead of TString.
+ void outputTriplet(TInfoSinkBase &out,
+ Visit visit,
+ const char *preString,
+ const char *inString,
+ const char *postString);
+ void outputLineDirective(TInfoSinkBase &out, int line);
+ void writeParameter(const TVariable *param, TInfoSinkBase &out);
+
+ void outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node);
+ const TConstantUnion *writeConstantUnion(TInfoSinkBase &out,
+ const TType &type,
+ const TConstantUnion *constUnion);
+
+ void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
+ void outputAssign(Visit visit, const TType &type, TInfoSinkBase &out);
+
+ void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op);
+
+ // Returns true if it found a 'same symbol' initializer (initializer that references the
+ // variable it's initting)
+ bool writeSameSymbolInitializer(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *expression);
+ // Returns true if variable initializer could be written using literal {} notation.
+ bool writeConstantInitialization(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *expression);
+
+ void writeIfElse(TInfoSinkBase &out, TIntermIfElse *node);
+
+ // Returns the function name
+ TString addStructEqualityFunction(const TStructure &structure);
+ TString addArrayEqualityFunction(const TType &type);
+ TString addArrayAssignmentFunction(const TType &type);
+ TString addArrayConstructIntoFunction(const TType &type);
+
+ // Ensures if the type is a struct, the struct is defined
+ void ensureStructDefined(const TType &type);
+
+ bool shaderNeedsGenerateOutput() const;
+ const char *generateOutputCall() const;
+
+ sh::GLenum mShaderType;
+ int mShaderVersion;
+ const TExtensionBehavior &mExtensionBehavior;
+ const char *mSourcePath;
+ const ShShaderOutput mOutputType;
+ ShCompileOptions mCompileOptions;
+
+ bool mInsideFunction;
+ bool mInsideMain;
+
+ // Output streams
+ TInfoSinkBase mHeader;
+ TInfoSinkBase mBody;
+ TInfoSinkBase mFooter;
+
+ // A stack is useful when we want to traverse in the header, or in helper functions, but not
+ // always write to the body. Instead use an InfoSink stack to keep our current state intact.
+ // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler.
+ std::stack<TInfoSinkBase *> mInfoSinkStack;
+
+ ReferencedVariables mReferencedUniforms;
+
+ // Indexed by block id, not instance id.
+ ReferencedInterfaceBlocks mReferencedUniformBlocks;
+
+ ReferencedVariables mReferencedAttributes;
+ ReferencedVariables mReferencedVaryings;
+ ReferencedVariables mReferencedOutputVariables;
+
+ StructureHLSL *mStructureHLSL;
+ ResourcesHLSL *mResourcesHLSL;
+ TextureFunctionHLSL *mTextureFunctionHLSL;
+ ImageFunctionHLSL *mImageFunctionHLSL;
+ AtomicCounterFunctionHLSL *mAtomicCounterFunctionHLSL;
+
+ // Parameters determining what goes in the header output
+ bool mUsesFragColor;
+ bool mUsesFragData;
+ bool mUsesDepthRange;
+ bool mUsesFragCoord;
+ bool mUsesPointCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesInstanceID;
+ bool mHasMultiviewExtensionEnabled;
+ bool mUsesViewID;
+ bool mUsesVertexID;
+ bool mUsesFragDepth;
+ bool mUsesNumWorkGroups;
+ bool mUsesWorkGroupID;
+ bool mUsesLocalInvocationID;
+ bool mUsesGlobalInvocationID;
+ bool mUsesLocalInvocationIndex;
+ bool mUsesXor;
+ bool mUsesDiscardRewriting;
+ bool mUsesNestedBreak;
+ bool mRequiresIEEEStrictCompiling;
+ mutable bool mUseZeroArray;
+ bool mUsesSecondaryColor;
+
+ int mNumRenderTargets;
+ int mMaxDualSourceDrawBuffers;
+
+ int mUniqueIndex; // For creating unique names
+
+ CallDAG mCallDag;
+ MetadataList mASTMetadataList;
+ ASTMetadataHLSL *mCurrentFunctionMetadata;
+ bool mOutputLod0Function;
+ bool mInsideDiscontinuousLoop;
+ int mNestedLoopDepth;
+
+ TIntermSymbol *mExcessiveLoopIndex;
+
+ TString structInitializerString(int indent, const TType &type, const TString &name) const;
+
+ struct HelperFunction
+ {
+ TString functionName;
+ TString functionDefinition;
+
+ virtual ~HelperFunction() {}
+ };
+
+ // A list of all equality comparison functions. It's important to preserve the order at
+ // which we add the functions, since nested structures call each other recursively, and
+ // structure equality functions may need to call array equality functions and vice versa.
+ // The ownership of the pointers is maintained by the type-specific arrays.
+ std::vector<HelperFunction *> mEqualityFunctions;
+
+ struct StructEqualityFunction : public HelperFunction
+ {
+ const TStructure *structure;
+ };
+ std::vector<StructEqualityFunction *> mStructEqualityFunctions;
+
+ struct ArrayHelperFunction : public HelperFunction
+ {
+ TType type;
+ };
+ std::vector<ArrayHelperFunction *> mArrayEqualityFunctions;
+
+ std::vector<ArrayHelperFunction> mArrayAssignmentFunctions;
+
+ // The construct-into functions are functions that fill an N-element array passed as an out
+ // parameter with the other N parameters of the function. This is used to work around that
+ // arrays can't be return values in HLSL.
+ std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions;
+
+ sh::WorkGroupSize mWorkGroupSize;
+
+ PerformanceDiagnostics *mPerfDiagnostics;
+
+ private:
+ TString generateStructMapping(const std::vector<MappedStruct> &std140Structs) const;
+ ImmutableString samplerNamePrefixFromStruct(TIntermTyped *node);
+ bool ancestorEvaluatesToSamplerInStruct();
+ // We need to do struct mapping when pass the struct to a function or copy the struct via
+ // assignment.
+ bool needStructMapping(TIntermTyped *node);
+
+ ShaderStorageBlockOutputHLSL *mSSBOOutputHLSL;
+ bool mNeedStructMapping;
+};
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputTree.cpp b/gfx/angle/checkout/src/compiler/translator/OutputTree.cpp
new file mode 100644
index 0000000000..6de64a660a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputTree.cpp
@@ -0,0 +1,699 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void OutputFunction(TInfoSinkBase &out, const char *str, const TFunction *func)
+{
+ const char *internal =
+ (func->symbolType() == SymbolType::AngleInternal) ? " (internal function)" : "";
+ out << str << internal << ": " << func->name() << " (symbol id " << func->uniqueId().get()
+ << ")";
+}
+
+// Two purposes:
+// 1. Show an example of how to iterate tree. Functions can also directly call traverse() on
+// children themselves to have finer grained control over the process than shown here, though
+// that's not recommended if it can be avoided.
+// 2. Print out a text based description of the tree.
+
+// The traverser subclass is used to carry along data from node to node in the traversal.
+class TOutputTraverser : public TIntermTraverser
+{
+ public:
+ TOutputTraverser(TInfoSinkBase &out)
+ : TIntermTraverser(true, false, false), mOut(out), mIndentDepth(0)
+ {}
+
+ protected:
+ void visitSymbol(TIntermSymbol *) override;
+ void visitConstantUnion(TIntermConstantUnion *) override;
+ bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+ bool visitUnary(Visit visit, TIntermUnary *) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+ bool visitIfElse(Visit visit, TIntermIfElse *node) override;
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+ bool visitCase(Visit visit, TIntermCase *node) override;
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *) override;
+ bool visitBlock(Visit visit, TIntermBlock *) override;
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *) override;
+ bool visitBranch(Visit visit, TIntermBranch *) override;
+
+ int getCurrentIndentDepth() const { return mIndentDepth + getCurrentTraversalDepth(); }
+
+ TInfoSinkBase &mOut;
+ int mIndentDepth;
+};
+
+//
+// Helper functions for printing, not part of traversing.
+//
+void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth)
+{
+ int i;
+
+ out.location(node->getLine().first_file, node->getLine().first_line);
+
+ for (i = 0; i < depth; ++i)
+ out << " ";
+}
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TOutputTraverser::visitSymbol(TIntermSymbol *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ if (node->variable().symbolType() == SymbolType::Empty)
+ {
+ mOut << "''";
+ }
+ else
+ {
+ mOut << "'" << node->getName() << "' ";
+ }
+ mOut << "(symbol id " << node->uniqueId().get() << ") ";
+ mOut << "(" << node->getType() << ")";
+ mOut << "\n";
+}
+
+bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "vector swizzle (";
+ node->writeOffsetsAsXYZW(&mOut);
+ mOut << ")";
+
+ mOut << " (" << node->getType() << ")";
+ mOut << "\n";
+ return true;
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ switch (node->getOp())
+ {
+ case EOpComma:
+ mOut << "comma";
+ break;
+ case EOpAssign:
+ mOut << "move second child to first child";
+ break;
+ case EOpInitialize:
+ mOut << "initialize first child with second child";
+ break;
+ case EOpAddAssign:
+ mOut << "add second child into first child";
+ break;
+ case EOpSubAssign:
+ mOut << "subtract second child into first child";
+ break;
+ case EOpMulAssign:
+ mOut << "multiply second child into first child";
+ break;
+ case EOpVectorTimesMatrixAssign:
+ mOut << "matrix mult second child into first child";
+ break;
+ case EOpVectorTimesScalarAssign:
+ mOut << "vector scale second child into first child";
+ break;
+ case EOpMatrixTimesScalarAssign:
+ mOut << "matrix scale second child into first child";
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ mOut << "matrix mult second child into first child";
+ break;
+ case EOpDivAssign:
+ mOut << "divide second child into first child";
+ break;
+ case EOpIModAssign:
+ mOut << "modulo second child into first child";
+ break;
+ case EOpBitShiftLeftAssign:
+ mOut << "bit-wise shift first child left by second child";
+ break;
+ case EOpBitShiftRightAssign:
+ mOut << "bit-wise shift first child right by second child";
+ break;
+ case EOpBitwiseAndAssign:
+ mOut << "bit-wise and second child into first child";
+ break;
+ case EOpBitwiseXorAssign:
+ mOut << "bit-wise xor second child into first child";
+ break;
+ case EOpBitwiseOrAssign:
+ mOut << "bit-wise or second child into first child";
+ break;
+
+ case EOpIndexDirect:
+ mOut << "direct index";
+ break;
+ case EOpIndexIndirect:
+ mOut << "indirect index";
+ break;
+ case EOpIndexDirectStruct:
+ mOut << "direct index for structure";
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ mOut << "direct index for interface block";
+ break;
+
+ case EOpAdd:
+ mOut << "add";
+ break;
+ case EOpSub:
+ mOut << "subtract";
+ break;
+ case EOpMul:
+ mOut << "component-wise multiply";
+ break;
+ case EOpDiv:
+ mOut << "divide";
+ break;
+ case EOpIMod:
+ mOut << "modulo";
+ break;
+ case EOpBitShiftLeft:
+ mOut << "bit-wise shift left";
+ break;
+ case EOpBitShiftRight:
+ mOut << "bit-wise shift right";
+ break;
+ case EOpBitwiseAnd:
+ mOut << "bit-wise and";
+ break;
+ case EOpBitwiseXor:
+ mOut << "bit-wise xor";
+ break;
+ case EOpBitwiseOr:
+ mOut << "bit-wise or";
+ break;
+
+ case EOpEqual:
+ mOut << "Compare Equal";
+ break;
+ case EOpNotEqual:
+ mOut << "Compare Not Equal";
+ break;
+ case EOpLessThan:
+ mOut << "Compare Less Than";
+ break;
+ case EOpGreaterThan:
+ mOut << "Compare Greater Than";
+ break;
+ case EOpLessThanEqual:
+ mOut << "Compare Less Than or Equal";
+ break;
+ case EOpGreaterThanEqual:
+ mOut << "Compare Greater Than or Equal";
+ break;
+
+ case EOpVectorTimesScalar:
+ mOut << "vector-scale";
+ break;
+ case EOpVectorTimesMatrix:
+ mOut << "vector-times-matrix";
+ break;
+ case EOpMatrixTimesVector:
+ mOut << "matrix-times-vector";
+ break;
+ case EOpMatrixTimesScalar:
+ mOut << "matrix-scale";
+ break;
+ case EOpMatrixTimesMatrix:
+ mOut << "matrix-multiply";
+ break;
+
+ case EOpLogicalOr:
+ mOut << "logical-or";
+ break;
+ case EOpLogicalXor:
+ mOut << "logical-xor";
+ break;
+ case EOpLogicalAnd:
+ mOut << "logical-and";
+ break;
+ default:
+ mOut << "<unknown op>";
+ }
+
+ mOut << " (" << node->getType() << ")";
+
+ mOut << "\n";
+
+ // Special handling for direct indexes. Because constant
+ // unions are not aware they are struct indexes, treat them
+ // here where we have that contextual knowledge.
+ if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
+ {
+ node->getLeft()->traverse(this);
+
+ TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
+ ASSERT(intermConstantUnion);
+
+ OutputTreeText(mOut, intermConstantUnion, getCurrentIndentDepth() + 1);
+
+ // The following code finds the field name from the constant union
+ const TConstantUnion *constantUnion = intermConstantUnion->getConstantValue();
+ const TStructure *structure = node->getLeft()->getType().getStruct();
+ const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
+ ASSERT(structure || interfaceBlock);
+
+ const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
+
+ const TField *field = fields[constantUnion->getIConst()];
+
+ mOut << constantUnion->getIConst() << " (field '" << field->name() << "')";
+
+ mOut << "\n";
+
+ return false;
+ }
+
+ return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ switch (node->getOp())
+ {
+ // Give verbose names for ops that have special syntax and some built-in functions that are
+ // easy to confuse with others, but mostly use GLSL names for functions.
+ case EOpNegative:
+ mOut << "Negate value";
+ break;
+ case EOpPositive:
+ mOut << "Positive sign";
+ break;
+ case EOpLogicalNot:
+ mOut << "negation";
+ break;
+ case EOpBitwiseNot:
+ mOut << "bit-wise not";
+ break;
+
+ case EOpPostIncrement:
+ mOut << "Post-Increment";
+ break;
+ case EOpPostDecrement:
+ mOut << "Post-Decrement";
+ break;
+ case EOpPreIncrement:
+ mOut << "Pre-Increment";
+ break;
+ case EOpPreDecrement:
+ mOut << "Pre-Decrement";
+ break;
+
+ case EOpArrayLength:
+ mOut << "Array length";
+ break;
+
+ case EOpLogicalNotComponentWise:
+ mOut << "component-wise not";
+ break;
+
+ default:
+ mOut << GetOperatorString(node->getOp());
+ break;
+ }
+
+ mOut << " (" << node->getType() << ")";
+
+ mOut << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Function Definition:\n";
+ return true;
+}
+
+bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Invariant Declaration:\n";
+ return true;
+}
+
+void TOutputTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ OutputFunction(mOut, "Function Prototype", node->getFunction());
+ mOut << " (" << node->getType() << ")";
+ mOut << "\n";
+ size_t paramCount = node->getFunction()->getParamCount();
+ for (size_t i = 0; i < paramCount; ++i)
+ {
+ const TVariable *param = node->getFunction()->getParam(i);
+ OutputTreeText(mOut, node, getCurrentIndentDepth() + 1);
+ mOut << "parameter: " << param->name() << " (" << param->getType() << ")";
+ }
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ if (node->getOp() == EOpNull)
+ {
+ mOut.prefix(SH_ERROR);
+ mOut << "node is still EOpNull!\n";
+ return true;
+ }
+
+ // Give verbose names for some built-in functions that are easy to confuse with others, but
+ // mostly use GLSL names for functions.
+ switch (node->getOp())
+ {
+ case EOpCallFunctionInAST:
+ OutputFunction(mOut, "Call an user-defined function", node->getFunction());
+ break;
+ case EOpCallInternalRawFunction:
+ OutputFunction(mOut, "Call an internal function with raw implementation",
+ node->getFunction());
+ break;
+ case EOpCallBuiltInFunction:
+ OutputFunction(mOut, "Call a built-in function", node->getFunction());
+ break;
+
+ case EOpConstruct:
+ // The type of the constructor will be printed below.
+ mOut << "Construct";
+ break;
+
+ case EOpEqualComponentWise:
+ mOut << "component-wise equal";
+ break;
+ case EOpNotEqualComponentWise:
+ mOut << "component-wise not equal";
+ break;
+ case EOpLessThanComponentWise:
+ mOut << "component-wise less than";
+ break;
+ case EOpGreaterThanComponentWise:
+ mOut << "component-wise greater than";
+ break;
+ case EOpLessThanEqualComponentWise:
+ mOut << "component-wise less than or equal";
+ break;
+ case EOpGreaterThanEqualComponentWise:
+ mOut << "component-wise greater than or equal";
+ break;
+
+ case EOpDot:
+ mOut << "dot product";
+ break;
+ case EOpCross:
+ mOut << "cross product";
+ break;
+ case EOpMulMatrixComponentWise:
+ mOut << "component-wise multiply";
+ break;
+
+ default:
+ mOut << GetOperatorString(node->getOp());
+ break;
+ }
+
+ mOut << " (" << node->getType() << ")";
+
+ mOut << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Code block\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Declaration\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ mOut << "Ternary selection";
+ mOut << " (" << node->getType() << ")\n";
+
+ ++mIndentDepth;
+
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ if (node->getTrueExpression())
+ {
+ mOut << "true case\n";
+ node->getTrueExpression()->traverse(this);
+ }
+ if (node->getFalseExpression())
+ {
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "false case\n";
+ node->getFalseExpression()->traverse(this);
+ }
+
+ --mIndentDepth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ mOut << "If test\n";
+
+ ++mIndentDepth;
+
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ if (node->getTrueBlock())
+ {
+ mOut << "true case\n";
+ node->getTrueBlock()->traverse(this);
+ }
+ else
+ {
+ mOut << "true case is null\n";
+ }
+
+ if (node->getFalseBlock())
+ {
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "false case\n";
+ node->getFalseBlock()->traverse(this);
+ }
+
+ --mIndentDepth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ mOut << "Switch\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ if (node->getCondition() == nullptr)
+ {
+ mOut << "Default\n";
+ }
+ else
+ {
+ mOut << "Case\n";
+ }
+
+ return true;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ size_t size = node->getType().getObjectSize();
+
+ for (size_t i = 0; i < size; i++)
+ {
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ switch (node->getConstantValue()[i].getType())
+ {
+ case EbtBool:
+ if (node->getConstantValue()[i].getBConst())
+ mOut << "true";
+ else
+ mOut << "false";
+
+ mOut << " ("
+ << "const bool"
+ << ")";
+ mOut << "\n";
+ break;
+ case EbtFloat:
+ mOut << node->getConstantValue()[i].getFConst();
+ mOut << " (const float)\n";
+ break;
+ case EbtInt:
+ mOut << node->getConstantValue()[i].getIConst();
+ mOut << " (const int)\n";
+ break;
+ case EbtUInt:
+ mOut << node->getConstantValue()[i].getUConst();
+ mOut << " (const uint)\n";
+ break;
+ case EbtYuvCscStandardEXT:
+ mOut << getYuvCscStandardEXTString(
+ node->getConstantValue()[i].getYuvCscStandardEXTConst());
+ mOut << " (const yuvCscStandardEXT)\n";
+ break;
+ default:
+ mOut.prefix(SH_ERROR);
+ mOut << "Unknown constant\n";
+ break;
+ }
+ }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ mOut << "Loop with condition ";
+ if (node->getType() == ELoopDoWhile)
+ mOut << "not ";
+ mOut << "tested first\n";
+
+ ++mIndentDepth;
+
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ if (node->getCondition())
+ {
+ mOut << "Loop Condition\n";
+ node->getCondition()->traverse(this);
+ }
+ else
+ {
+ mOut << "No loop condition\n";
+ }
+
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ if (node->getBody())
+ {
+ mOut << "Loop Body\n";
+ node->getBody()->traverse(this);
+ }
+ else
+ {
+ mOut << "No loop body\n";
+ }
+
+ if (node->getExpression())
+ {
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+ mOut << "Loop Terminal Expression\n";
+ node->getExpression()->traverse(this);
+ }
+
+ --mIndentDepth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+ OutputTreeText(mOut, node, getCurrentIndentDepth());
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ mOut << "Branch: Kill";
+ break;
+ case EOpBreak:
+ mOut << "Branch: Break";
+ break;
+ case EOpContinue:
+ mOut << "Branch: Continue";
+ break;
+ case EOpReturn:
+ mOut << "Branch: Return";
+ break;
+ default:
+ mOut << "Branch: Unknown Branch";
+ break;
+ }
+
+ if (node->getExpression())
+ {
+ mOut << " with expression\n";
+ ++mIndentDepth;
+ node->getExpression()->traverse(this);
+ --mIndentDepth;
+ }
+ else
+ {
+ mOut << "\n";
+ }
+
+ return false;
+}
+
+} // anonymous namespace
+
+void OutputTree(TIntermNode *root, TInfoSinkBase &out)
+{
+ TOutputTraverser it(out);
+ ASSERT(root);
+ root->traverse(&it);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/OutputTree.h b/gfx/angle/checkout/src/compiler/translator/OutputTree.h
new file mode 100644
index 0000000000..9f11989cb1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/OutputTree.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Output the AST intermediate representation of the GLSL code.
+
+#ifndef COMPILER_TRANSLATOR_OUTPUTTREE_H_
+#define COMPILER_TRANSLATOR_OUTPUTTREE_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TInfoSinkBase;
+
+// Output the AST along with metadata.
+void OutputTree(TIntermNode *root, TInfoSinkBase &out);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_OUTPUTTREE_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp b/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp
new file mode 100644
index 0000000000..5808c880d1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp
@@ -0,0 +1,6100 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ParseContext.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "common/mathutil.h"
+#include "compiler/preprocessor/SourceLocation.h"
+#include "compiler/translator/Declarator.h"
+#include "compiler/translator/ParseContext_autogen.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/ValidateGlobalInitializer.h"
+#include "compiler/translator/ValidateSwitch.h"
+#include "compiler/translator/glslang.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sub- vector and matrix fields
+//
+////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+
+const int kWebGLMaxStructNesting = 4;
+
+bool ContainsSampler(const TStructure *structType);
+
+bool ContainsSampler(const TType &type)
+{
+ if (IsSampler(type.getBasicType()))
+ {
+ return true;
+ }
+ if (type.getBasicType() == EbtStruct)
+ {
+ return ContainsSampler(type.getStruct());
+ }
+
+ return false;
+}
+
+bool ContainsSampler(const TStructure *structType)
+{
+ for (const auto &field : structType->fields())
+ {
+ if (ContainsSampler(*field->type()))
+ return true;
+ }
+ return false;
+}
+
+// Get a token from an image argument to use as an error message token.
+const char *GetImageArgumentToken(TIntermTyped *imageNode)
+{
+ ASSERT(IsImage(imageNode->getBasicType()));
+ while (imageNode->getAsBinaryNode() &&
+ (imageNode->getAsBinaryNode()->getOp() == EOpIndexIndirect ||
+ imageNode->getAsBinaryNode()->getOp() == EOpIndexDirect))
+ {
+ imageNode = imageNode->getAsBinaryNode()->getLeft();
+ }
+ TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode();
+ if (imageSymbol)
+ {
+ return imageSymbol->getName().data();
+ }
+ return "image";
+}
+
+bool CanSetDefaultPrecisionOnType(const TPublicType &type)
+{
+ if (!SupportsPrecision(type.getBasicType()))
+ {
+ return false;
+ }
+ if (type.getBasicType() == EbtUInt)
+ {
+ // ESSL 3.00.4 section 4.5.4
+ return false;
+ }
+ if (type.isAggregate())
+ {
+ // Not allowed to set for aggregate types
+ return false;
+ }
+ return true;
+}
+
+// Map input primitive types to input array sizes in a geometry shader.
+GLuint GetGeometryShaderInputArraySize(TLayoutPrimitiveType primitiveType)
+{
+ switch (primitiveType)
+ {
+ case EptPoints:
+ return 1u;
+ case EptLines:
+ return 2u;
+ case EptTriangles:
+ return 3u;
+ case EptLinesAdjacency:
+ return 4u;
+ case EptTrianglesAdjacency:
+ return 6u;
+ default:
+ UNREACHABLE();
+ return 0u;
+ }
+}
+
+bool IsBufferOrSharedVariable(TIntermTyped *var)
+{
+ if (var->isInterfaceBlock() || var->getQualifier() == EvqBuffer ||
+ var->getQualifier() == EvqShared)
+ {
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+// This tracks each binding point's current default offset for inheritance of subsequent
+// variables using the same binding, and keeps offsets unique and non overlapping.
+// See GLSL ES 3.1, section 4.4.6.
+class TParseContext::AtomicCounterBindingState
+{
+ public:
+ AtomicCounterBindingState() : mDefaultOffset(0) {}
+ // Inserts a new span and returns -1 if overlapping, else returns the starting offset of
+ // newly inserted span.
+ int insertSpan(int start, size_t length)
+ {
+ gl::RangeI newSpan(start, start + static_cast<int>(length));
+ for (const auto &span : mSpans)
+ {
+ if (newSpan.intersects(span))
+ {
+ return -1;
+ }
+ }
+ mSpans.push_back(newSpan);
+ mDefaultOffset = newSpan.high();
+ return start;
+ }
+ // Inserts a new span starting from the default offset.
+ int appendSpan(size_t length) { return insertSpan(mDefaultOffset, length); }
+ void setDefaultOffset(int offset) { mDefaultOffset = offset; }
+
+ private:
+ int mDefaultOffset;
+ std::vector<gl::RangeI> mSpans;
+};
+
+TParseContext::TParseContext(TSymbolTable &symt,
+ TExtensionBehavior &ext,
+ sh::GLenum type,
+ ShShaderSpec spec,
+ ShCompileOptions options,
+ bool checksPrecErrors,
+ TDiagnostics *diagnostics,
+ const ShBuiltInResources &resources)
+ : symbolTable(symt),
+ mDeferredNonEmptyDeclarationErrorCheck(false),
+ mShaderType(type),
+ mShaderSpec(spec),
+ mCompileOptions(options),
+ mShaderVersion(100),
+ mTreeRoot(nullptr),
+ mLoopNestingLevel(0),
+ mStructNestingLevel(0),
+ mSwitchNestingLevel(0),
+ mCurrentFunctionType(nullptr),
+ mFunctionReturnsValue(false),
+ mChecksPrecisionErrors(checksPrecErrors),
+ mFragmentPrecisionHighOnESSL1(false),
+ mDefaultUniformMatrixPacking(EmpColumnMajor),
+ mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
+ mDefaultBufferMatrixPacking(EmpColumnMajor),
+ mDefaultBufferBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
+ mDiagnostics(diagnostics),
+ mDirectiveHandler(ext,
+ *mDiagnostics,
+ mShaderVersion,
+ mShaderType,
+ resources.WEBGL_debug_shader_precision == 1),
+ mPreprocessor(mDiagnostics, &mDirectiveHandler, angle::pp::PreprocessorSettings(spec)),
+ mScanner(nullptr),
+ mMinProgramTexelOffset(resources.MinProgramTexelOffset),
+ mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
+ mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset),
+ mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset),
+ mComputeShaderLocalSizeDeclared(false),
+ mComputeShaderLocalSize(-1),
+ mNumViews(-1),
+ mMaxNumViews(resources.MaxViewsOVR),
+ mMaxImageUnits(resources.MaxImageUnits),
+ mMaxCombinedTextureImageUnits(resources.MaxCombinedTextureImageUnits),
+ mMaxUniformLocations(resources.MaxUniformLocations),
+ mMaxUniformBufferBindings(resources.MaxUniformBufferBindings),
+ mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings),
+ mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings),
+ mDeclaringFunction(false),
+ mGeometryShaderInputPrimitiveType(EptUndefined),
+ mGeometryShaderOutputPrimitiveType(EptUndefined),
+ mGeometryShaderInvocations(0),
+ mGeometryShaderMaxVertices(-1),
+ mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations),
+ mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices),
+ mFunctionBodyNewScope(false)
+{}
+
+TParseContext::~TParseContext() {}
+
+bool TParseContext::anyMultiviewExtensionAvailable()
+{
+ return isExtensionEnabled(TExtension::OVR_multiview) ||
+ isExtensionEnabled(TExtension::OVR_multiview2);
+}
+
+bool TParseContext::parseVectorFields(const TSourceLoc &line,
+ const ImmutableString &compString,
+ int vecSize,
+ TVector<int> *fieldOffsets)
+{
+ ASSERT(fieldOffsets);
+ size_t fieldCount = compString.length();
+ if (fieldCount > 4u)
+ {
+ error(line, "illegal vector field selection", compString);
+ return false;
+ }
+ fieldOffsets->resize(fieldCount);
+
+ enum
+ {
+ exyzw,
+ ergba,
+ estpq
+ } fieldSet[4];
+
+ for (unsigned int i = 0u; i < fieldOffsets->size(); ++i)
+ {
+ switch (compString[i])
+ {
+ case 'x':
+ (*fieldOffsets)[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ (*fieldOffsets)[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ (*fieldOffsets)[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ (*fieldOffsets)[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ (*fieldOffsets)[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ (*fieldOffsets)[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ (*fieldOffsets)[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ (*fieldOffsets)[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ (*fieldOffsets)[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ (*fieldOffsets)[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ (*fieldOffsets)[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ (*fieldOffsets)[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString);
+ return false;
+ }
+ }
+
+ for (unsigned int i = 0u; i < fieldOffsets->size(); ++i)
+ {
+ if ((*fieldOffsets)[i] >= vecSize)
+ {
+ error(line, "vector field selection out of range", compString);
+ return false;
+ }
+
+ if (i > 0)
+ {
+ if (fieldSet[i] != fieldSet[i - 1])
+ {
+ error(line, "illegal - vector component fields not from the same set", compString);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Errors
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Used by flex/bison to output all syntax and parsing errors.
+//
+void TParseContext::error(const TSourceLoc &loc, const char *reason, const char *token)
+{
+ mDiagnostics->error(loc, reason, token);
+}
+
+void TParseContext::error(const TSourceLoc &loc, const char *reason, const ImmutableString &token)
+{
+ mDiagnostics->error(loc, reason, token.data());
+}
+
+void TParseContext::warning(const TSourceLoc &loc, const char *reason, const char *token)
+{
+ mDiagnostics->warning(loc, reason, token);
+}
+
+void TParseContext::outOfRangeError(bool isError,
+ const TSourceLoc &loc,
+ const char *reason,
+ const char *token)
+{
+ if (isError)
+ {
+ error(loc, reason, token);
+ }
+ else
+ {
+ warning(loc, reason, token);
+ }
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(const TSourceLoc &line,
+ const char *op,
+ const TType &left,
+ const TType &right)
+{
+ TInfoSinkBase reasonStream;
+ reasonStream << "cannot convert from '" << right << "' to '" << left << "'";
+ error(line, reasonStream.c_str(), op);
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, const TType &operand)
+{
+ TInfoSinkBase reasonStream;
+ reasonStream << "wrong operand type - no operation '" << op
+ << "' exists that takes an operand of type " << operand
+ << " (or there is no acceptable conversion)";
+ error(line, reasonStream.c_str(), op);
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(const TSourceLoc &line,
+ const char *op,
+ const TType &left,
+ const TType &right)
+{
+ TInfoSinkBase reasonStream;
+ reasonStream << "wrong operand types - no operation '" << op
+ << "' exists that takes a left-hand operand of type '" << left
+ << "' and a right operand of type '" << right
+ << "' (or there is no acceptable conversion)";
+ error(line, reasonStream.c_str(), op);
+}
+
+void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
+ TPrecision precision,
+ TBasicType type)
+{
+ if (!mChecksPrecisionErrors)
+ return;
+
+ if (precision != EbpUndefined && !SupportsPrecision(type))
+ {
+ error(line, "illegal type for precision qualifier", getBasicString(type));
+ }
+
+ if (precision == EbpUndefined)
+ {
+ switch (type)
+ {
+ case EbtFloat:
+ error(line, "No precision specified for (float)", "");
+ return;
+ case EbtInt:
+ case EbtUInt:
+ UNREACHABLE(); // there's always a predeclared qualifier
+ error(line, "No precision specified (int)", "");
+ return;
+ default:
+ if (IsOpaqueType(type))
+ {
+ error(line, "No precision specified", getBasicString(type));
+ return;
+ }
+ }
+ }
+}
+
+void TParseContext::markStaticReadIfSymbol(TIntermNode *node)
+{
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ markStaticReadIfSymbol(swizzleNode->getOperand());
+ return;
+ }
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ markStaticReadIfSymbol(binaryNode->getLeft());
+ return;
+ default:
+ return;
+ }
+ }
+ TIntermSymbol *symbolNode = node->getAsSymbolNode();
+ if (symbolNode)
+ {
+ symbolTable.markStaticRead(symbolNode->variable());
+ }
+}
+
+// Both test and if necessary, spit out an error, to see if the node is really
+// an l-value that can be operated on this way.
+bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node)
+{
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand());
+ if (ok && swizzleNode->hasDuplicateOffsets())
+ {
+ error(line, " l-value of swizzle cannot have duplicate components", op);
+ return false;
+ }
+ return ok;
+ }
+
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ if (node->getMemoryQualifier().readonly)
+ {
+ error(line, "can't modify a readonly variable", op);
+ return false;
+ }
+ return checkCanBeLValue(line, op, binaryNode->getLeft());
+ default:
+ break;
+ }
+ error(line, " l-value required", op);
+ return false;
+ }
+
+ std::string message;
+ switch (node->getQualifier())
+ {
+ case EvqConst:
+ message = "can't modify a const";
+ break;
+ case EvqConstReadOnly:
+ message = "can't modify a const";
+ break;
+ case EvqAttribute:
+ message = "can't modify an attribute";
+ break;
+ case EvqFragmentIn:
+ case EvqVertexIn:
+ case EvqGeometryIn:
+ case EvqFlatIn:
+ case EvqSmoothIn:
+ case EvqCentroidIn:
+ message = "can't modify an input";
+ break;
+ case EvqUniform:
+ message = "can't modify a uniform";
+ break;
+ case EvqVaryingIn:
+ message = "can't modify a varying";
+ break;
+ case EvqFragCoord:
+ message = "can't modify gl_FragCoord";
+ break;
+ case EvqFrontFacing:
+ message = "can't modify gl_FrontFacing";
+ break;
+ case EvqPointCoord:
+ message = "can't modify gl_PointCoord";
+ break;
+ case EvqNumWorkGroups:
+ message = "can't modify gl_NumWorkGroups";
+ break;
+ case EvqWorkGroupSize:
+ message = "can't modify gl_WorkGroupSize";
+ break;
+ case EvqWorkGroupID:
+ message = "can't modify gl_WorkGroupID";
+ break;
+ case EvqLocalInvocationID:
+ message = "can't modify gl_LocalInvocationID";
+ break;
+ case EvqGlobalInvocationID:
+ message = "can't modify gl_GlobalInvocationID";
+ break;
+ case EvqLocalInvocationIndex:
+ message = "can't modify gl_LocalInvocationIndex";
+ break;
+ case EvqViewIDOVR:
+ message = "can't modify gl_ViewID_OVR";
+ break;
+ case EvqComputeIn:
+ message = "can't modify work group size variable";
+ break;
+ case EvqPerVertexIn:
+ message = "can't modify any member in gl_in";
+ break;
+ case EvqPrimitiveIDIn:
+ message = "can't modify gl_PrimitiveIDIn";
+ break;
+ case EvqInvocationID:
+ message = "can't modify gl_InvocationID";
+ break;
+ case EvqPrimitiveID:
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ message = "can't modify gl_PrimitiveID in a fragment shader";
+ }
+ break;
+ case EvqLayer:
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ message = "can't modify gl_Layer in a fragment shader";
+ }
+ break;
+ default:
+ //
+ // Type that can't be written to?
+ //
+ if (node->getBasicType() == EbtVoid)
+ {
+ message = "can't modify void";
+ }
+ if (IsOpaqueType(node->getBasicType()))
+ {
+ message = "can't modify a variable with type ";
+ message += getBasicString(node->getBasicType());
+ }
+ else if (node->getMemoryQualifier().readonly)
+ {
+ message = "can't modify a readonly variable";
+ }
+ }
+
+ ASSERT(binaryNode == nullptr && swizzleNode == nullptr);
+ TIntermSymbol *symNode = node->getAsSymbolNode();
+ if (message.empty() && symNode != nullptr)
+ {
+ symbolTable.markStaticWrite(symNode->variable());
+ return true;
+ }
+
+ std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
+ reasonStream << "l-value required";
+ if (!message.empty())
+ {
+ if (symNode)
+ {
+ // Symbol inside an expression can't be nameless.
+ ASSERT(symNode->variable().symbolType() != SymbolType::Empty);
+ const ImmutableString &symbol = symNode->getName();
+ reasonStream << " (" << message << " \"" << symbol << "\")";
+ }
+ else
+ {
+ reasonStream << " (" << message << ")";
+ }
+ }
+ std::string reason = reasonStream.str();
+ error(line, reason.c_str(), op);
+
+ return false;
+}
+
+// Both test, and if necessary spit out an error, to see if the node is really
+// a constant.
+void TParseContext::checkIsConst(TIntermTyped *node)
+{
+ if (node->getQualifier() != EvqConst)
+ {
+ error(node->getLine(), "constant expression required", "");
+ }
+}
+
+// Both test, and if necessary spit out an error, to see if the node is really
+// an integer.
+void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token)
+{
+ if (!node->isScalarInt())
+ {
+ error(node->getLine(), "integer expression required", token);
+ }
+}
+
+// Both test, and if necessary spit out an error, to see if we are currently
+// globally scoped.
+bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token)
+{
+ if (!symbolTable.atGlobalLevel())
+ {
+ error(line, "only allowed at global scope", token);
+ return false;
+ }
+ return true;
+}
+
+// ESSL 3.00.5 sections 3.8 and 3.9.
+// If it starts "gl_" or contains two consecutive underscores, it's reserved.
+// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a webgl shader.
+bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier)
+{
+ static const char *reservedErrMsg = "reserved built-in name";
+ if (identifier.beginsWith("gl_"))
+ {
+ error(line, reservedErrMsg, "gl_");
+ return false;
+ }
+ if (sh::IsWebGLBasedSpec(mShaderSpec))
+ {
+ if (identifier.beginsWith("webgl_"))
+ {
+ error(line, reservedErrMsg, "webgl_");
+ return false;
+ }
+ if (identifier.beginsWith("_webgl_"))
+ {
+ error(line, reservedErrMsg, "_webgl_");
+ return false;
+ }
+ }
+ if (identifier.contains("__"))
+ {
+ error(line,
+ "identifiers containing two consecutive underscores (__) are reserved as "
+ "possible future keywords",
+ identifier);
+ return false;
+ }
+ return true;
+}
+
+// Make sure the argument types are correct for constructing a specific type.
+bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
+ const TIntermSequence &arguments,
+ const TType &type)
+{
+ if (arguments.empty())
+ {
+ error(line, "constructor does not have any arguments", "constructor");
+ return false;
+ }
+
+ for (TIntermNode *arg : arguments)
+ {
+ markStaticReadIfSymbol(arg);
+ const TIntermTyped *argTyped = arg->getAsTyped();
+ ASSERT(argTyped != nullptr);
+ if (type.getBasicType() != EbtStruct && IsOpaqueType(argTyped->getBasicType()))
+ {
+ std::string reason("cannot convert a variable with type ");
+ reason += getBasicString(argTyped->getBasicType());
+ error(line, reason.c_str(), "constructor");
+ return false;
+ }
+ else if (argTyped->getMemoryQualifier().writeonly)
+ {
+ error(line, "cannot convert a variable with writeonly", "constructor");
+ return false;
+ }
+ if (argTyped->getBasicType() == EbtVoid)
+ {
+ error(line, "cannot convert a void", "constructor");
+ return false;
+ }
+ }
+
+ if (type.isArray())
+ {
+ // The size of an unsized constructor should already have been determined.
+ ASSERT(!type.isUnsizedArray());
+ if (static_cast<size_t>(type.getOutermostArraySize()) != arguments.size())
+ {
+ error(line, "array constructor needs one argument per array element", "constructor");
+ return false;
+ }
+ // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
+ // the array.
+ for (TIntermNode *const &argNode : arguments)
+ {
+ const TType &argType = argNode->getAsTyped()->getType();
+ if (mShaderVersion < 310 && argType.isArray())
+ {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return false;
+ }
+ if (!argType.isElementTypeOf(type))
+ {
+ error(line, "Array constructor argument has an incorrect type", "constructor");
+ return false;
+ }
+ }
+ }
+ else if (type.getBasicType() == EbtStruct)
+ {
+ const TFieldList &fields = type.getStruct()->fields();
+ if (fields.size() != arguments.size())
+ {
+ error(line,
+ "Number of constructor parameters does not match the number of structure fields",
+ "constructor");
+ return false;
+ }
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ if (i >= arguments.size() ||
+ arguments[i]->getAsTyped()->getType() != *fields[i]->type())
+ {
+ error(line, "Structure constructor arguments do not match structure fields",
+ "constructor");
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // We're constructing a scalar, vector, or matrix.
+
+ // Note: It's okay to have too many components available, but not okay to have unused
+ // arguments. 'full' will go to true when enough args have been seen. If we loop again,
+ // there is an extra argument, so 'overFull' will become true.
+
+ size_t size = 0;
+ bool full = false;
+ bool overFull = false;
+ bool matrixArg = false;
+ for (TIntermNode *arg : arguments)
+ {
+ const TIntermTyped *argTyped = arg->getAsTyped();
+ ASSERT(argTyped != nullptr);
+
+ if (argTyped->getBasicType() == EbtStruct)
+ {
+ error(line, "a struct cannot be used as a constructor argument for this type",
+ "constructor");
+ return false;
+ }
+ if (argTyped->getType().isArray())
+ {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return false;
+ }
+ if (argTyped->getType().isMatrix())
+ {
+ matrixArg = true;
+ }
+
+ size += argTyped->getType().getObjectSize();
+ if (full)
+ {
+ overFull = true;
+ }
+ if (size >= type.getObjectSize())
+ {
+ full = true;
+ }
+ }
+
+ if (type.isMatrix() && matrixArg)
+ {
+ if (arguments.size() != 1)
+ {
+ error(line, "constructing matrix from matrix can only take one argument",
+ "constructor");
+ return false;
+ }
+ }
+ else
+ {
+ if (size != 1 && size < type.getObjectSize())
+ {
+ error(line, "not enough data provided for construction", "constructor");
+ return false;
+ }
+ if (overFull)
+ {
+ error(line, "too many arguments", "constructor");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// This function checks to see if a void variable has been declared and raise an error message for
+// such a case
+//
+// returns true in case of an error
+//
+bool TParseContext::checkIsNonVoid(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ const TBasicType &type)
+{
+ if (type == EbtVoid)
+ {
+ error(line, "illegal use of type 'void'", identifier);
+ return false;
+ }
+
+ return true;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression
+// or not.
+bool TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type)
+{
+ if (type->getBasicType() != EbtBool || !type->isScalar())
+ {
+ error(line, "boolean expression expected", "");
+ return false;
+ }
+ return true;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression
+// or not.
+void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType)
+{
+ if (pType.getBasicType() != EbtBool || pType.isAggregate())
+ {
+ error(line, "boolean expression expected", "");
+ }
+}
+
+bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line,
+ const TTypeSpecifierNonArray &pType,
+ const char *reason)
+{
+ if (pType.type == EbtStruct)
+ {
+ if (ContainsSampler(pType.userDef))
+ {
+ std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
+ reasonStream << reason << " (structure contains a sampler)";
+ std::string reasonStr = reasonStream.str();
+ error(line, reasonStr.c_str(), getBasicString(pType.type));
+ return false;
+ }
+ // only samplers need to be checked from structs, since other opaque types can't be struct
+ // members.
+ return true;
+ }
+ else if (IsOpaqueType(pType.type))
+ {
+ error(line, reason, getBasicString(pType.type));
+ return false;
+ }
+
+ return true;
+}
+
+void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line,
+ const TPublicType &pType)
+{
+ if (pType.layoutQualifier.location != -1)
+ {
+ error(line, "location must only be specified for a single input or output variable",
+ "location");
+ }
+}
+
+void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location,
+ const TLayoutQualifier &layoutQualifier)
+{
+ if (layoutQualifier.location != -1)
+ {
+ const char *errorMsg = "invalid layout qualifier: only valid on program inputs and outputs";
+ if (mShaderVersion >= 310)
+ {
+ errorMsg =
+ "invalid layout qualifier: only valid on shader inputs, outputs, and uniforms";
+ }
+ error(location, errorMsg, "location");
+ }
+}
+
+void TParseContext::checkStd430IsForShaderStorageBlock(const TSourceLoc &location,
+ const TLayoutBlockStorage &blockStorage,
+ const TQualifier &qualifier)
+{
+ if (blockStorage == EbsStd430 && qualifier != EvqBuffer)
+ {
+ error(location, "The std430 layout is supported only for shader storage blocks.", "std430");
+ }
+}
+
+void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
+ TQualifier qualifier,
+ const TType &type)
+{
+ ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
+ if (IsOpaqueType(type.getBasicType()))
+ {
+ error(line, "opaque types cannot be output parameters", type.getBasicString());
+ }
+}
+
+// Do size checking for an array type's size.
+unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr)
+{
+ TIntermConstantUnion *constant = expr->getAsConstantUnion();
+
+ // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be
+ // safe against corner cases we still check for constant folding. Some interpretations of the
+ // spec have allowed constant expressions with side effects - like array length() method on a
+ // non-constant array.
+ if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt())
+ {
+ error(line, "array size must be a constant integer expression", "");
+ return 1u;
+ }
+
+ unsigned int size = 0u;
+
+ if (constant->getBasicType() == EbtUInt)
+ {
+ size = constant->getUConst(0);
+ }
+ else
+ {
+ int signedSize = constant->getIConst(0);
+
+ if (signedSize < 0)
+ {
+ error(line, "array size must be non-negative", "");
+ return 1u;
+ }
+
+ size = static_cast<unsigned int>(signedSize);
+ }
+
+ if (size == 0u)
+ {
+ error(line, "array size must be greater than zero", "");
+ return 1u;
+ }
+
+ // The size of arrays is restricted here to prevent issues further down the
+ // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
+ // 4096 registers so this should be reasonable even for aggressively optimizable code.
+ const unsigned int sizeLimit = 65536;
+
+ if (size > sizeLimit)
+ {
+ error(line, "array size too large", "");
+ return 1u;
+ }
+
+ return size;
+}
+
+// See if this qualifier can be an array.
+bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line,
+ const TPublicType &elementQualifier)
+{
+ if ((elementQualifier.qualifier == EvqAttribute) ||
+ (elementQualifier.qualifier == EvqVertexIn) ||
+ (elementQualifier.qualifier == EvqConst && mShaderVersion < 300))
+ {
+ error(line, "cannot declare arrays of this qualifier",
+ TType(elementQualifier).getQualifierString());
+ return false;
+ }
+
+ return true;
+}
+
+// See if this element type can be formed into an array.
+bool TParseContext::checkArrayElementIsNotArray(const TSourceLoc &line,
+ const TPublicType &elementType)
+{
+ if (mShaderVersion < 310 && elementType.isArray())
+ {
+ TInfoSinkBase typeString;
+ typeString << TType(elementType);
+ error(line, "cannot declare arrays of arrays", typeString.c_str());
+ return false;
+ }
+ return true;
+}
+
+// Check if this qualified element type can be formed into an array. This is only called when array
+// brackets are associated with an identifier in a declaration, like this:
+// float a[2];
+// Similar checks are done in addFullySpecifiedType for array declarations where the array brackets
+// are associated with the type, like this:
+// float[2] a;
+bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
+ const TPublicType &elementType)
+{
+ if (!checkArrayElementIsNotArray(indexLocation, elementType))
+ {
+ return false;
+ }
+ // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
+ // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
+ // 4.3.4).
+ // Geometry shader requires each user-defined input be declared as arrays or inside input
+ // blocks declared as arrays (GL_EXT_geometry_shader section 11.1gs.4.3). For the purposes of
+ // interface matching, such variables and blocks are treated as though they were not declared
+ // as arrays (GL_EXT_geometry_shader section 7.4.1).
+ if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
+ sh::IsVarying(elementType.qualifier) &&
+ !IsGeometryShaderInput(mShaderType, elementType.qualifier))
+ {
+ TInfoSinkBase typeString;
+ typeString << TType(elementType);
+ error(indexLocation, "cannot declare arrays of structs of this qualifier",
+ typeString.c_str());
+ return false;
+ }
+ return checkIsValidQualifierForArray(indexLocation, elementType);
+}
+
+// Enforce non-initializer type/qualifier rules.
+void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ TType *type)
+{
+ ASSERT(type != nullptr);
+ if (type->getQualifier() == EvqConst)
+ {
+ // Make the qualifier make sense.
+ type->setQualifier(EvqTemporary);
+
+ // Generate informative error messages for ESSL1.
+ // In ESSL3 arrays and structures containing arrays can be constant.
+ if (mShaderVersion < 300 && type->isStructureContainingArrays())
+ {
+ error(line,
+ "structures containing arrays may not be declared constant since they cannot be "
+ "initialized",
+ identifier);
+ }
+ else
+ {
+ error(line, "variables with qualifier 'const' must be initialized", identifier);
+ }
+ }
+ // This will make the type sized if it isn't sized yet.
+ checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized", identifier,
+ type);
+}
+
+// Do some simple checks that are shared between all variable declarations,
+// and update the symbol table.
+//
+// Returns true if declaring the variable succeeded.
+//
+bool TParseContext::declareVariable(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ const TType *type,
+ TVariable **variable)
+{
+ ASSERT((*variable) == nullptr);
+
+ (*variable) = new TVariable(&symbolTable, identifier, type, SymbolType::UserDefined);
+
+ ASSERT(type->getLayoutQualifier().index == -1 ||
+ (isExtensionEnabled(TExtension::EXT_blend_func_extended) &&
+ mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300));
+ if (type->getQualifier() == EvqFragmentOut)
+ {
+ if (type->getLayoutQualifier().index != -1 && type->getLayoutQualifier().location == -1)
+ {
+ error(line,
+ "If index layout qualifier is specified for a fragment output, location must "
+ "also be specified.",
+ "index");
+ return false;
+ }
+ }
+ else
+ {
+ checkIndexIsNotSpecified(line, type->getLayoutQualifier().index);
+ }
+
+ checkBindingIsValid(line, *type);
+
+ bool needsReservedCheck = true;
+
+ // gl_LastFragData may be redeclared with a new precision qualifier
+ if (type->isArray() && identifier.beginsWith("gl_LastFragData"))
+ {
+ const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
+ symbolTable.findBuiltIn(ImmutableString("gl_MaxDrawBuffers"), mShaderVersion));
+ if (type->isArrayOfArrays())
+ {
+ error(line, "redeclaration of gl_LastFragData as an array of arrays", identifier);
+ return false;
+ }
+ else if (static_cast<int>(type->getOutermostArraySize()) ==
+ maxDrawBuffers->getConstPointer()->getIConst())
+ {
+ if (const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
+ {
+ needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->extension());
+ }
+ }
+ else
+ {
+ error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
+ identifier);
+ return false;
+ }
+ }
+
+ if (needsReservedCheck && !checkIsNotReserved(line, identifier))
+ return false;
+
+ if (!symbolTable.declare(*variable))
+ {
+ error(line, "redefinition", identifier);
+ return false;
+ }
+
+ if (!checkIsNonVoid(line, identifier, type->getBasicType()))
+ return false;
+
+ return true;
+}
+
+void TParseContext::checkIsParameterQualifierValid(
+ const TSourceLoc &line,
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TType *type)
+{
+ // The only parameter qualifiers a parameter can have are in, out, inout or const.
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics);
+
+ if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
+ {
+ checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type);
+ }
+
+ if (!IsImage(type->getBasicType()))
+ {
+ checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, line);
+ }
+ else
+ {
+ type->setMemoryQualifier(typeQualifier.memoryQualifier);
+ }
+
+ type->setQualifier(typeQualifier.qualifier);
+
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ type->setPrecision(typeQualifier.precision);
+ }
+}
+
+template <size_t size>
+bool TParseContext::checkCanUseOneOfExtensions(const TSourceLoc &line,
+ const std::array<TExtension, size> &extensions)
+{
+ ASSERT(!extensions.empty());
+ const TExtensionBehavior &extBehavior = extensionBehavior();
+
+ bool canUseWithWarning = false;
+ bool canUseWithoutWarning = false;
+
+ const char *errorMsgString = "";
+ TExtension errorMsgExtension = TExtension::UNDEFINED;
+
+ for (TExtension extension : extensions)
+ {
+ auto extIter = extBehavior.find(extension);
+ if (canUseWithWarning)
+ {
+ // We already have an extension that we can use, but with a warning.
+ // See if we can use the alternative extension without a warning.
+ if (extIter == extBehavior.end())
+ {
+ continue;
+ }
+ if (extIter->second == EBhEnable || extIter->second == EBhRequire)
+ {
+ canUseWithoutWarning = true;
+ break;
+ }
+ continue;
+ }
+ if (extIter == extBehavior.end())
+ {
+ errorMsgString = "extension is not supported";
+ errorMsgExtension = extension;
+ }
+ else if (extIter->second == EBhUndefined || extIter->second == EBhDisable)
+ {
+ errorMsgString = "extension is disabled";
+ errorMsgExtension = extension;
+ }
+ else if (extIter->second == EBhWarn)
+ {
+ errorMsgExtension = extension;
+ canUseWithWarning = true;
+ }
+ else
+ {
+ ASSERT(extIter->second == EBhEnable || extIter->second == EBhRequire);
+ canUseWithoutWarning = true;
+ break;
+ }
+ }
+
+ if (canUseWithoutWarning)
+ {
+ return true;
+ }
+ if (canUseWithWarning)
+ {
+ warning(line, "extension is being used", GetExtensionNameString(errorMsgExtension));
+ return true;
+ }
+ error(line, errorMsgString, GetExtensionNameString(errorMsgExtension));
+ return false;
+}
+
+template bool TParseContext::checkCanUseOneOfExtensions(
+ const TSourceLoc &line,
+ const std::array<TExtension, 1> &extensions);
+template bool TParseContext::checkCanUseOneOfExtensions(
+ const TSourceLoc &line,
+ const std::array<TExtension, 2> &extensions);
+template bool TParseContext::checkCanUseOneOfExtensions(
+ const TSourceLoc &line,
+ const std::array<TExtension, 3> &extensions);
+
+bool TParseContext::checkCanUseExtension(const TSourceLoc &line, TExtension extension)
+{
+ ASSERT(extension != TExtension::UNDEFINED);
+ return checkCanUseOneOfExtensions(line, std::array<TExtension, 1u>{{extension}});
+}
+
+// ESSL 3.00.6 section 4.8 Empty Declarations: "The combinations of qualifiers that cause
+// compile-time or link-time errors are the same whether or not the declaration is empty".
+// This function implements all the checks that are done on qualifiers regardless of if the
+// declaration is empty.
+void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifier,
+ const sh::TLayoutQualifier &layoutQualifier,
+ const TSourceLoc &location)
+{
+ if (qualifier == EvqShared && !layoutQualifier.isEmpty())
+ {
+ error(location, "Shared memory declarations cannot have layout specified", "layout");
+ }
+
+ if (layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ error(location, "layout qualifier only valid for interface blocks",
+ getMatrixPackingString(layoutQualifier.matrixPacking));
+ return;
+ }
+
+ if (layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(location, "layout qualifier only valid for interface blocks",
+ getBlockStorageString(layoutQualifier.blockStorage));
+ return;
+ }
+
+ if (qualifier == EvqFragmentOut)
+ {
+ if (layoutQualifier.location != -1 && layoutQualifier.yuv == true)
+ {
+ error(location, "invalid layout qualifier combination", "yuv");
+ return;
+ }
+ }
+ else
+ {
+ checkYuvIsNotSpecified(location, layoutQualifier.yuv);
+ }
+
+ // If multiview extension is enabled, "in" qualifier is allowed in the vertex shader in previous
+ // parsing steps. So it needs to be checked here.
+ if (anyMultiviewExtensionAvailable() && mShaderVersion < 300 && qualifier == EvqVertexIn)
+ {
+ error(location, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+ }
+
+ bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut;
+ if (mShaderVersion >= 310)
+ {
+ canHaveLocation = canHaveLocation || qualifier == EvqUniform || IsVarying(qualifier);
+ // We're not checking whether the uniform location is in range here since that depends on
+ // the type of the variable.
+ // The type can only be fully determined for non-empty declarations.
+ }
+ if (!canHaveLocation)
+ {
+ checkLocationIsNotSpecified(location, layoutQualifier);
+ }
+}
+
+void TParseContext::atomicCounterQualifierErrorCheck(const TPublicType &publicType,
+ const TSourceLoc &location)
+{
+ if (publicType.precision != EbpHigh)
+ {
+ error(location, "Can only be highp", "atomic counter");
+ }
+ // dEQP enforces compile error if location is specified. See uniform_location.test.
+ if (publicType.layoutQualifier.location != -1)
+ {
+ error(location, "location must not be set for atomic_uint", "layout");
+ }
+ if (publicType.layoutQualifier.binding == -1)
+ {
+ error(location, "no binding specified", "atomic counter");
+ }
+}
+
+void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location)
+{
+ if (type.isUnsizedArray())
+ {
+ // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
+ // error. It is assumed that this applies to empty declarations as well.
+ error(location, "empty array declaration needs to specify a size", "");
+ }
+
+ if (type.getQualifier() != EvqFragmentOut)
+ {
+ checkIndexIsNotSpecified(location, type.getLayoutQualifier().index);
+ }
+}
+
+// These checks are done for all declarations that are non-empty. They're done for non-empty
+// declarations starting a declarator list, and declarators that follow an empty declaration.
+void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation)
+{
+ switch (publicType.qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqAttribute:
+ case EvqVertexIn:
+ case EvqFragmentOut:
+ case EvqComputeIn:
+ if (publicType.getBasicType() == EbtStruct)
+ {
+ error(identifierLocation, "cannot be used with a structure",
+ getQualifierString(publicType.qualifier));
+ return;
+ }
+ break;
+ case EvqBuffer:
+ if (publicType.getBasicType() != EbtInterfaceBlock)
+ {
+ error(identifierLocation,
+ "cannot declare buffer variables at global scope(outside a block)",
+ getQualifierString(publicType.qualifier));
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ std::string reason(getBasicString(publicType.getBasicType()));
+ reason += "s must be uniform";
+ if (publicType.qualifier != EvqUniform &&
+ !checkIsNotOpaqueType(identifierLocation, publicType.typeSpecifierNonArray, reason.c_str()))
+ {
+ return;
+ }
+
+ if ((publicType.qualifier != EvqTemporary && publicType.qualifier != EvqGlobal &&
+ publicType.qualifier != EvqConst) &&
+ publicType.getBasicType() == EbtYuvCscStandardEXT)
+ {
+ error(identifierLocation, "cannot be used with a yuvCscStandardEXT",
+ getQualifierString(publicType.qualifier));
+ return;
+ }
+
+ if (mShaderVersion >= 310 && publicType.qualifier == EvqUniform)
+ {
+ // Valid uniform declarations can't be unsized arrays since uniforms can't be initialized.
+ // But invalid shaders may still reach here with an unsized array declaration.
+ TType type(publicType);
+ if (!type.isUnsizedArray())
+ {
+ checkUniformLocationInRange(identifierLocation, type.getLocationCount(),
+ publicType.layoutQualifier);
+ }
+ }
+
+ // check for layout qualifier issues
+ const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
+
+ if (IsImage(publicType.getBasicType()))
+ {
+
+ switch (layoutQualifier.imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ case EiifRGBA8:
+ case EiifRGBA8_SNORM:
+ if (!IsFloatImage(publicType.getBasicType()))
+ {
+ error(identifierLocation,
+ "internal image format requires a floating image type",
+ getBasicString(publicType.getBasicType()));
+ return;
+ }
+ break;
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ if (!IsIntegerImage(publicType.getBasicType()))
+ {
+ error(identifierLocation,
+ "internal image format requires an integer image type",
+ getBasicString(publicType.getBasicType()));
+ return;
+ }
+ break;
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ if (!IsUnsignedImage(publicType.getBasicType()))
+ {
+ error(identifierLocation,
+ "internal image format requires an unsigned image type",
+ getBasicString(publicType.getBasicType()));
+ return;
+ }
+ break;
+ case EiifUnspecified:
+ error(identifierLocation, "layout qualifier", "No image internal format specified");
+ return;
+ default:
+ error(identifierLocation, "layout qualifier", "unrecognized token");
+ return;
+ }
+
+ // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
+ switch (layoutQualifier.imageInternalFormat)
+ {
+ case EiifR32F:
+ case EiifR32I:
+ case EiifR32UI:
+ break;
+ default:
+ if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly)
+ {
+ error(identifierLocation, "layout qualifier",
+ "Except for images with the r32f, r32i and r32ui format qualifiers, "
+ "image variables must be qualified readonly and/or writeonly");
+ return;
+ }
+ break;
+ }
+ }
+ else
+ {
+ checkInternalFormatIsNotSpecified(identifierLocation, layoutQualifier.imageInternalFormat);
+ checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation);
+ }
+
+ if (IsAtomicCounter(publicType.getBasicType()))
+ {
+ atomicCounterQualifierErrorCheck(publicType, identifierLocation);
+ }
+ else
+ {
+ checkOffsetIsNotSpecified(identifierLocation, layoutQualifier.offset);
+ }
+}
+
+void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type)
+{
+ TLayoutQualifier layoutQualifier = type.getLayoutQualifier();
+ // Note that the ESSL 3.10 section 4.4.5 is not particularly clear on how the binding qualifier
+ // on arrays of arrays should be handled. We interpret the spec so that the binding value is
+ // incremented for each element of the innermost nested arrays. This is in line with how arrays
+ // of arrays of blocks are specified to behave in GLSL 4.50 and a conservative interpretation
+ // when it comes to which shaders are accepted by the compiler.
+ int arrayTotalElementCount = type.getArraySizeProduct();
+ if (IsImage(type.getBasicType()))
+ {
+ checkImageBindingIsValid(identifierLocation, layoutQualifier.binding,
+ arrayTotalElementCount);
+ }
+ else if (IsSampler(type.getBasicType()))
+ {
+ checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding,
+ arrayTotalElementCount);
+ }
+ else if (IsAtomicCounter(type.getBasicType()))
+ {
+ checkAtomicCounterBindingIsValid(identifierLocation, layoutQualifier.binding);
+ }
+ else
+ {
+ ASSERT(!IsOpaqueType(type.getBasicType()));
+ checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding);
+ }
+}
+
+void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
+ const ImmutableString &layoutQualifierName,
+ int versionRequired)
+{
+
+ if (mShaderVersion < versionRequired)
+ {
+ error(location, "invalid layout qualifier: not supported", layoutQualifierName);
+ }
+}
+
+bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
+ const TLayoutQualifier &layoutQualifier)
+{
+ const sh::WorkGroupSize &localSize = layoutQualifier.localSize;
+ for (size_t i = 0u; i < localSize.size(); ++i)
+ {
+ if (localSize[i] != -1)
+ {
+ error(location,
+ "invalid layout qualifier: only valid when used with 'in' in a compute shader "
+ "global layout declaration",
+ getWorkGroupSizeString(i));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location,
+ TLayoutImageInternalFormat internalFormat)
+{
+ if (internalFormat != EiifUnspecified)
+ {
+ error(location, "invalid layout qualifier: only valid when used with images",
+ getImageInternalFormatString(internalFormat));
+ }
+}
+
+void TParseContext::checkIndexIsNotSpecified(const TSourceLoc &location, int index)
+{
+ if (index != -1)
+ {
+ error(location,
+ "invalid layout qualifier: only valid when used with a fragment shader output in "
+ "ESSL version >= 3.00 and EXT_blend_func_extended is enabled",
+ "index");
+ }
+}
+
+void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding)
+{
+ if (binding != -1)
+ {
+ error(location,
+ "invalid layout qualifier: only valid when used with opaque types or blocks",
+ "binding");
+ }
+}
+
+void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int offset)
+{
+ if (offset != -1)
+ {
+ error(location, "invalid layout qualifier: only valid when used with atomic counters",
+ "offset");
+ }
+}
+
+void TParseContext::checkImageBindingIsValid(const TSourceLoc &location,
+ int binding,
+ int arrayTotalElementCount)
+{
+ // Expects arraySize to be 1 when setting binding for only a single variable.
+ if (binding >= 0 && binding + arrayTotalElementCount > mMaxImageUnits)
+ {
+ error(location, "image binding greater than gl_MaxImageUnits", "binding");
+ }
+}
+
+void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location,
+ int binding,
+ int arrayTotalElementCount)
+{
+ // Expects arraySize to be 1 when setting binding for only a single variable.
+ if (binding >= 0 && binding + arrayTotalElementCount > mMaxCombinedTextureImageUnits)
+ {
+ error(location, "sampler binding greater than maximum texture units", "binding");
+ }
+}
+
+void TParseContext::checkBlockBindingIsValid(const TSourceLoc &location,
+ const TQualifier &qualifier,
+ int binding,
+ int arraySize)
+{
+ int size = (arraySize == 0 ? 1 : arraySize);
+ if (qualifier == EvqUniform)
+ {
+ if (binding + size > mMaxUniformBufferBindings)
+ {
+ error(location, "uniform block binding greater than MAX_UNIFORM_BUFFER_BINDINGS",
+ "binding");
+ }
+ }
+ else if (qualifier == EvqBuffer)
+ {
+ if (binding + size > mMaxShaderStorageBufferBindings)
+ {
+ error(location,
+ "shader storage block binding greater than MAX_SHADER_STORAGE_BUFFER_BINDINGS",
+ "binding");
+ }
+ }
+}
+void TParseContext::checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding)
+{
+ if (binding >= mMaxAtomicCounterBindings)
+ {
+ error(location, "atomic counter binding greater than gl_MaxAtomicCounterBindings",
+ "binding");
+ }
+}
+
+void TParseContext::checkUniformLocationInRange(const TSourceLoc &location,
+ int objectLocationCount,
+ const TLayoutQualifier &layoutQualifier)
+{
+ int loc = layoutQualifier.location;
+ if (loc >= 0 && loc + objectLocationCount > mMaxUniformLocations)
+ {
+ error(location, "Uniform location out of range", "location");
+ }
+}
+
+void TParseContext::checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv)
+{
+ if (yuv != false)
+ {
+ error(location, "invalid layout qualifier: only valid on program outputs", "yuv");
+ }
+}
+
+void TParseContext::functionCallRValueLValueErrorCheck(const TFunction *fnCandidate,
+ TIntermAggregate *fnCall)
+{
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
+ {
+ TQualifier qual = fnCandidate->getParam(i)->getType().getQualifier();
+ TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped();
+ bool argumentIsRead = (IsQualifierUnspecified(qual) || qual == EvqIn || qual == EvqInOut ||
+ qual == EvqConstReadOnly);
+ if (argumentIsRead)
+ {
+ markStaticReadIfSymbol(argument);
+ if (!IsImage(argument->getBasicType()))
+ {
+ if (argument->getMemoryQualifier().writeonly)
+ {
+ error(argument->getLine(),
+ "Writeonly value cannot be passed for 'in' or 'inout' parameters.",
+ fnCall->functionName());
+ return;
+ }
+ }
+ }
+ if (qual == EvqOut || qual == EvqInOut)
+ {
+ if (!checkCanBeLValue(argument->getLine(), "assign", argument))
+ {
+ error(argument->getLine(),
+ "Constant value cannot be passed for 'out' or 'inout' parameters.",
+ fnCall->functionName());
+ return;
+ }
+ }
+ }
+}
+
+void TParseContext::checkInvariantVariableQualifier(bool invariant,
+ const TQualifier qualifier,
+ const TSourceLoc &invariantLocation)
+{
+ if (!invariant)
+ return;
+
+ if (mShaderVersion < 300)
+ {
+ // input variables in the fragment shader can be also qualified as invariant
+ if (!sh::CanBeInvariantESSL1(qualifier))
+ {
+ error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
+ }
+ }
+ else
+ {
+ if (!sh::CanBeInvariantESSL3OrGreater(qualifier))
+ {
+ error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
+ }
+ }
+}
+
+bool TParseContext::isExtensionEnabled(TExtension extension) const
+{
+ return IsExtensionEnabled(extensionBehavior(), extension);
+}
+
+void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
+ const char *extName,
+ const char *behavior)
+{
+ angle::pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ mDirectiveHandler.handleExtension(srcLoc, extName, behavior);
+}
+
+void TParseContext::handlePragmaDirective(const TSourceLoc &loc,
+ const char *name,
+ const char *value,
+ bool stdgl)
+{
+ angle::pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl);
+}
+
+sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const
+{
+ sh::WorkGroupSize result(-1);
+ for (size_t i = 0u; i < result.size(); ++i)
+ {
+ if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1)
+ {
+ result[i] = 1;
+ }
+ else
+ {
+ result[i] = mComputeShaderLocalSize[i];
+ }
+ }
+ return result;
+}
+
+TIntermConstantUnion *TParseContext::addScalarLiteral(const TConstantUnion *constantUnion,
+ const TSourceLoc &line)
+{
+ TIntermConstantUnion *node = new TIntermConstantUnion(
+ constantUnion, TType(constantUnion->getType(), EbpUndefined, EvqConst));
+ node->setLine(line);
+ return node;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Non-Errors.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
+ const ImmutableString &name,
+ const TSymbol *symbol)
+{
+ if (!symbol)
+ {
+ error(location, "undeclared identifier", name);
+ return nullptr;
+ }
+
+ if (!symbol->isVariable())
+ {
+ error(location, "variable expected", name);
+ return nullptr;
+ }
+
+ const TVariable *variable = static_cast<const TVariable *>(symbol);
+
+ if (variable->extension() != TExtension::UNDEFINED)
+ {
+ checkCanUseExtension(location, variable->extension());
+ }
+
+ // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables
+ if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared &&
+ variable->getType().getQualifier() == EvqWorkGroupSize)
+ {
+ error(location,
+ "It is an error to use gl_WorkGroupSize before declaring the local group size",
+ "gl_WorkGroupSize");
+ }
+ return variable;
+}
+
+TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
+ const ImmutableString &name,
+ const TSymbol *symbol)
+{
+ const TVariable *variable = getNamedVariable(location, name, symbol);
+
+ if (!variable)
+ {
+ TIntermTyped *node = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+ node->setLine(location);
+ return node;
+ }
+
+ const TType &variableType = variable->getType();
+ TIntermTyped *node = nullptr;
+
+ if (variable->getConstPointer() && variableType.canReplaceWithConstantUnion())
+ {
+ const TConstantUnion *constArray = variable->getConstPointer();
+ node = new TIntermConstantUnion(constArray, variableType);
+ }
+ else if (variableType.getQualifier() == EvqWorkGroupSize && mComputeShaderLocalSizeDeclared)
+ {
+ // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it
+ // needs to be added to the AST as a constant and not as a symbol.
+ sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize();
+ TConstantUnion *constArray = new TConstantUnion[3];
+ for (size_t i = 0; i < 3; ++i)
+ {
+ constArray[i].setUConst(static_cast<unsigned int>(workGroupSize[i]));
+ }
+
+ ASSERT(variableType.getBasicType() == EbtUInt);
+ ASSERT(variableType.getObjectSize() == 3);
+
+ TType type(variableType);
+ type.setQualifier(EvqConst);
+ node = new TIntermConstantUnion(constArray, type);
+ }
+ else if ((mGeometryShaderInputPrimitiveType != EptUndefined) &&
+ (variableType.getQualifier() == EvqPerVertexIn))
+ {
+ ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr);
+ node = new TIntermSymbol(symbolTable.getGlInVariableWithArraySize());
+ }
+ else
+ {
+ node = new TIntermSymbol(variable);
+ }
+ ASSERT(node != nullptr);
+ node->setLine(location);
+ return node;
+}
+
+// Initializers show up in several places in the grammar. Have one set of
+// code to handle them here.
+//
+// Returns true on success.
+bool TParseContext::executeInitializer(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ TType *type,
+ TIntermTyped *initializer,
+ TIntermBinary **initNode)
+{
+ ASSERT(initNode != nullptr);
+ ASSERT(*initNode == nullptr);
+
+ if (type->isUnsizedArray())
+ {
+ // In case initializer is not an array or type has more dimensions than initializer, this
+ // will default to setting array sizes to 1. We have not checked yet whether the initializer
+ // actually is an array or not. Having a non-array initializer for an unsized array will
+ // result in an error later, so we don't generate an error message here.
+ auto *arraySizes = initializer->getType().getArraySizes();
+ type->sizeUnsizedArrays(arraySizes);
+ }
+
+ const TQualifier qualifier = type->getQualifier();
+
+ bool constError = false;
+ if (qualifier == EvqConst)
+ {
+ if (EvqConst != initializer->getType().getQualifier())
+ {
+ TInfoSinkBase reasonStream;
+ reasonStream << "assigning non-constant to '" << *type << "'";
+ error(line, reasonStream.c_str(), "=");
+
+ // We're still going to declare the variable to avoid extra error messages.
+ type->setQualifier(EvqTemporary);
+ constError = true;
+ }
+ }
+
+ TVariable *variable = nullptr;
+ if (!declareVariable(line, identifier, type, &variable))
+ {
+ return false;
+ }
+
+ if (constError)
+ {
+ return false;
+ }
+
+ bool globalInitWarning = false;
+ if (symbolTable.atGlobalLevel() &&
+ !ValidateGlobalInitializer(initializer, mShaderVersion, &globalInitWarning))
+ {
+ // Error message does not completely match behavior with ESSL 1.00, but
+ // we want to steer developers towards only using constant expressions.
+ error(line, "global variable initializers must be constant expressions", "=");
+ return false;
+ }
+ if (globalInitWarning)
+ {
+ warning(
+ line,
+ "global variable initializers should be constant expressions "
+ "(uniforms and globals are allowed in global initializers for legacy compatibility)",
+ "=");
+ }
+
+ // identifier must be of type constant, a global, or a temporary
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
+ {
+ error(line, " cannot initialize this type of qualifier ",
+ variable->getType().getQualifierString());
+ return false;
+ }
+
+ TIntermSymbol *intermSymbol = new TIntermSymbol(variable);
+ intermSymbol->setLine(line);
+
+ if (!binaryOpCommonCheck(EOpInitialize, intermSymbol, initializer, line))
+ {
+ assignError(line, "=", variable->getType(), initializer->getType());
+ return false;
+ }
+
+ if (qualifier == EvqConst)
+ {
+ // Save the constant folded value to the variable if possible.
+ const TConstantUnion *constArray = initializer->getConstantValue();
+ if (constArray)
+ {
+ variable->shareConstPointer(constArray);
+ if (initializer->getType().canReplaceWithConstantUnion())
+ {
+ ASSERT(*initNode == nullptr);
+ return true;
+ }
+ }
+ }
+
+ *initNode = new TIntermBinary(EOpInitialize, intermSymbol, initializer);
+ markStaticReadIfSymbol(initializer);
+ (*initNode)->setLine(line);
+ return true;
+}
+
+TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType,
+ const ImmutableString &identifier,
+ TIntermTyped *initializer,
+ const TSourceLoc &loc)
+{
+ checkIsScalarBool(loc, pType);
+ TIntermBinary *initNode = nullptr;
+ TType *type = new TType(pType);
+ if (executeInitializer(loc, identifier, type, initializer, &initNode))
+ {
+ // The initializer is valid. The init condition needs to have a node - either the
+ // initializer node, or a constant node in case the initialized variable is const and won't
+ // be recorded in the AST.
+ if (initNode == nullptr)
+ {
+ return initializer;
+ }
+ else
+ {
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->appendDeclarator(initNode);
+ return declaration;
+ }
+ }
+ return nullptr;
+}
+
+TIntermNode *TParseContext::addLoop(TLoopType type,
+ TIntermNode *init,
+ TIntermNode *cond,
+ TIntermTyped *expr,
+ TIntermNode *body,
+ const TSourceLoc &line)
+{
+ TIntermNode *node = nullptr;
+ TIntermTyped *typedCond = nullptr;
+ if (cond)
+ {
+ markStaticReadIfSymbol(cond);
+ typedCond = cond->getAsTyped();
+ }
+ if (expr)
+ {
+ markStaticReadIfSymbol(expr);
+ }
+ // In case the loop body was not parsed as a block and contains a statement that simply refers
+ // to a variable, we need to mark it as statically used.
+ if (body)
+ {
+ markStaticReadIfSymbol(body);
+ }
+ if (cond == nullptr || typedCond)
+ {
+ if (type == ELoopDoWhile)
+ {
+ checkIsScalarBool(line, typedCond);
+ }
+ // In the case of other loops, it was checked before that the condition is a scalar boolean.
+ ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr ||
+ (typedCond->getBasicType() == EbtBool && !typedCond->isArray() &&
+ !typedCond->isVector()));
+
+ node = new TIntermLoop(type, init, typedCond, expr, EnsureBlock(body));
+ node->setLine(line);
+ return node;
+ }
+
+ ASSERT(type != ELoopDoWhile);
+
+ TIntermDeclaration *declaration = cond->getAsDeclarationNode();
+ ASSERT(declaration);
+ TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode();
+ ASSERT(declarator->getLeft()->getAsSymbolNode());
+
+ // The condition is a declaration. In the AST representation we don't support declarations as
+ // loop conditions. Wrap the loop to a block that declares the condition variable and contains
+ // the loop.
+ TIntermBlock *block = new TIntermBlock();
+
+ TIntermDeclaration *declareCondition = new TIntermDeclaration();
+ declareCondition->appendDeclarator(declarator->getLeft()->deepCopy());
+ block->appendStatement(declareCondition);
+
+ TIntermBinary *conditionInit = new TIntermBinary(EOpAssign, declarator->getLeft()->deepCopy(),
+ declarator->getRight()->deepCopy());
+ TIntermLoop *loop = new TIntermLoop(type, init, conditionInit, expr, EnsureBlock(body));
+ block->appendStatement(loop);
+ loop->setLine(line);
+ block->setLine(line);
+ return block;
+}
+
+TIntermNode *TParseContext::addIfElse(TIntermTyped *cond,
+ TIntermNodePair code,
+ const TSourceLoc &loc)
+{
+ bool isScalarBool = checkIsScalarBool(loc, cond);
+ // In case the conditional statements were not parsed as blocks and contain a statement that
+ // simply refers to a variable, we need to mark them as statically used.
+ if (code.node1)
+ {
+ markStaticReadIfSymbol(code.node1);
+ }
+ if (code.node2)
+ {
+ markStaticReadIfSymbol(code.node2);
+ }
+
+ // For compile time constant conditions, prune the code now.
+ if (isScalarBool && cond->getAsConstantUnion())
+ {
+ if (cond->getAsConstantUnion()->getBConst(0) == true)
+ {
+ return EnsureBlock(code.node1);
+ }
+ else
+ {
+ return EnsureBlock(code.node2);
+ }
+ }
+
+ TIntermIfElse *node = new TIntermIfElse(cond, EnsureBlock(code.node1), EnsureBlock(code.node2));
+ markStaticReadIfSymbol(cond);
+ node->setLine(loc);
+
+ return node;
+}
+
+void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
+{
+ checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision,
+ typeSpecifier->getBasicType());
+
+ if (mShaderVersion < 300 && typeSpecifier->isArray())
+ {
+ error(typeSpecifier->getLine(), "not supported", "first-class array");
+ typeSpecifier->clearArrayness();
+ }
+}
+
+TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TPublicType &typeSpecifier)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
+
+ TPublicType returnType = typeSpecifier;
+ returnType.qualifier = typeQualifier.qualifier;
+ returnType.invariant = typeQualifier.invariant;
+ returnType.layoutQualifier = typeQualifier.layoutQualifier;
+ returnType.memoryQualifier = typeQualifier.memoryQualifier;
+ returnType.precision = typeSpecifier.precision;
+
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ returnType.precision = typeQualifier.precision;
+ }
+
+ checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision,
+ typeSpecifier.getBasicType());
+
+ checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier,
+ typeSpecifier.getLine());
+
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier);
+
+ if (mShaderVersion < 300)
+ {
+ if (typeSpecifier.isArray())
+ {
+ error(typeSpecifier.getLine(), "not supported", "first-class array");
+ returnType.clearArrayness();
+ }
+
+ if (returnType.qualifier == EvqAttribute &&
+ (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
+ {
+ error(typeSpecifier.getLine(), "cannot be bool or int",
+ getQualifierString(returnType.qualifier));
+ }
+
+ if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) &&
+ (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
+ {
+ error(typeSpecifier.getLine(), "cannot be bool or int",
+ getQualifierString(returnType.qualifier));
+ }
+ }
+ else
+ {
+ if (!returnType.layoutQualifier.isEmpty())
+ {
+ checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout");
+ }
+ if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn ||
+ returnType.qualifier == EvqFragmentOut)
+ {
+ checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier,
+ typeSpecifier.getLine());
+ }
+ if (returnType.qualifier == EvqComputeIn)
+ {
+ error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size",
+ "in");
+ }
+ }
+
+ return returnType;
+}
+
+void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
+ const TPublicType &type,
+ const TSourceLoc &qualifierLocation)
+{
+ // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
+ if (type.getBasicType() == EbtBool)
+ {
+ error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
+ }
+
+ // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
+ switch (qualifier)
+ {
+ case EvqVertexIn:
+ // ESSL 3.00 section 4.3.4
+ if (type.isArray())
+ {
+ error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
+ }
+ // Vertex inputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck
+ return;
+ case EvqFragmentOut:
+ // ESSL 3.00 section 4.3.6
+ if (type.typeSpecifierNonArray.isMatrix())
+ {
+ error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
+ }
+ // Fragment outputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck
+ return;
+ default:
+ break;
+ }
+
+ // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
+ // restrictions.
+ bool typeContainsIntegers =
+ (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt ||
+ type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt));
+ if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
+ {
+ error(qualifierLocation, "must use 'flat' interpolation here",
+ getQualifierString(qualifier));
+ }
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ // ESSL 3.00 sections 4.3.4 and 4.3.6.
+ // These restrictions are only implied by the ESSL 3.00 spec, but
+ // the ESSL 3.10 spec lists these restrictions explicitly.
+ if (type.isArray())
+ {
+ error(qualifierLocation, "cannot be an array of structures",
+ getQualifierString(qualifier));
+ }
+ if (type.isStructureContainingArrays())
+ {
+ error(qualifierLocation, "cannot be a structure containing an array",
+ getQualifierString(qualifier));
+ }
+ if (type.isStructureContainingType(EbtStruct))
+ {
+ error(qualifierLocation, "cannot be a structure containing a structure",
+ getQualifierString(qualifier));
+ }
+ if (type.isStructureContainingType(EbtBool))
+ {
+ error(qualifierLocation, "cannot be a structure containing a bool",
+ getQualifierString(qualifier));
+ }
+ }
+}
+
+void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier)
+{
+ if (qualifier.getType() == QtStorage)
+ {
+ const TStorageQualifierWrapper &storageQualifier =
+ static_cast<const TStorageQualifierWrapper &>(qualifier);
+ if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst &&
+ !symbolTable.atGlobalLevel())
+ {
+ error(storageQualifier.getLine(),
+ "Local variables can only use the const storage qualifier.",
+ storageQualifier.getQualifierString());
+ }
+ }
+}
+
+void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier,
+ const TSourceLoc &location)
+{
+ const std::string reason(
+ "Only allowed with shader storage blocks, variables declared within shader storage blocks "
+ "and variables declared as image types.");
+ if (memoryQualifier.readonly)
+ {
+ error(location, reason.c_str(), "readonly");
+ }
+ if (memoryQualifier.writeonly)
+ {
+ error(location, reason.c_str(), "writeonly");
+ }
+ if (memoryQualifier.coherent)
+ {
+ error(location, reason.c_str(), "coherent");
+ }
+ if (memoryQualifier.restrictQualifier)
+ {
+ error(location, reason.c_str(), "restrict");
+ }
+ if (memoryQualifier.volatileQualifier)
+ {
+ error(location, reason.c_str(), "volatile");
+ }
+}
+
+// Make sure there is no offset overlapping, and store the newly assigned offset to "type" in
+// intermediate tree.
+void TParseContext::checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
+ const TSourceLoc &loc,
+ TType *type)
+{
+ const size_t size = type->isArray() ? kAtomicCounterArrayStride * type->getArraySizeProduct()
+ : kAtomicCounterSize;
+ TLayoutQualifier layoutQualifier = type->getLayoutQualifier();
+ auto &bindingState = mAtomicCounterBindingStates[layoutQualifier.binding];
+ int offset;
+ if (layoutQualifier.offset == -1 || forceAppend)
+ {
+ offset = bindingState.appendSpan(size);
+ }
+ else
+ {
+ offset = bindingState.insertSpan(layoutQualifier.offset, size);
+ }
+ if (offset == -1)
+ {
+ error(loc, "Offset overlapping", "atomic counter");
+ return;
+ }
+ layoutQualifier.offset = offset;
+ type->setLayoutQualifier(layoutQualifier);
+}
+
+void TParseContext::checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type)
+{
+ TLayoutQualifier layoutQualifier = type.getLayoutQualifier();
+
+ // OpenGL ES 3.1 Table 6.5, Atomic counter offset must be a multiple of 4
+ if (layoutQualifier.offset % 4 != 0)
+ {
+ error(location, "Offset must be multiple of 4", "atomic counter");
+ }
+}
+
+void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location,
+ const ImmutableString &token,
+ TType *type)
+{
+ if (IsGeometryShaderInput(mShaderType, type->getQualifier()))
+ {
+ if (type->isArray() && type->getOutermostArraySize() == 0u)
+ {
+ // Set size for the unsized geometry shader inputs if they are declared after a valid
+ // input primitive declaration.
+ if (mGeometryShaderInputPrimitiveType != EptUndefined)
+ {
+ ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr);
+ type->sizeOutermostUnsizedArray(
+ symbolTable.getGlInVariableWithArraySize()->getType().getOutermostArraySize());
+ }
+ else
+ {
+ // [GLSL ES 3.2 SPEC Chapter 4.4.1.2]
+ // An input can be declared without an array size if there is a previous layout
+ // which specifies the size.
+ error(location,
+ "Missing a valid input primitive declaration before declaring an unsized "
+ "array input",
+ token);
+ }
+ }
+ else if (type->isArray())
+ {
+ setGeometryShaderInputArraySize(type->getOutermostArraySize(), location);
+ }
+ else
+ {
+ error(location, "Geometry shader input variable must be declared as an array", token);
+ }
+ }
+}
+
+TIntermDeclaration *TParseContext::parseSingleDeclaration(
+ TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const ImmutableString &identifier)
+{
+ TType *type = new TType(publicType);
+ if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) &&
+ mDirectiveHandler.pragma().stdgl.invariantAll)
+ {
+ TQualifier qualifier = type->getQualifier();
+
+ // The directive handler has already taken care of rejecting invalid uses of this pragma
+ // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all
+ // affected variable declarations:
+ //
+ // 1. Built-in special variables which are inputs to the fragment shader. (These are handled
+ // elsewhere, in TranslatorGLSL.)
+ //
+ // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It
+ // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but
+ // the way this is currently implemented we have to enable this compiler option before
+ // parsing the shader and determining the shading language version it uses. If this were
+ // implemented as a post-pass, the workaround could be more targeted.
+ if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut)
+ {
+ type->setInvariant(true);
+ }
+ }
+
+ checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier, type);
+
+ declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
+ identifierOrTypeLocation);
+
+ bool emptyDeclaration = (identifier == "");
+ mDeferredNonEmptyDeclarationErrorCheck = emptyDeclaration;
+
+ TIntermSymbol *symbol = nullptr;
+ if (emptyDeclaration)
+ {
+ emptyDeclarationErrorCheck(*type, identifierOrTypeLocation);
+ // In most cases we don't need to create a symbol node for an empty declaration.
+ // But if the empty declaration is declaring a struct type, the symbol node will store that.
+ if (type->getBasicType() == EbtStruct)
+ {
+ TVariable *emptyVariable =
+ new TVariable(&symbolTable, kEmptyImmutableString, type, SymbolType::Empty);
+ symbol = new TIntermSymbol(emptyVariable);
+ }
+ else if (IsAtomicCounter(publicType.getBasicType()))
+ {
+ setAtomicCounterBindingDefaultOffset(publicType, identifierOrTypeLocation);
+ }
+ }
+ else
+ {
+ nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation);
+
+ checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, type);
+
+ if (IsAtomicCounter(type->getBasicType()))
+ {
+ checkAtomicCounterOffsetDoesNotOverlap(false, identifierOrTypeLocation, type);
+
+ checkAtomicCounterOffsetAlignment(identifierOrTypeLocation, *type);
+ }
+
+ TVariable *variable = nullptr;
+ if (declareVariable(identifierOrTypeLocation, identifier, type, &variable))
+ {
+ symbol = new TIntermSymbol(variable);
+ }
+ }
+
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->setLine(identifierOrTypeLocation);
+ if (symbol)
+ {
+ symbol->setLine(identifierOrTypeLocation);
+ declaration->appendDeclarator(symbol);
+ }
+ return declaration;
+}
+
+TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(
+ TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &indexLocation,
+ const TVector<unsigned int> &arraySizes)
+{
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+
+ declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier,
+ identifierLocation);
+
+ nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
+
+ checkIsValidTypeAndQualifierForArray(indexLocation, elementType);
+
+ TType *arrayType = new TType(elementType);
+ arrayType->makeArrays(arraySizes);
+
+ checkGeometryShaderInputAndSetArraySize(indexLocation, identifier, arrayType);
+
+ checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType);
+
+ if (IsAtomicCounter(arrayType->getBasicType()))
+ {
+ checkAtomicCounterOffsetDoesNotOverlap(false, identifierLocation, arrayType);
+
+ checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType);
+ }
+
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->setLine(identifierLocation);
+
+ TVariable *variable = nullptr;
+ if (declareVariable(identifierLocation, identifier, arrayType, &variable))
+ {
+ TIntermSymbol *symbol = new TIntermSymbol(variable);
+ symbol->setLine(identifierLocation);
+ declaration->appendDeclarator(symbol);
+ }
+
+ return declaration;
+}
+
+TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+
+ declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
+ identifierLocation);
+
+ nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
+
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->setLine(identifierLocation);
+
+ TIntermBinary *initNode = nullptr;
+ TType *type = new TType(publicType);
+ if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode))
+ {
+ if (initNode)
+ {
+ declaration->appendDeclarator(initNode);
+ }
+ }
+ return declaration;
+}
+
+TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
+ TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &indexLocation,
+ const TVector<unsigned int> &arraySizes,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+
+ declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier,
+ identifierLocation);
+
+ nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
+
+ checkIsValidTypeAndQualifierForArray(indexLocation, elementType);
+
+ TType *arrayType = new TType(elementType);
+ arrayType->makeArrays(arraySizes);
+
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->setLine(identifierLocation);
+
+ // initNode will correspond to the whole of "type b[n] = initializer".
+ TIntermBinary *initNode = nullptr;
+ if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ {
+ if (initNode)
+ {
+ declaration->appendDeclarator(initNode);
+ }
+ }
+
+ return declaration;
+}
+
+TIntermInvariantDeclaration *TParseContext::parseInvariantDeclaration(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &identifierLoc,
+ const ImmutableString &identifier,
+ const TSymbol *symbol)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
+
+ if (!typeQualifier.invariant)
+ {
+ error(identifierLoc, "Expected invariant", identifier);
+ return nullptr;
+ }
+ if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying"))
+ {
+ return nullptr;
+ }
+ if (!symbol)
+ {
+ error(identifierLoc, "undeclared identifier declared as invariant", identifier);
+ return nullptr;
+ }
+ if (!IsQualifierUnspecified(typeQualifier.qualifier))
+ {
+ error(identifierLoc, "invariant declaration specifies qualifier",
+ getQualifierString(typeQualifier.qualifier));
+ }
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ error(identifierLoc, "invariant declaration specifies precision",
+ getPrecisionString(typeQualifier.precision));
+ }
+ if (!typeQualifier.layoutQualifier.isEmpty())
+ {
+ error(identifierLoc, "invariant declaration specifies layout", "'layout'");
+ }
+
+ const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
+ if (!variable)
+ {
+ return nullptr;
+ }
+ const TType &type = variable->getType();
+
+ checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(),
+ typeQualifier.line);
+ checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
+
+ symbolTable.addInvariantVarying(*variable);
+
+ TIntermSymbol *intermSymbol = new TIntermSymbol(variable);
+ intermSymbol->setLine(identifierLoc);
+
+ return new TIntermInvariantDeclaration(intermSymbol, identifierLoc);
+}
+
+void TParseContext::parseDeclarator(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ TIntermDeclaration *declarationOut)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredNonEmptyDeclarationErrorCheck)
+ {
+ nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
+
+ TType *type = new TType(publicType);
+
+ checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, type);
+
+ checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, type);
+
+ if (IsAtomicCounter(type->getBasicType()))
+ {
+ checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, type);
+
+ checkAtomicCounterOffsetAlignment(identifierLocation, *type);
+ }
+
+ TVariable *variable = nullptr;
+ if (declareVariable(identifierLocation, identifier, type, &variable))
+ {
+ TIntermSymbol *symbol = new TIntermSymbol(variable);
+ symbol->setLine(identifierLocation);
+ declarationOut->appendDeclarator(symbol);
+ }
+}
+
+void TParseContext::parseArrayDeclarator(TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &arrayLocation,
+ const TVector<unsigned int> &arraySizes,
+ TIntermDeclaration *declarationOut)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredNonEmptyDeclarationErrorCheck)
+ {
+ nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType);
+
+ if (checkIsValidTypeAndQualifierForArray(arrayLocation, elementType))
+ {
+ TType *arrayType = new TType(elementType);
+ arrayType->makeArrays(arraySizes);
+
+ checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, arrayType);
+
+ checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType);
+
+ if (IsAtomicCounter(arrayType->getBasicType()))
+ {
+ checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, arrayType);
+
+ checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType);
+ }
+
+ TVariable *variable = nullptr;
+ if (declareVariable(identifierLocation, identifier, arrayType, &variable))
+ {
+ TIntermSymbol *symbol = new TIntermSymbol(variable);
+ symbol->setLine(identifierLocation);
+ declarationOut->appendDeclarator(symbol);
+ }
+ }
+}
+
+void TParseContext::parseInitDeclarator(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer,
+ TIntermDeclaration *declarationOut)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredNonEmptyDeclarationErrorCheck)
+ {
+ nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
+
+ TIntermBinary *initNode = nullptr;
+ TType *type = new TType(publicType);
+ if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode))
+ {
+ //
+ // build the intermediate representation
+ //
+ if (initNode)
+ {
+ declarationOut->appendDeclarator(initNode);
+ }
+ }
+}
+
+void TParseContext::parseArrayInitDeclarator(const TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &indexLocation,
+ const TVector<unsigned int> &arraySizes,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer,
+ TIntermDeclaration *declarationOut)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredNonEmptyDeclarationErrorCheck)
+ {
+ nonEmptyDeclarationErrorCheck(elementType, identifierLocation);
+ mDeferredNonEmptyDeclarationErrorCheck = false;
+ }
+
+ checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType);
+
+ checkIsValidTypeAndQualifierForArray(indexLocation, elementType);
+
+ TType *arrayType = new TType(elementType);
+ arrayType->makeArrays(arraySizes);
+
+ // initNode will correspond to the whole of "b[n] = initializer".
+ TIntermBinary *initNode = nullptr;
+ if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ {
+ if (initNode)
+ {
+ declarationOut->appendDeclarator(initNode);
+ }
+ }
+}
+
+TIntermNode *TParseContext::addEmptyStatement(const TSourceLoc &location)
+{
+ // It's simpler to parse an empty statement as a constant expression rather than having a
+ // different type of node just for empty statements, that will be pruned from the AST anyway.
+ TIntermNode *node = CreateZeroNode(TType(EbtInt, EbpMedium));
+ node->setLine(location);
+ return node;
+}
+
+void TParseContext::setAtomicCounterBindingDefaultOffset(const TPublicType &publicType,
+ const TSourceLoc &location)
+{
+ const TLayoutQualifier &layoutQualifier = publicType.layoutQualifier;
+ checkAtomicCounterBindingIsValid(location, layoutQualifier.binding);
+ if (layoutQualifier.binding == -1 || layoutQualifier.offset == -1)
+ {
+ error(location, "Requires both binding and offset", "layout");
+ return;
+ }
+ mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset);
+}
+
+void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision,
+ const TPublicType &type,
+ const TSourceLoc &loc)
+{
+ if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER) &&
+ !getFragmentPrecisionHigh())
+ {
+ error(loc, "precision is not supported in fragment shader", "highp");
+ }
+
+ if (!CanSetDefaultPrecisionOnType(type))
+ {
+ error(loc, "illegal type argument for default precision qualifier",
+ getBasicString(type.getBasicType()));
+ return;
+ }
+ symbolTable.setDefaultPrecision(type.getBasicType(), precision);
+}
+
+bool TParseContext::checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier)
+{
+ switch (typeQualifier.layoutQualifier.primitiveType)
+ {
+ case EptLines:
+ case EptLinesAdjacency:
+ case EptTriangles:
+ case EptTrianglesAdjacency:
+ return typeQualifier.qualifier == EvqGeometryIn;
+
+ case EptLineStrip:
+ case EptTriangleStrip:
+ return typeQualifier.qualifier == EvqGeometryOut;
+
+ case EptPoints:
+ return true;
+
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+void TParseContext::setGeometryShaderInputArraySize(unsigned int inputArraySize,
+ const TSourceLoc &line)
+{
+ if (!symbolTable.setGlInArraySize(inputArraySize))
+ {
+ error(line,
+ "Array size or input primitive declaration doesn't match the size of earlier sized "
+ "array inputs.",
+ "layout");
+ }
+}
+
+bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier)
+{
+ ASSERT(typeQualifier.qualifier == EvqGeometryIn);
+
+ const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier;
+
+ if (layoutQualifier.maxVertices != -1)
+ {
+ error(typeQualifier.line,
+ "max_vertices can only be declared in 'out' layout in a geometry shader", "layout");
+ return false;
+ }
+
+ // Set mGeometryInputPrimitiveType if exists
+ if (layoutQualifier.primitiveType != EptUndefined)
+ {
+ if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier))
+ {
+ error(typeQualifier.line, "invalid primitive type for 'in' layout", "layout");
+ return false;
+ }
+
+ if (mGeometryShaderInputPrimitiveType == EptUndefined)
+ {
+ mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType;
+ setGeometryShaderInputArraySize(
+ GetGeometryShaderInputArraySize(mGeometryShaderInputPrimitiveType),
+ typeQualifier.line);
+ }
+ else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType)
+ {
+ error(typeQualifier.line, "primitive doesn't match earlier input primitive declaration",
+ "layout");
+ return false;
+ }
+ }
+
+ // Set mGeometryInvocations if exists
+ if (layoutQualifier.invocations > 0)
+ {
+ if (mGeometryShaderInvocations == 0)
+ {
+ mGeometryShaderInvocations = layoutQualifier.invocations;
+ }
+ else if (mGeometryShaderInvocations != layoutQualifier.invocations)
+ {
+ error(typeQualifier.line, "invocations contradicts to the earlier declaration",
+ "layout");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier)
+{
+ ASSERT(typeQualifier.qualifier == EvqGeometryOut);
+
+ const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier;
+
+ if (layoutQualifier.invocations > 0)
+ {
+ error(typeQualifier.line,
+ "invocations can only be declared in 'in' layout in a geometry shader", "layout");
+ return false;
+ }
+
+ // Set mGeometryOutputPrimitiveType if exists
+ if (layoutQualifier.primitiveType != EptUndefined)
+ {
+ if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier))
+ {
+ error(typeQualifier.line, "invalid primitive type for 'out' layout", "layout");
+ return false;
+ }
+
+ if (mGeometryShaderOutputPrimitiveType == EptUndefined)
+ {
+ mGeometryShaderOutputPrimitiveType = layoutQualifier.primitiveType;
+ }
+ else if (mGeometryShaderOutputPrimitiveType != layoutQualifier.primitiveType)
+ {
+ error(typeQualifier.line,
+ "primitive doesn't match earlier output primitive declaration", "layout");
+ return false;
+ }
+ }
+
+ // Set mGeometryMaxVertices if exists
+ if (layoutQualifier.maxVertices > -1)
+ {
+ if (mGeometryShaderMaxVertices == -1)
+ {
+ mGeometryShaderMaxVertices = layoutQualifier.maxVertices;
+ }
+ else if (mGeometryShaderMaxVertices != layoutQualifier.maxVertices)
+ {
+ error(typeQualifier.line, "max_vertices contradicts to the earlier declaration",
+ "layout");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
+ const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
+
+ checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier,
+ typeQualifier.line);
+
+ // It should never be the case, but some strange parser errors can send us here.
+ if (layoutQualifier.isEmpty())
+ {
+ error(typeQualifier.line, "Error during layout qualifier parsing.", "?");
+ return;
+ }
+
+ if (!layoutQualifier.isCombinationValid())
+ {
+ error(typeQualifier.line, "invalid layout qualifier combination", "layout");
+ return;
+ }
+
+ checkIndexIsNotSpecified(typeQualifier.line, layoutQualifier.index);
+
+ checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding);
+
+ checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
+
+ checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat);
+
+ checkYuvIsNotSpecified(typeQualifier.line, layoutQualifier.yuv);
+
+ checkOffsetIsNotSpecified(typeQualifier.line, layoutQualifier.offset);
+
+ checkStd430IsForShaderStorageBlock(typeQualifier.line, layoutQualifier.blockStorage,
+ typeQualifier.qualifier);
+
+ if (typeQualifier.qualifier == EvqComputeIn)
+ {
+ if (mComputeShaderLocalSizeDeclared &&
+ !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize))
+ {
+ error(typeQualifier.line, "Work group size does not match the previous declaration",
+ "layout");
+ return;
+ }
+
+ if (mShaderVersion < 310)
+ {
+ error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout");
+ return;
+ }
+
+ if (!layoutQualifier.localSize.isAnyValueSet())
+ {
+ error(typeQualifier.line, "No local work group size specified", "layout");
+ return;
+ }
+
+ const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>(
+ symbolTable.findBuiltIn(ImmutableString("gl_MaxComputeWorkGroupSize"), mShaderVersion));
+
+ const TConstantUnion *maxComputeWorkGroupSizeData =
+ maxComputeWorkGroupSize->getConstPointer();
+
+ for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i)
+ {
+ if (layoutQualifier.localSize[i] != -1)
+ {
+ mComputeShaderLocalSize[i] = layoutQualifier.localSize[i];
+ const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst();
+ if (mComputeShaderLocalSize[i] < 1 ||
+ mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue)
+ {
+ std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
+ reasonStream << "invalid value: Value must be at least 1 and no greater than "
+ << maxComputeWorkGroupSizeValue;
+ const std::string &reason = reasonStream.str();
+
+ error(typeQualifier.line, reason.c_str(), getWorkGroupSizeString(i));
+ return;
+ }
+ }
+ }
+
+ mComputeShaderLocalSizeDeclared = true;
+ }
+ else if (typeQualifier.qualifier == EvqGeometryIn)
+ {
+ if (mShaderVersion < 310)
+ {
+ error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout");
+ return;
+ }
+
+ if (!parseGeometryShaderInputLayoutQualifier(typeQualifier))
+ {
+ return;
+ }
+ }
+ else if (typeQualifier.qualifier == EvqGeometryOut)
+ {
+ if (mShaderVersion < 310)
+ {
+ error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 only",
+ "layout");
+ return;
+ }
+
+ if (!parseGeometryShaderOutputLayoutQualifier(typeQualifier))
+ {
+ return;
+ }
+ }
+ else if (anyMultiviewExtensionAvailable() && typeQualifier.qualifier == EvqVertexIn)
+ {
+ // This error is only specified in WebGL, but tightens unspecified behavior in the native
+ // specification.
+ if (mNumViews != -1 && layoutQualifier.numViews != mNumViews)
+ {
+ error(typeQualifier.line, "Number of views does not match the previous declaration",
+ "layout");
+ return;
+ }
+
+ if (layoutQualifier.numViews == -1)
+ {
+ error(typeQualifier.line, "No num_views specified", "layout");
+ return;
+ }
+
+ if (layoutQualifier.numViews > mMaxNumViews)
+ {
+ error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR",
+ "layout");
+ return;
+ }
+
+ mNumViews = layoutQualifier.numViews;
+ }
+ else
+ {
+ if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier))
+ {
+ return;
+ }
+
+ if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer)
+ {
+ error(typeQualifier.line, "invalid qualifier: global layout can only be set for blocks",
+ getQualifierString(typeQualifier.qualifier));
+ return;
+ }
+
+ if (mShaderVersion < 300)
+ {
+ error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above",
+ "layout");
+ return;
+ }
+
+ checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier);
+
+ if (layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ if (typeQualifier.qualifier == EvqUniform)
+ {
+ mDefaultUniformMatrixPacking = layoutQualifier.matrixPacking;
+ }
+ else if (typeQualifier.qualifier == EvqBuffer)
+ {
+ mDefaultBufferMatrixPacking = layoutQualifier.matrixPacking;
+ }
+ }
+
+ if (layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ if (typeQualifier.qualifier == EvqUniform)
+ {
+ mDefaultUniformBlockStorage = layoutQualifier.blockStorage;
+ }
+ else if (typeQualifier.qualifier == EvqBuffer)
+ {
+ mDefaultBufferBlockStorage = layoutQualifier.blockStorage;
+ }
+ }
+ }
+}
+
+TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction(
+ const TFunction &function,
+ const TSourceLoc &location,
+ bool insertParametersToSymbolTable)
+{
+ checkIsNotReserved(location, function.name());
+
+ TIntermFunctionPrototype *prototype = new TIntermFunctionPrototype(&function);
+ prototype->setLine(location);
+
+ for (size_t i = 0; i < function.getParamCount(); i++)
+ {
+ const TVariable *param = function.getParam(i);
+
+ // If the parameter has no name, it's not an error, just don't add it to symbol table (could
+ // be used for unused args).
+ if (param->symbolType() != SymbolType::Empty)
+ {
+ if (insertParametersToSymbolTable)
+ {
+ if (!symbolTable.declare(const_cast<TVariable *>(param)))
+ {
+ error(location, "redefinition", param->name());
+ }
+ }
+ // Unsized type of a named parameter should have already been checked and sanitized.
+ ASSERT(!param->getType().isUnsizedArray());
+ }
+ else
+ {
+ if (param->getType().isUnsizedArray())
+ {
+ error(location, "function parameter array must be sized at compile time", "[]");
+ // We don't need to size the arrays since the parameter is unnamed and hence
+ // inaccessible.
+ }
+ }
+ }
+ return prototype;
+}
+
+TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration(
+ const TFunction &parsedFunction,
+ const TSourceLoc &location)
+{
+ // Note: function found from the symbol table could be the same as parsedFunction if this is the
+ // first declaration. Either way the instance in the symbol table is used to track whether the
+ // function is declared multiple times.
+ bool hadPrototypeDeclaration = false;
+ const TFunction *function = symbolTable.markFunctionHasPrototypeDeclaration(
+ parsedFunction.getMangledName(), &hadPrototypeDeclaration);
+
+ if (hadPrototypeDeclaration && mShaderVersion == 100)
+ {
+ // ESSL 1.00.17 section 4.2.7.
+ // Doesn't apply to ESSL 3.00.4: see section 4.2.3.
+ error(location, "duplicate function prototype declarations are not allowed", "function");
+ }
+
+ TIntermFunctionPrototype *prototype =
+ createPrototypeNodeFromFunction(*function, location, false);
+
+ symbolTable.pop();
+
+ if (!symbolTable.atGlobalLevel())
+ {
+ // ESSL 3.00.4 section 4.2.4.
+ error(location, "local function prototype declarations are not allowed", "function");
+ }
+
+ return prototype;
+}
+
+TIntermFunctionDefinition *TParseContext::addFunctionDefinition(
+ TIntermFunctionPrototype *functionPrototype,
+ TIntermBlock *functionBody,
+ const TSourceLoc &location)
+{
+ // Undo push at end of parseFunctionDefinitionHeader() below for ESSL1.00 case
+ if (mFunctionBodyNewScope)
+ {
+ mFunctionBodyNewScope = false;
+ symbolTable.pop();
+ }
+
+ // Check that non-void functions have at least one return statement.
+ if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
+ {
+ error(location,
+ "function does not return a value:", functionPrototype->getFunction()->name());
+ }
+
+ if (functionBody == nullptr)
+ {
+ functionBody = new TIntermBlock();
+ functionBody->setLine(location);
+ }
+ TIntermFunctionDefinition *functionNode =
+ new TIntermFunctionDefinition(functionPrototype, functionBody);
+ functionNode->setLine(location);
+
+ symbolTable.pop();
+ return functionNode;
+}
+
+void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
+ const TFunction *function,
+ TIntermFunctionPrototype **prototypeOut)
+{
+ ASSERT(function);
+
+ bool wasDefined = false;
+ function = symbolTable.setFunctionParameterNamesFromDefinition(function, &wasDefined);
+ if (wasDefined)
+ {
+ error(location, "function already has a body", function->name());
+ }
+
+ // Remember the return type for later checking for return statements.
+ mCurrentFunctionType = &(function->getReturnType());
+ mFunctionReturnsValue = false;
+
+ *prototypeOut = createPrototypeNodeFromFunction(*function, location, true);
+ setLoopNestingLevel(0);
+
+ // ESSL 1.00 spec allows for variable in function body to redefine parameter
+ if (IsSpecWithFunctionBodyNewScope(mShaderSpec, mShaderVersion))
+ {
+ mFunctionBodyNewScope = true;
+ symbolTable.push();
+ }
+}
+
+TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
+{
+ //
+ // We don't know at this point whether this is a function definition or a prototype.
+ // The definition production code will check for redefinitions.
+ // In the case of ESSL 1.00 the prototype production code will also check for redeclarations.
+ //
+
+ for (size_t i = 0u; i < function->getParamCount(); ++i)
+ {
+ const TVariable *param = function->getParam(i);
+ if (param->getType().isStructSpecifier())
+ {
+ // ESSL 3.00.6 section 12.10.
+ error(location, "Function parameter type cannot be a structure definition",
+ function->name());
+ }
+ }
+
+ if (getShaderVersion() >= 300)
+ {
+ const UnmangledBuiltIn *builtIn =
+ symbolTable.getUnmangledBuiltInForShaderVersion(function->name(), getShaderVersion());
+ if (builtIn &&
+ (builtIn->extension == TExtension::UNDEFINED || isExtensionEnabled(builtIn->extension)))
+ {
+ // With ESSL 3.00 and above, names of built-in functions cannot be redeclared as
+ // functions. Therefore overloading or redefining builtin functions is an error.
+ error(location, "Name of a built-in function cannot be redeclared as function",
+ function->name());
+ }
+ }
+ else
+ {
+ // ESSL 1.00.17 section 4.2.6: built-ins can be overloaded but not redefined. We assume that
+ // this applies to redeclarations as well.
+ const TSymbol *builtIn =
+ symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
+ if (builtIn)
+ {
+ error(location, "built-in functions cannot be redefined", function->name());
+ }
+ }
+
+ // Return types and parameter qualifiers must match in all redeclarations, so those are checked
+ // here.
+ const TFunction *prevDec =
+ static_cast<const TFunction *>(symbolTable.findGlobal(function->getMangledName()));
+ if (prevDec)
+ {
+ if (prevDec->getReturnType() != function->getReturnType())
+ {
+ error(location, "function must have the same return type in all of its declarations",
+ function->getReturnType().getBasicString());
+ }
+ for (size_t i = 0; i < prevDec->getParamCount(); ++i)
+ {
+ if (prevDec->getParam(i)->getType().getQualifier() !=
+ function->getParam(i)->getType().getQualifier())
+ {
+ error(location,
+ "function must have the same parameter qualifiers in all of its declarations",
+ function->getParam(i)->getType().getQualifierString());
+ }
+ }
+ }
+
+ // Check for previously declared variables using the same name.
+ const TSymbol *prevSym = symbolTable.find(function->name(), getShaderVersion());
+ bool insertUnmangledName = true;
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ error(location, "redefinition of a function", function->name());
+ }
+ insertUnmangledName = false;
+ }
+ // Parsing is at the inner scope level of the function's arguments and body statement at this
+ // point, but declareUserDefinedFunction takes care of declaring the function at the global
+ // scope.
+ symbolTable.declareUserDefinedFunction(function, insertUnmangledName);
+
+ // Raise error message if main function takes any parameters or return anything other than void
+ if (function->isMain())
+ {
+ if (function->getParamCount() > 0)
+ {
+ error(location, "function cannot take any parameter(s)", "main");
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid)
+ {
+ error(location, "main function cannot return a value",
+ function->getReturnType().getBasicString());
+ }
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition, in which case, we want to use the
+ // variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ return function;
+}
+
+TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
+ const ImmutableString &name,
+ const TSourceLoc &location)
+{
+ if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary)
+ {
+ error(location, "no qualifiers allowed for function return",
+ getQualifierString(type.qualifier));
+ }
+ if (!type.layoutQualifier.isEmpty())
+ {
+ error(location, "no qualifiers allowed for function return", "layout");
+ }
+ // make sure an opaque type is not involved as well...
+ std::string reason(getBasicString(type.getBasicType()));
+ reason += "s can't be function return values";
+ checkIsNotOpaqueType(location, type.typeSpecifierNonArray, reason.c_str());
+ if (mShaderVersion < 300)
+ {
+ // Array return values are forbidden, but there's also no valid syntax for declaring array
+ // return values in ESSL 1.00.
+ ASSERT(!type.isArray() || mDiagnostics->numErrors() > 0);
+
+ if (type.isStructureContainingArrays())
+ {
+ // ESSL 1.00.17 section 6.1 Function Definitions
+ TInfoSinkBase typeString;
+ typeString << TType(type);
+ error(location, "structures containing arrays can't be function return values",
+ typeString.c_str());
+ }
+ }
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ return new TFunction(&symbolTable, name, SymbolType::UserDefined, new TType(type), false);
+}
+
+TFunctionLookup *TParseContext::addNonConstructorFunc(const ImmutableString &name,
+ const TSymbol *symbol)
+{
+ return TFunctionLookup::CreateFunctionCall(name, symbol);
+}
+
+TFunctionLookup *TParseContext::addConstructorFunc(const TPublicType &publicType)
+{
+ if (mShaderVersion < 300 && publicType.isArray())
+ {
+ error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only",
+ "[]");
+ }
+ if (publicType.isStructSpecifier())
+ {
+ error(publicType.getLine(), "constructor can't be a structure definition",
+ getBasicString(publicType.getBasicType()));
+ }
+
+ TType *type = new TType(publicType);
+ if (!type->canBeConstructed())
+ {
+ error(publicType.getLine(), "cannot construct this type",
+ getBasicString(publicType.getBasicType()));
+ type->setBasicType(EbtFloat);
+ }
+ return TFunctionLookup::CreateConstructor(type);
+}
+
+void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line,
+ const char *errorMessage,
+ const ImmutableString &token,
+ TType *arrayType)
+{
+ if (arrayType->isUnsizedArray())
+ {
+ error(line, errorMessage, token);
+ arrayType->sizeUnsizedArrays(nullptr);
+ }
+}
+
+TParameter TParseContext::parseParameterDeclarator(TType *type,
+ const ImmutableString &name,
+ const TSourceLoc &nameLoc)
+{
+ ASSERT(type);
+ checkIsNotUnsizedArray(nameLoc, "function parameter array must specify a size", name, type);
+ if (type->getBasicType() == EbtVoid)
+ {
+ error(nameLoc, "illegal use of type 'void'", name);
+ }
+ checkIsNotReserved(nameLoc, name);
+ TParameter param = {name.data(), type};
+ return param;
+}
+
+TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType,
+ const ImmutableString &name,
+ const TSourceLoc &nameLoc)
+{
+ TType *type = new TType(publicType);
+ return parseParameterDeclarator(type, name, nameLoc);
+}
+
+TParameter TParseContext::parseParameterArrayDeclarator(const ImmutableString &name,
+ const TSourceLoc &nameLoc,
+ const TVector<unsigned int> &arraySizes,
+ const TSourceLoc &arrayLoc,
+ TPublicType *elementType)
+{
+ checkArrayElementIsNotArray(arrayLoc, *elementType);
+ TType *arrayType = new TType(*elementType);
+ arrayType->makeArrays(arraySizes);
+ return parseParameterDeclarator(arrayType, name, nameLoc);
+}
+
+bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality(
+ const TIntermSequence &arguments,
+ TType type,
+ const TSourceLoc &line)
+{
+ if (arguments.empty())
+ {
+ error(line, "implicitly sized array constructor must have at least one argument", "[]");
+ return false;
+ }
+ for (TIntermNode *arg : arguments)
+ {
+ const TIntermTyped *element = arg->getAsTyped();
+ ASSERT(element);
+ size_t dimensionalityFromElement = element->getType().getNumArraySizes() + 1u;
+ if (dimensionalityFromElement > type.getNumArraySizes())
+ {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return false;
+ }
+ else if (dimensionalityFromElement < type.getNumArraySizes())
+ {
+ if (dimensionalityFromElement == 1u)
+ {
+ error(line, "implicitly sized array of arrays constructor argument is not an array",
+ "constructor");
+ }
+ else
+ {
+ error(line,
+ "implicitly sized array of arrays constructor argument dimensionality is too "
+ "low",
+ "constructor");
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+// This function is used to test for the correctness of the parameters passed to various constructor
+// functions and also convert them to the right datatype if it is allowed and required.
+//
+// Returns a node to add to the tree regardless of if an error was generated or not.
+//
+TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line)
+{
+ TType type = fnCall->constructorType();
+ TIntermSequence &arguments = fnCall->arguments();
+ if (type.isUnsizedArray())
+ {
+ if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line))
+ {
+ type.sizeUnsizedArrays(nullptr);
+ return CreateZeroNode(type);
+ }
+ TIntermTyped *firstElement = arguments.at(0)->getAsTyped();
+ ASSERT(firstElement);
+ if (type.getOutermostArraySize() == 0u)
+ {
+ type.sizeOutermostUnsizedArray(static_cast<unsigned int>(arguments.size()));
+ }
+ for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i)
+ {
+ if ((*type.getArraySizes())[i] == 0u)
+ {
+ type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]);
+ }
+ }
+ ASSERT(!type.isUnsizedArray());
+ }
+
+ if (!checkConstructorArguments(line, arguments, type))
+ {
+ return CreateZeroNode(type);
+ }
+
+ TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, &arguments);
+ constructorNode->setLine(line);
+
+ return constructorNode->fold(mDiagnostics);
+}
+
+//
+// Interface/uniform blocks
+// TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
+//
+TIntermDeclaration *TParseContext::addInterfaceBlock(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &nameLine,
+ const ImmutableString &blockName,
+ TFieldList *fieldList,
+ const ImmutableString &instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc &arrayIndexLine)
+{
+ checkIsNotReserved(nameLine, blockName);
+
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
+
+ if (mShaderVersion < 310 && typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line,
+ "invalid qualifier: interface blocks must be uniform in version lower than GLSL ES "
+ "3.10",
+ getQualifierString(typeQualifier.qualifier));
+ }
+ else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer)
+ {
+ error(typeQualifier.line, "invalid qualifier: interface blocks must be uniform or buffer",
+ getQualifierString(typeQualifier.qualifier));
+ }
+
+ if (typeQualifier.invariant)
+ {
+ error(typeQualifier.line, "invalid qualifier on interface block member", "invariant");
+ }
+
+ if (typeQualifier.qualifier != EvqBuffer)
+ {
+ checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
+ }
+
+ // add array index
+ unsigned int arraySize = 0;
+ if (arrayIndex != nullptr)
+ {
+ arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex);
+ }
+
+ checkIndexIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.index);
+
+ if (mShaderVersion < 310)
+ {
+ checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding);
+ }
+ else
+ {
+ checkBlockBindingIsValid(typeQualifier.line, typeQualifier.qualifier,
+ typeQualifier.layoutQualifier.binding, arraySize);
+ }
+
+ checkYuvIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.yuv);
+
+ TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
+ checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
+ checkStd430IsForShaderStorageBlock(typeQualifier.line, blockLayoutQualifier.blockStorage,
+ typeQualifier.qualifier);
+
+ if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ if (typeQualifier.qualifier == EvqUniform)
+ {
+ blockLayoutQualifier.matrixPacking = mDefaultUniformMatrixPacking;
+ }
+ else if (typeQualifier.qualifier == EvqBuffer)
+ {
+ blockLayoutQualifier.matrixPacking = mDefaultBufferMatrixPacking;
+ }
+ }
+
+ if (blockLayoutQualifier.blockStorage == EbsUnspecified)
+ {
+ if (typeQualifier.qualifier == EvqUniform)
+ {
+ blockLayoutQualifier.blockStorage = mDefaultUniformBlockStorage;
+ }
+ else if (typeQualifier.qualifier == EvqBuffer)
+ {
+ blockLayoutQualifier.blockStorage = mDefaultBufferBlockStorage;
+ }
+ }
+
+ checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier);
+
+ checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat);
+
+ // check for sampler types and apply layout qualifiers
+ for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+ {
+ TField *field = (*fieldList)[memberIndex];
+ TType *fieldType = field->type();
+ if (IsOpaqueType(fieldType->getBasicType()))
+ {
+ std::string reason("unsupported type - ");
+ reason += fieldType->getBasicString();
+ reason += " types are not allowed in interface blocks";
+ error(field->line(), reason.c_str(), fieldType->getBasicString());
+ }
+
+ const TQualifier qualifier = fieldType->getQualifier();
+ switch (qualifier)
+ {
+ case EvqGlobal:
+ break;
+ case EvqUniform:
+ if (typeQualifier.qualifier == EvqBuffer)
+ {
+ error(field->line(), "invalid qualifier on shader storage block member",
+ getQualifierString(qualifier));
+ }
+ break;
+ case EvqBuffer:
+ if (typeQualifier.qualifier == EvqUniform)
+ {
+ error(field->line(), "invalid qualifier on uniform block member",
+ getQualifierString(qualifier));
+ }
+ break;
+ default:
+ error(field->line(), "invalid qualifier on interface block member",
+ getQualifierString(qualifier));
+ break;
+ }
+
+ if (fieldType->isInvariant())
+ {
+ error(field->line(), "invalid qualifier on interface block member", "invariant");
+ }
+
+ // check layout qualifiers
+ TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
+ checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
+ checkIndexIsNotSpecified(field->line(), fieldLayoutQualifier.index);
+ checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding);
+
+ if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(field->line(), "invalid layout qualifier: cannot be used here",
+ getBlockStorageString(fieldLayoutQualifier.blockStorage));
+ }
+
+ if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
+ }
+ else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
+ {
+ warning(field->line(),
+ "extraneous layout qualifier: only has an effect on matrix types",
+ getMatrixPackingString(fieldLayoutQualifier.matrixPacking));
+ }
+
+ fieldType->setLayoutQualifier(fieldLayoutQualifier);
+
+ if (mShaderVersion < 310 || memberIndex != fieldList->size() - 1u ||
+ typeQualifier.qualifier != EvqBuffer)
+ {
+ // ESSL 3.10 spec section 4.1.9 allows for runtime-sized arrays.
+ checkIsNotUnsizedArray(field->line(),
+ "array members of interface blocks must specify a size",
+ field->name(), field->type());
+ }
+
+ if (typeQualifier.qualifier == EvqBuffer)
+ {
+ // set memory qualifiers
+ // GLSL ES 3.10 session 4.9 [Memory Access Qualifiers]. When a block declaration is
+ // qualified with a memory qualifier, it is as if all of its members were declared with
+ // the same memory qualifier.
+ const TMemoryQualifier &blockMemoryQualifier = typeQualifier.memoryQualifier;
+ TMemoryQualifier fieldMemoryQualifier = fieldType->getMemoryQualifier();
+ fieldMemoryQualifier.readonly |= blockMemoryQualifier.readonly;
+ fieldMemoryQualifier.writeonly |= blockMemoryQualifier.writeonly;
+ fieldMemoryQualifier.coherent |= blockMemoryQualifier.coherent;
+ fieldMemoryQualifier.restrictQualifier |= blockMemoryQualifier.restrictQualifier;
+ fieldMemoryQualifier.volatileQualifier |= blockMemoryQualifier.volatileQualifier;
+ // TODO(jiajia.qin@intel.com): Decide whether if readonly and writeonly buffer variable
+ // is legal. See bug https://github.com/KhronosGroup/OpenGL-API/issues/7
+ fieldType->setMemoryQualifier(fieldMemoryQualifier);
+ }
+ }
+
+ TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
+ &symbolTable, blockName, fieldList, blockLayoutQualifier, SymbolType::UserDefined);
+ if (!symbolTable.declare(interfaceBlock))
+ {
+ error(nameLine, "redefinition of an interface block name", blockName);
+ }
+
+ TType *interfaceBlockType =
+ new TType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier);
+ if (arrayIndex != nullptr)
+ {
+ interfaceBlockType->makeArray(arraySize);
+ }
+
+ // The instance variable gets created to refer to the interface block type from the AST
+ // regardless of if there's an instance name. It's created as an empty symbol if there is no
+ // instance name.
+ TVariable *instanceVariable =
+ new TVariable(&symbolTable, instanceName, interfaceBlockType,
+ instanceName.empty() ? SymbolType::Empty : SymbolType::UserDefined);
+
+ if (instanceVariable->symbolType() == SymbolType::Empty)
+ {
+ // define symbols for the members of the interface block
+ for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+ {
+ TField *field = (*fieldList)[memberIndex];
+ TType *fieldType = new TType(*field->type());
+
+ // set parent pointer of the field variable
+ fieldType->setInterfaceBlock(interfaceBlock);
+
+ fieldType->setQualifier(typeQualifier.qualifier);
+
+ TVariable *fieldVariable =
+ new TVariable(&symbolTable, field->name(), fieldType, SymbolType::UserDefined);
+ if (!symbolTable.declare(fieldVariable))
+ {
+ error(field->line(), "redefinition of an interface block member name",
+ field->name());
+ }
+ }
+ }
+ else
+ {
+ checkIsNotReserved(instanceLine, instanceName);
+
+ // add a symbol for this interface block
+ if (!symbolTable.declare(instanceVariable))
+ {
+ error(instanceLine, "redefinition of an interface block instance name", instanceName);
+ }
+ }
+
+ TIntermSymbol *blockSymbol = new TIntermSymbol(instanceVariable);
+ blockSymbol->setLine(typeQualifier.line);
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->appendDeclarator(blockSymbol);
+ declaration->setLine(nameLine);
+
+ exitStructDeclaration();
+ return declaration;
+}
+
+void TParseContext::enterStructDeclaration(const TSourceLoc &line,
+ const ImmutableString &identifier)
+{
+ ++mStructNestingLevel;
+
+ // Embedded structure definitions are not supported per GLSL ES spec.
+ // ESSL 1.00.17 section 10.9. ESSL 3.00.6 section 12.11.
+ if (mStructNestingLevel > 1)
+ {
+ error(line, "Embedded struct definitions are not allowed", "struct");
+ }
+}
+
+void TParseContext::exitStructDeclaration()
+{
+ --mStructNestingLevel;
+}
+
+void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field)
+{
+ if (!sh::IsWebGLBasedSpec(mShaderSpec))
+ {
+ return;
+ }
+
+ if (field.type()->getBasicType() != EbtStruct)
+ {
+ return;
+ }
+
+ // We're already inside a structure definition at this point, so add
+ // one to the field's struct nesting.
+ if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
+ {
+ std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
+ if (field.type()->getStruct()->symbolType() == SymbolType::Empty)
+ {
+ // This may happen in case there are nested struct definitions. While they are also
+ // invalid GLSL, they don't cause a syntax error.
+ reasonStream << "Struct nesting";
+ }
+ else
+ {
+ reasonStream << "Reference of struct type " << field.type()->getStruct()->name();
+ }
+ reasonStream << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
+ std::string reason = reasonStream.str();
+ error(line, reason.c_str(), field.name());
+ return;
+ }
+}
+
+//
+// Parse an array index expression
+//
+TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &location,
+ TIntermTyped *indexExpression)
+{
+ if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
+ {
+ if (baseExpression->getAsSymbolNode())
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ",
+ baseExpression->getAsSymbolNode()->getName());
+ }
+ else
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
+ }
+
+ return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+ }
+
+ if (baseExpression->getQualifier() == EvqPerVertexIn)
+ {
+ ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT);
+ if (mGeometryShaderInputPrimitiveType == EptUndefined)
+ {
+ error(location, "missing input primitive declaration before indexing gl_in.", "[");
+ return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+ }
+ }
+
+ TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
+
+ // ANGLE should be able to fold any constant expressions resulting in an integer - but to be
+ // safe we don't treat "EvqConst" that's evaluated according to the spec as being sufficient
+ // for constness. Some interpretations of the spec have allowed constant expressions with side
+ // effects - like array length() method on a non-constant array.
+ if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr)
+ {
+ if (baseExpression->isInterfaceBlock())
+ {
+ // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
+ switch (baseExpression->getQualifier())
+ {
+ case EvqPerVertexIn:
+ break;
+ case EvqUniform:
+ case EvqBuffer:
+ error(location,
+ "array indexes for uniform block arrays and shader storage block arrays "
+ "must be constant integral expressions",
+ "[");
+ break;
+ default:
+ // We can reach here only in error cases.
+ ASSERT(mDiagnostics->numErrors() > 0);
+ break;
+ }
+ }
+ else if (baseExpression->getQualifier() == EvqFragmentOut)
+ {
+ error(location,
+ "array indexes for fragment outputs must be constant integral expressions", "[");
+ }
+ else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
+ {
+ error(location, "array index for gl_FragData must be constant zero", "[");
+ }
+ }
+
+ if (indexConstantUnion)
+ {
+ // If an out-of-range index is not qualified as constant, the behavior in the spec is
+ // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may
+ // constant fold expressions that are not constant expressions). The most compatible way to
+ // handle this case is to report a warning instead of an error and force the index to be in
+ // the correct range.
+ bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
+ int index = 0;
+ if (indexConstantUnion->getBasicType() == EbtInt)
+ {
+ index = indexConstantUnion->getIConst(0);
+ }
+ else if (indexConstantUnion->getBasicType() == EbtUInt)
+ {
+ index = static_cast<int>(indexConstantUnion->getUConst(0));
+ }
+
+ int safeIndex = -1;
+
+ if (index < 0)
+ {
+ outOfRangeError(outOfRangeIndexIsError, location, "index expression is negative", "[]");
+ safeIndex = 0;
+ }
+
+ if (!baseExpression->getType().isUnsizedArray())
+ {
+ if (baseExpression->isArray())
+ {
+ if (baseExpression->getQualifier() == EvqFragData && index > 0)
+ {
+ if (!isExtensionEnabled(TExtension::EXT_draw_buffers))
+ {
+ outOfRangeError(outOfRangeIndexIsError, location,
+ "array index for gl_FragData must be zero when "
+ "GL_EXT_draw_buffers is disabled",
+ "[]");
+ safeIndex = 0;
+ }
+ }
+ }
+ // Only do generic out-of-range check if similar error hasn't already been reported.
+ if (safeIndex < 0)
+ {
+ if (baseExpression->isArray())
+ {
+ safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index,
+ baseExpression->getOutermostArraySize(),
+ "array index out of range");
+ }
+ else if (baseExpression->isMatrix())
+ {
+ safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getCols(),
+ "matrix field selection out of range");
+ }
+ else
+ {
+ ASSERT(baseExpression->isVector());
+ safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getNominalSize(),
+ "vector field selection out of range");
+ }
+ }
+
+ ASSERT(safeIndex >= 0);
+ // Data of constant unions can't be changed, because it may be shared with other
+ // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
+ // sanitized object.
+ if (safeIndex != index || indexConstantUnion->getBasicType() != EbtInt)
+ {
+ TConstantUnion *safeConstantUnion = new TConstantUnion();
+ safeConstantUnion->setIConst(safeIndex);
+ indexExpression = new TIntermConstantUnion(
+ safeConstantUnion, TType(EbtInt, indexExpression->getPrecision(),
+ indexExpression->getQualifier()));
+ }
+
+ TIntermBinary *node =
+ new TIntermBinary(EOpIndexDirect, baseExpression, indexExpression);
+ node->setLine(location);
+ return expressionOrFoldedResult(node);
+ }
+ }
+
+ markStaticReadIfSymbol(indexExpression);
+ TIntermBinary *node = new TIntermBinary(EOpIndexIndirect, baseExpression, indexExpression);
+ node->setLine(location);
+ // Indirect indexing can never be constant folded.
+ return node;
+}
+
+int TParseContext::checkIndexLessThan(bool outOfRangeIndexIsError,
+ const TSourceLoc &location,
+ int index,
+ int arraySize,
+ const char *reason)
+{
+ // Should not reach here with an unsized / runtime-sized array.
+ ASSERT(arraySize > 0);
+ // A negative index should already have been checked.
+ ASSERT(index >= 0);
+ if (index >= arraySize)
+ {
+ std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
+ reasonStream << reason << " '" << index << "'";
+ std::string token = reasonStream.str();
+ outOfRangeError(outOfRangeIndexIsError, location, reason, "[]");
+ return arraySize - 1;
+ }
+ return index;
+}
+
+TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &dotLocation,
+ const ImmutableString &fieldString,
+ const TSourceLoc &fieldLocation)
+{
+ if (baseExpression->isArray())
+ {
+ error(fieldLocation, "cannot apply dot operator to an array", ".");
+ return baseExpression;
+ }
+
+ if (baseExpression->isVector())
+ {
+ TVector<int> fieldOffsets;
+ if (!parseVectorFields(fieldLocation, fieldString, baseExpression->getNominalSize(),
+ &fieldOffsets))
+ {
+ fieldOffsets.resize(1);
+ fieldOffsets[0] = 0;
+ }
+ TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldOffsets);
+ node->setLine(dotLocation);
+
+ return node->fold(mDiagnostics);
+ }
+ else if (baseExpression->getBasicType() == EbtStruct)
+ {
+ const TFieldList &fields = baseExpression->getType().getStruct()->fields();
+ if (fields.empty())
+ {
+ error(dotLocation, "structure has no fields", "Internal Error");
+ return baseExpression;
+ }
+ else
+ {
+ bool fieldFound = false;
+ unsigned int i;
+ for (i = 0; i < fields.size(); ++i)
+ {
+ if (fields[i]->name() == fieldString)
+ {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound)
+ {
+ TIntermTyped *index = CreateIndexNode(i);
+ index->setLine(fieldLocation);
+ TIntermBinary *node =
+ new TIntermBinary(EOpIndexDirectStruct, baseExpression, index);
+ node->setLine(dotLocation);
+ return expressionOrFoldedResult(node);
+ }
+ else
+ {
+ error(dotLocation, " no such field in structure", fieldString);
+ return baseExpression;
+ }
+ }
+ }
+ else if (baseExpression->isInterfaceBlock())
+ {
+ const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
+ if (fields.empty())
+ {
+ error(dotLocation, "interface block has no fields", "Internal Error");
+ return baseExpression;
+ }
+ else
+ {
+ bool fieldFound = false;
+ unsigned int i;
+ for (i = 0; i < fields.size(); ++i)
+ {
+ if (fields[i]->name() == fieldString)
+ {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound)
+ {
+ TIntermTyped *index = CreateIndexNode(i);
+ index->setLine(fieldLocation);
+ TIntermBinary *node =
+ new TIntermBinary(EOpIndexDirectInterfaceBlock, baseExpression, index);
+ node->setLine(dotLocation);
+ // Indexing interface blocks can never be constant folded.
+ return node;
+ }
+ else
+ {
+ error(dotLocation, " no such field in interface block", fieldString);
+ return baseExpression;
+ }
+ }
+ }
+ else
+ {
+ if (mShaderVersion < 300)
+ {
+ error(dotLocation, " field selection requires structure or vector on left hand side",
+ fieldString);
+ }
+ else
+ {
+ error(dotLocation,
+ " field selection requires structure, vector, or interface block on left hand "
+ "side",
+ fieldString);
+ }
+ return baseExpression;
+ }
+}
+
+TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType,
+ const TSourceLoc &qualifierTypeLine)
+{
+ TLayoutQualifier qualifier = TLayoutQualifier::Create();
+
+ if (qualifierType == "shared")
+ {
+ if (sh::IsWebGLBasedSpec(mShaderSpec))
+ {
+ error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared");
+ }
+ qualifier.blockStorage = EbsShared;
+ }
+ else if (qualifierType == "packed")
+ {
+ if (sh::IsWebGLBasedSpec(mShaderSpec))
+ {
+ error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed");
+ }
+ qualifier.blockStorage = EbsPacked;
+ }
+ else if (qualifierType == "std430")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.blockStorage = EbsStd430;
+ }
+ else if (qualifierType == "std140")
+ {
+ qualifier.blockStorage = EbsStd140;
+ }
+ else if (qualifierType == "row_major")
+ {
+ qualifier.matrixPacking = EmpRowMajor;
+ }
+ else if (qualifierType == "column_major")
+ {
+ qualifier.matrixPacking = EmpColumnMajor;
+ }
+ else if (qualifierType == "location")
+ {
+ error(qualifierTypeLine, "invalid layout qualifier: location requires an argument",
+ qualifierType);
+ }
+ else if (qualifierType == "yuv" && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ if (checkCanUseExtension(qualifierTypeLine, TExtension::EXT_YUV_target))
+ {
+ qualifier.yuv = true;
+ }
+ }
+ else if (qualifierType == "rgba32f")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA32F;
+ }
+ else if (qualifierType == "rgba16f")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA16F;
+ }
+ else if (qualifierType == "r32f")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifR32F;
+ }
+ else if (qualifierType == "rgba8")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA8;
+ }
+ else if (qualifierType == "rgba8_snorm")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA8_SNORM;
+ }
+ else if (qualifierType == "rgba32i")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA32I;
+ }
+ else if (qualifierType == "rgba16i")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA16I;
+ }
+ else if (qualifierType == "rgba8i")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA8I;
+ }
+ else if (qualifierType == "r32i")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifR32I;
+ }
+ else if (qualifierType == "rgba32ui")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA32UI;
+ }
+ else if (qualifierType == "rgba16ui")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA16UI;
+ }
+ else if (qualifierType == "rgba8ui")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifRGBA8UI;
+ }
+ else if (qualifierType == "r32ui")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.imageInternalFormat = EiifR32UI;
+ }
+ else if (qualifierType == "points" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptPoints;
+ }
+ else if (qualifierType == "lines" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptLines;
+ }
+ else if (qualifierType == "lines_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptLinesAdjacency;
+ }
+ else if (qualifierType == "triangles" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptTriangles;
+ }
+ else if (qualifierType == "triangles_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptTrianglesAdjacency;
+ }
+ else if (qualifierType == "line_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptLineStrip;
+ }
+ else if (qualifierType == "triangle_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ qualifier.primitiveType = EptTriangleStrip;
+ }
+
+ else
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
+ }
+
+ return qualifier;
+}
+
+void TParseContext::parseLocalSize(const ImmutableString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ size_t index,
+ sh::WorkGroupSize *localSize)
+{
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ if (intValue < 1)
+ {
+ std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
+ reasonStream << "out of range: " << getWorkGroupSizeString(index) << " must be positive";
+ std::string reason = reasonStream.str();
+ error(intValueLine, reason.c_str(), intValueString.c_str());
+ }
+ (*localSize)[index] = intValue;
+}
+
+void TParseContext::parseNumViews(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *numViews)
+{
+ // This error is only specified in WebGL, but tightens unspecified behavior in the native
+ // specification.
+ if (intValue < 1)
+ {
+ error(intValueLine, "out of range: num_views must be positive", intValueString.c_str());
+ }
+ *numViews = intValue;
+}
+
+void TParseContext::parseInvocations(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *numInvocations)
+{
+ // Although SPEC isn't clear whether invocations can be less than 1, we add this limit because
+ // it doesn't make sense to accept invocations <= 0.
+ if (intValue < 1 || intValue > mMaxGeometryShaderInvocations)
+ {
+ error(intValueLine,
+ "out of range: invocations must be in the range of [1, "
+ "MAX_GEOMETRY_SHADER_INVOCATIONS_OES]",
+ intValueString.c_str());
+ }
+ else
+ {
+ *numInvocations = intValue;
+ }
+}
+
+void TParseContext::parseMaxVertices(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *maxVertices)
+{
+ // Although SPEC isn't clear whether max_vertices can be less than 0, we add this limit because
+ // it doesn't make sense to accept max_vertices < 0.
+ if (intValue < 0 || intValue > mMaxGeometryShaderMaxVertices)
+ {
+ error(
+ intValueLine,
+ "out of range: max_vertices must be in the range of [0, gl_MaxGeometryOutputVertices]",
+ intValueString.c_str());
+ }
+ else
+ {
+ *maxVertices = intValue;
+ }
+}
+
+void TParseContext::parseIndexLayoutQualifier(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *index)
+{
+ // EXT_blend_func_extended specifies that most validation should happen at link time, but since
+ // we're validating output variable locations at compile time, it makes sense to validate that
+ // index is 0 or 1 also at compile time. Also since we use "-1" as a placeholder for unspecified
+ // index, we can't accept it here.
+ if (intValue < 0 || intValue > 1)
+ {
+ error(intValueLine, "out of range: index layout qualifier can only be 0 or 1",
+ intValueString.c_str());
+ }
+ else
+ {
+ *index = intValue;
+ }
+}
+
+TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ int intValue,
+ const TSourceLoc &intValueLine)
+{
+ TLayoutQualifier qualifier = TLayoutQualifier::Create();
+
+ std::string intValueString = Str(intValue);
+
+ if (qualifierType == "location")
+ {
+ // must check that location is non-negative
+ if (intValue < 0)
+ {
+ error(intValueLine, "out of range: location must be non-negative",
+ intValueString.c_str());
+ }
+ else
+ {
+ qualifier.location = intValue;
+ qualifier.locationsSpecified = 1;
+ }
+ }
+ else if (qualifierType == "binding")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ if (intValue < 0)
+ {
+ error(intValueLine, "out of range: binding must be non-negative",
+ intValueString.c_str());
+ }
+ else
+ {
+ qualifier.binding = intValue;
+ }
+ }
+ else if (qualifierType == "offset")
+ {
+ checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
+ if (intValue < 0)
+ {
+ error(intValueLine, "out of range: offset must be non-negative",
+ intValueString.c_str());
+ }
+ else
+ {
+ qualifier.offset = intValue;
+ }
+ }
+ else if (qualifierType == "local_size_x")
+ {
+ parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u,
+ &qualifier.localSize);
+ }
+ else if (qualifierType == "local_size_y")
+ {
+ parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u,
+ &qualifier.localSize);
+ }
+ else if (qualifierType == "local_size_z")
+ {
+ parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u,
+ &qualifier.localSize);
+ }
+ else if (qualifierType == "num_views" && mShaderType == GL_VERTEX_SHADER)
+ {
+ if (checkCanUseOneOfExtensions(
+ qualifierTypeLine, std::array<TExtension, 2u>{
+ {TExtension::OVR_multiview, TExtension::OVR_multiview2}}))
+ {
+ parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews);
+ }
+ }
+ else if (qualifierType == "invocations" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ parseInvocations(intValue, intValueLine, intValueString, &qualifier.invocations);
+ }
+ else if (qualifierType == "max_vertices" && mShaderType == GL_GEOMETRY_SHADER_EXT &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
+ {
+ parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices);
+ }
+ else if (qualifierType == "index" && mShaderType == GL_FRAGMENT_SHADER &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_blend_func_extended))
+ {
+ parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index);
+ }
+ else
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
+ }
+
+ return qualifier;
+}
+
+TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc)
+{
+ return new TTypeQualifierBuilder(
+ new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc),
+ mShaderVersion);
+}
+
+TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier,
+ const TSourceLoc &loc)
+{
+ checkIsAtGlobalLevel(loc, getQualifierString(qualifier));
+ return new TStorageQualifierWrapper(qualifier, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc)
+{
+ if (getShaderType() == GL_VERTEX_SHADER)
+ {
+ return parseGlobalStorageQualifier(EvqVaryingOut, loc);
+ }
+ return parseGlobalStorageQualifier(EvqVaryingIn, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc)
+{
+ if (declaringFunction())
+ {
+ return new TStorageQualifierWrapper(EvqIn, loc);
+ }
+
+ switch (getShaderType())
+ {
+ case GL_VERTEX_SHADER:
+ {
+ if (mShaderVersion < 300 && !anyMultiviewExtensionAvailable())
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+ }
+ return new TStorageQualifierWrapper(EvqVertexIn, loc);
+ }
+ case GL_FRAGMENT_SHADER:
+ {
+ if (mShaderVersion < 300)
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+ }
+ return new TStorageQualifierWrapper(EvqFragmentIn, loc);
+ }
+ case GL_COMPUTE_SHADER:
+ {
+ return new TStorageQualifierWrapper(EvqComputeIn, loc);
+ }
+ case GL_GEOMETRY_SHADER_EXT:
+ {
+ return new TStorageQualifierWrapper(EvqGeometryIn, loc);
+ }
+ default:
+ {
+ UNREACHABLE();
+ return new TStorageQualifierWrapper(EvqLast, loc);
+ }
+ }
+}
+
+TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc)
+{
+ if (declaringFunction())
+ {
+ return new TStorageQualifierWrapper(EvqOut, loc);
+ }
+ switch (getShaderType())
+ {
+ case GL_VERTEX_SHADER:
+ {
+ if (mShaderVersion < 300)
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
+ }
+ return new TStorageQualifierWrapper(EvqVertexOut, loc);
+ }
+ case GL_FRAGMENT_SHADER:
+ {
+ if (mShaderVersion < 300)
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
+ }
+ return new TStorageQualifierWrapper(EvqFragmentOut, loc);
+ }
+ case GL_COMPUTE_SHADER:
+ {
+ error(loc, "storage qualifier isn't supported in compute shaders", "out");
+ return new TStorageQualifierWrapper(EvqLast, loc);
+ }
+ case GL_GEOMETRY_SHADER_EXT:
+ {
+ return new TStorageQualifierWrapper(EvqGeometryOut, loc);
+ }
+ default:
+ {
+ UNREACHABLE();
+ return new TStorageQualifierWrapper(EvqLast, loc);
+ }
+ }
+}
+
+TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc)
+{
+ if (!declaringFunction())
+ {
+ error(loc, "invalid qualifier: can be only used with function parameters", "inout");
+ }
+ return new TStorageQualifierWrapper(EvqInOut, loc);
+}
+
+TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier,
+ const TSourceLoc &rightQualifierLocation)
+{
+ return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
+ mDiagnostics);
+}
+
+TDeclarator *TParseContext::parseStructDeclarator(const ImmutableString &identifier,
+ const TSourceLoc &loc)
+{
+ checkIsNotReserved(loc, identifier);
+ return new TDeclarator(identifier, loc);
+}
+
+TDeclarator *TParseContext::parseStructArrayDeclarator(const ImmutableString &identifier,
+ const TSourceLoc &loc,
+ const TVector<unsigned int> *arraySizes)
+{
+ checkIsNotReserved(loc, identifier);
+ return new TDeclarator(identifier, arraySizes, loc);
+}
+
+void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
+ const TFieldList::const_iterator end,
+ const ImmutableString &name,
+ const TSourceLoc &location)
+{
+ for (auto fieldIter = begin; fieldIter != end; ++fieldIter)
+ {
+ if ((*fieldIter)->name() == name)
+ {
+ error(location, "duplicate field name in structure", name);
+ }
+ }
+}
+
+TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location)
+{
+ for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end();
+ ++fieldIter)
+ {
+ checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(),
+ location);
+ }
+ return fields;
+}
+
+TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
+ const TFieldList *newlyAddedFields,
+ const TSourceLoc &location)
+{
+ for (TField *field : *newlyAddedFields)
+ {
+ checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(),
+ field->name(), location);
+ processedFields->push_back(field);
+ }
+ return processedFields;
+}
+
+TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TPublicType *typeSpecifier,
+ const TDeclaratorList *declaratorList)
+{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
+
+ typeSpecifier->qualifier = typeQualifier.qualifier;
+ typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
+ typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier;
+ typeSpecifier->invariant = typeQualifier.invariant;
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ typeSpecifier->precision = typeQualifier.precision;
+ }
+ return addStructDeclaratorList(*typeSpecifier, declaratorList);
+}
+
+TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
+ const TDeclaratorList *declaratorList)
+{
+ checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
+ typeSpecifier.getBasicType());
+
+ checkIsNonVoid(typeSpecifier.getLine(), (*declaratorList)[0]->name(),
+ typeSpecifier.getBasicType());
+
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
+
+ TFieldList *fieldList = new TFieldList();
+
+ for (const TDeclarator *declarator : *declaratorList)
+ {
+ TType *type = new TType(typeSpecifier);
+ if (declarator->isArray())
+ {
+ // Don't allow arrays of arrays in ESSL < 3.10.
+ checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier);
+ type->makeArrays(*declarator->arraySizes());
+ }
+
+ TField *field =
+ new TField(type, declarator->name(), declarator->line(), SymbolType::UserDefined);
+ checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *field);
+ fieldList->push_back(field);
+ }
+
+ return fieldList;
+}
+
+TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const ImmutableString &structName,
+ TFieldList *fieldList)
+{
+ SymbolType structSymbolType = SymbolType::UserDefined;
+ if (structName.empty())
+ {
+ structSymbolType = SymbolType::Empty;
+ }
+ TStructure *structure = new TStructure(&symbolTable, structName, fieldList, structSymbolType);
+
+ // Store a bool in the struct if we're at global scope, to allow us to
+ // skip the local struct scoping workaround in HLSL.
+ structure->setAtGlobalScope(symbolTable.atGlobalLevel());
+
+ if (structSymbolType != SymbolType::Empty)
+ {
+ checkIsNotReserved(nameLine, structName);
+ if (!symbolTable.declare(structure))
+ {
+ error(nameLine, "redefinition of a struct", structName);
+ }
+ }
+
+ // ensure we do not specify any storage qualifiers on the struct members
+ for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
+ {
+ TField &field = *(*fieldList)[typeListIndex];
+ const TQualifier qualifier = field.type()->getQualifier();
+ switch (qualifier)
+ {
+ case EvqGlobal:
+ case EvqTemporary:
+ break;
+ default:
+ error(field.line(), "invalid qualifier on struct member",
+ getQualifierString(qualifier));
+ break;
+ }
+ if (field.type()->isInvariant())
+ {
+ error(field.line(), "invalid qualifier on struct member", "invariant");
+ }
+ // ESSL 3.10 section 4.1.8 -- atomic_uint or images are not allowed as structure member.
+ if (IsImage(field.type()->getBasicType()) || IsAtomicCounter(field.type()->getBasicType()))
+ {
+ error(field.line(), "disallowed type in struct", field.type()->getBasicString());
+ }
+
+ checkIsNotUnsizedArray(field.line(), "array members of structs must specify a size",
+ field.name(), field.type());
+
+ checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line());
+
+ checkIndexIsNotSpecified(field.line(), field.type()->getLayoutQualifier().index);
+
+ checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding);
+
+ checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
+ }
+
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ typeSpecifierNonArray.initializeStruct(structure, true, structLine);
+ exitStructDeclaration();
+
+ return typeSpecifierNonArray;
+}
+
+TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc)
+{
+ TBasicType switchType = init->getBasicType();
+ if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
+ init->isVector())
+ {
+ error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
+ "switch");
+ return nullptr;
+ }
+
+ ASSERT(statementList);
+ if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc))
+ {
+ ASSERT(mDiagnostics->numErrors() > 0);
+ return nullptr;
+ }
+
+ markStaticReadIfSymbol(init);
+ TIntermSwitch *node = new TIntermSwitch(init, statementList);
+ node->setLine(loc);
+ return node;
+}
+
+TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
+{
+ if (mSwitchNestingLevel == 0)
+ {
+ error(loc, "case labels need to be inside switch statements", "case");
+ return nullptr;
+ }
+ if (condition == nullptr)
+ {
+ error(loc, "case label must have a condition", "case");
+ return nullptr;
+ }
+ if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
+ condition->isMatrix() || condition->isArray() || condition->isVector())
+ {
+ error(condition->getLine(), "case label must be a scalar integer", "case");
+ }
+ TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
+ // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be
+ // safe against corner cases we still check for conditionConst. Some interpretations of the
+ // spec have allowed constant expressions with side effects - like array length() method on a
+ // non-constant array.
+ if (condition->getQualifier() != EvqConst || conditionConst == nullptr)
+ {
+ error(condition->getLine(), "case label must be constant", "case");
+ }
+ TIntermCase *node = new TIntermCase(condition);
+ node->setLine(loc);
+ return node;
+}
+
+TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
+{
+ if (mSwitchNestingLevel == 0)
+ {
+ error(loc, "default labels need to be inside switch statements", "default");
+ return nullptr;
+ }
+ TIntermCase *node = new TIntermCase(nullptr);
+ node->setLine(loc);
+ return node;
+}
+
+TIntermTyped *TParseContext::createUnaryMath(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc,
+ const TFunction *func)
+{
+ ASSERT(child != nullptr);
+
+ switch (op)
+ {
+ case EOpLogicalNot:
+ if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
+ child->isVector())
+ {
+ unaryOpError(loc, GetOperatorString(op), child->getType());
+ return nullptr;
+ }
+ break;
+ case EOpBitwiseNot:
+ if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
+ child->isMatrix() || child->isArray())
+ {
+ unaryOpError(loc, GetOperatorString(op), child->getType());
+ return nullptr;
+ }
+ break;
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ case EOpPositive:
+ if (child->getBasicType() == EbtStruct || child->isInterfaceBlock() ||
+ child->getBasicType() == EbtBool || child->isArray() ||
+ child->getBasicType() == EbtVoid || IsOpaqueType(child->getBasicType()))
+ {
+ unaryOpError(loc, GetOperatorString(op), child->getType());
+ return nullptr;
+ }
+ break;
+ // Operators for built-ins are already type checked against their prototype.
+ default:
+ break;
+ }
+
+ if (child->getMemoryQualifier().writeonly)
+ {
+ unaryOpError(loc, GetOperatorString(op), child->getType());
+ return nullptr;
+ }
+
+ markStaticReadIfSymbol(child);
+ TIntermUnary *node = new TIntermUnary(op, child, func);
+ node->setLine(loc);
+
+ return node->fold(mDiagnostics);
+}
+
+TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
+{
+ ASSERT(op != EOpNull);
+ TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
+ if (node == nullptr)
+ {
+ return child;
+ }
+ return node;
+}
+
+TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc)
+{
+ checkCanBeLValue(loc, GetOperatorString(op), child);
+ return addUnaryMath(op, child, loc);
+}
+
+TIntermTyped *TParseContext::expressionOrFoldedResult(TIntermTyped *expression)
+{
+ // If we can, we should return the folded version of the expression for subsequent parsing. This
+ // enables folding the containing expression during parsing as well, instead of the separate
+ // FoldExpressions() step where folding nested expressions requires multiple full AST
+ // traversals.
+
+ // Even if folding fails the fold() functions return some node representing the expression,
+ // typically the original node. So "folded" can be assumed to be non-null.
+ TIntermTyped *folded = expression->fold(mDiagnostics);
+ ASSERT(folded != nullptr);
+ if (folded->getQualifier() == expression->getQualifier())
+ {
+ // We need this expression to have the correct qualifier when validating the consuming
+ // expression. So we can only return the folded node from here in case it has the same
+ // qualifier as the original expression. In this kind of a cases the qualifier of the folded
+ // node is EvqConst, whereas the qualifier of the expression is EvqTemporary:
+ // 1. (true ? 1.0 : non_constant)
+ // 2. (non_constant, 1.0)
+ return folded;
+ }
+ return expression;
+}
+
+bool TParseContext::binaryOpCommonCheck(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ // Check opaque types are not allowed to be operands in expressions other than array indexing
+ // and structure member selection.
+ if (IsOpaqueType(left->getBasicType()) || IsOpaqueType(right->getBasicType()))
+ {
+ switch (op)
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ break;
+
+ default:
+ ASSERT(op != EOpIndexDirectStruct);
+ error(loc, "Invalid operation for variables with an opaque type",
+ GetOperatorString(op));
+ return false;
+ }
+ }
+
+ if (right->getMemoryQualifier().writeonly)
+ {
+ error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op));
+ return false;
+ }
+
+ if (left->getMemoryQualifier().writeonly)
+ {
+ switch (op)
+ {
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ break;
+ default:
+ error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op));
+ return false;
+ }
+ }
+
+ if (left->getType().getStruct() || right->getType().getStruct())
+ {
+ switch (op)
+ {
+ case EOpIndexDirectStruct:
+ ASSERT(left->getType().getStruct());
+ break;
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpAssign:
+ case EOpInitialize:
+ if (left->getType() != right->getType())
+ {
+ return false;
+ }
+ break;
+ default:
+ error(loc, "Invalid operation for structs", GetOperatorString(op));
+ return false;
+ }
+ }
+
+ if (left->isInterfaceBlock() || right->isInterfaceBlock())
+ {
+ switch (op)
+ {
+ case EOpIndexDirectInterfaceBlock:
+ ASSERT(left->getType().getInterfaceBlock());
+ break;
+ default:
+ error(loc, "Invalid operation for interface blocks", GetOperatorString(op));
+ return false;
+ }
+ }
+
+ if (left->isArray() != right->isArray())
+ {
+ error(loc, "array / non-array mismatch", GetOperatorString(op));
+ return false;
+ }
+
+ if (left->isArray())
+ {
+ ASSERT(right->isArray());
+ if (mShaderVersion < 300)
+ {
+ error(loc, "Invalid operation for arrays", GetOperatorString(op));
+ return false;
+ }
+
+ switch (op)
+ {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpAssign:
+ case EOpInitialize:
+ break;
+ default:
+ error(loc, "Invalid operation for arrays", GetOperatorString(op));
+ return false;
+ }
+ // At this point, size of implicitly sized arrays should be resolved.
+ if (*left->getType().getArraySizes() != *right->getType().getArraySizes())
+ {
+ error(loc, "array size mismatch", GetOperatorString(op));
+ return false;
+ }
+ }
+
+ // Check ops which require integer / ivec parameters
+ bool isBitShift = false;
+ switch (op)
+ {
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ // Unsigned can be bit-shifted by signed and vice versa, but we need to
+ // check that the basic type is an integer type.
+ isBitShift = true;
+ if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
+ {
+ return false;
+ }
+ break;
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ // It is enough to check the type of only one operand, since later it
+ // is checked that the operand types match.
+ if (!IsInteger(left->getBasicType()))
+ {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ImplicitTypeConversion conversion = GetConversion(left->getBasicType(), right->getBasicType());
+
+ // Implicit type casting only supported for GL shaders
+ if (!isBitShift && conversion != ImplicitTypeConversion::Same &&
+ (!IsDesktopGLSpec(mShaderSpec) || !IsValidImplicitConversion(conversion, op)))
+ {
+ return false;
+ }
+
+ // Check that:
+ // 1. Type sizes match exactly on ops that require that.
+ // 2. Restrictions for structs that contain arrays or samplers are respected.
+ // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected.
+ switch (op)
+ {
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpEqual:
+ case EOpNotEqual:
+ // ESSL 1.00 sections 5.7, 5.8, 5.9
+ if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
+ {
+ error(loc, "undefined operation for structs containing arrays",
+ GetOperatorString(op));
+ return false;
+ }
+ // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
+ // we interpret the spec so that this extends to structs containing samplers,
+ // similarly to ESSL 1.00 spec.
+ if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
+ left->getType().isStructureContainingSamplers())
+ {
+ error(loc, "undefined operation for structs containing samplers",
+ GetOperatorString(op));
+ return false;
+ }
+
+ if ((left->getNominalSize() != right->getNominalSize()) ||
+ (left->getSecondarySize() != right->getSecondarySize()))
+ {
+ error(loc, "dimension mismatch", GetOperatorString(op));
+ return false;
+ }
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if (!left->isScalar() || !right->isScalar())
+ {
+ error(loc, "comparison operator only defined for scalars", GetOperatorString(op));
+ return false;
+ }
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpIMod:
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()))
+ {
+ return false;
+ }
+
+ // Are the sizes compatible?
+ if (left->getNominalSize() != right->getNominalSize() ||
+ left->getSecondarySize() != right->getSecondarySize())
+ {
+ // If the nominal sizes of operands do not match:
+ // One of them must be a scalar.
+ if (!left->isScalar() && !right->isScalar())
+ return false;
+
+ // In the case of compound assignment other than multiply-assign,
+ // the right side needs to be a scalar. Otherwise a vector/matrix
+ // would be assigned to a scalar. A scalar can't be shifted by a
+ // vector either.
+ if (!right->isScalar() &&
+ (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight))
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op,
+ const TType &left,
+ const TType &right)
+{
+ switch (op)
+ {
+ case EOpMul:
+ case EOpMulAssign:
+ return left.getNominalSize() == right.getNominalSize() &&
+ left.getSecondarySize() == right.getSecondarySize();
+ case EOpVectorTimesScalar:
+ return true;
+ case EOpVectorTimesScalarAssign:
+ ASSERT(!left.isMatrix() && !right.isMatrix());
+ return left.isVector() && !right.isVector();
+ case EOpVectorTimesMatrix:
+ return left.getNominalSize() == right.getRows();
+ case EOpVectorTimesMatrixAssign:
+ ASSERT(!left.isMatrix() && right.isMatrix());
+ return left.isVector() && left.getNominalSize() == right.getRows() &&
+ left.getNominalSize() == right.getCols();
+ case EOpMatrixTimesVector:
+ return left.getCols() == right.getNominalSize();
+ case EOpMatrixTimesScalar:
+ return true;
+ case EOpMatrixTimesScalarAssign:
+ ASSERT(left.isMatrix() && !right.isMatrix());
+ return !right.isVector();
+ case EOpMatrixTimesMatrix:
+ return left.getCols() == right.getRows();
+ case EOpMatrixTimesMatrixAssign:
+ ASSERT(left.isMatrix() && right.isMatrix());
+ // We need to check two things:
+ // 1. The matrix multiplication step is valid.
+ // 2. The result will have the same number of columns as the lvalue.
+ return left.getCols() == right.getRows() && left.getCols() == right.getCols();
+
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ if (!binaryOpCommonCheck(op, left, right, loc))
+ return nullptr;
+
+ switch (op)
+ {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
+ !right->getType().getStruct());
+ if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar())
+ {
+ return nullptr;
+ }
+ // Basic types matching should have been already checked.
+ ASSERT(right->getBasicType() == EbtBool);
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpMul:
+ ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
+ !right->getType().getStruct());
+ if (left->getBasicType() == EbtBool)
+ {
+ return nullptr;
+ }
+ break;
+ case EOpIMod:
+ ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
+ !right->getType().getStruct());
+ // Note that this is only for the % operator, not for mod()
+ if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat)
+ {
+ return nullptr;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (op == EOpMul)
+ {
+ op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType());
+ if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
+ {
+ return nullptr;
+ }
+ }
+
+ TIntermBinary *node = new TIntermBinary(op, left, right);
+ ASSERT(op != EOpAssign);
+ markStaticReadIfSymbol(left);
+ markStaticReadIfSymbol(right);
+ node->setLine(loc);
+ return expressionOrFoldedResult(node);
+}
+
+TIntermTyped *TParseContext::addBinaryMath(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
+ if (node == 0)
+ {
+ binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType());
+ return left;
+ }
+ return node;
+}
+
+TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
+ if (node == nullptr)
+ {
+ binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType());
+ node = CreateBoolNode(false);
+ node->setLine(loc);
+ }
+ return node;
+}
+
+TIntermTyped *TParseContext::addAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ checkCanBeLValue(loc, "assign", left);
+ TIntermBinary *node = nullptr;
+ if (binaryOpCommonCheck(op, left, right, loc))
+ {
+ if (op == EOpMulAssign)
+ {
+ op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType());
+ if (isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
+ {
+ node = new TIntermBinary(op, left, right);
+ }
+ }
+ else
+ {
+ node = new TIntermBinary(op, left, right);
+ }
+ }
+ if (node == nullptr)
+ {
+ assignError(loc, "assign", left->getType(), right->getType());
+ return left;
+ }
+ if (op != EOpAssign)
+ {
+ markStaticReadIfSymbol(left);
+ }
+ markStaticReadIfSymbol(right);
+ node->setLine(loc);
+ return node;
+}
+
+TIntermTyped *TParseContext::addComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ // WebGL2 section 5.26, the following results in an error:
+ // "Sequence operator applied to void, arrays, or structs containing arrays"
+ if (mShaderSpec == SH_WEBGL2_SPEC &&
+ (left->isArray() || left->getBasicType() == EbtVoid ||
+ left->getType().isStructureContainingArrays() || right->isArray() ||
+ right->getBasicType() == EbtVoid || right->getType().isStructureContainingArrays()))
+ {
+ error(loc,
+ "sequence operator is not allowed for void, arrays, or structs containing arrays",
+ ",");
+ }
+
+ TIntermBinary *commaNode = TIntermBinary::CreateComma(left, right, mShaderVersion);
+ markStaticReadIfSymbol(left);
+ markStaticReadIfSymbol(right);
+ commaNode->setLine(loc);
+
+ return expressionOrFoldedResult(commaNode);
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
+{
+ switch (op)
+ {
+ case EOpContinue:
+ if (mLoopNestingLevel <= 0)
+ {
+ error(loc, "continue statement only allowed in loops", "");
+ }
+ break;
+ case EOpBreak:
+ if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
+ {
+ error(loc, "break statement only allowed in loops and switch statements", "");
+ }
+ break;
+ case EOpReturn:
+ if (mCurrentFunctionType->getBasicType() != EbtVoid)
+ {
+ error(loc, "non-void function must return a value", "return");
+ }
+ break;
+ case EOpKill:
+ if (mShaderType != GL_FRAGMENT_SHADER)
+ {
+ error(loc, "discard supported in fragment shaders only", "discard");
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return addBranch(op, nullptr, loc);
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op,
+ TIntermTyped *expression,
+ const TSourceLoc &loc)
+{
+ if (expression != nullptr)
+ {
+ markStaticReadIfSymbol(expression);
+ ASSERT(op == EOpReturn);
+ mFunctionReturnsValue = true;
+ if (mCurrentFunctionType->getBasicType() == EbtVoid)
+ {
+ error(loc, "void function cannot return a value", "return");
+ }
+ else if (*mCurrentFunctionType != expression->getType())
+ {
+ error(loc, "function return is not matching type:", "return");
+ }
+ }
+ TIntermBranch *node = new TIntermBranch(op, expression);
+ node->setLine(loc);
+ return node;
+}
+
+void TParseContext::appendStatement(TIntermBlock *block, TIntermNode *statement)
+{
+ if (statement != nullptr)
+ {
+ markStaticReadIfSymbol(statement);
+ block->appendStatement(statement);
+ }
+}
+
+void TParseContext::checkTextureGather(TIntermAggregate *functionCall)
+{
+ ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
+ const TFunction *func = functionCall->getFunction();
+ if (BuiltInGroup::isTextureGather(func))
+ {
+ bool isTextureGatherOffset = BuiltInGroup::isTextureGatherOffset(func);
+ TIntermNode *componentNode = nullptr;
+ TIntermSequence *arguments = functionCall->getSequence();
+ ASSERT(arguments->size() >= 2u && arguments->size() <= 4u);
+ const TIntermTyped *sampler = arguments->front()->getAsTyped();
+ ASSERT(sampler != nullptr);
+ switch (sampler->getBasicType())
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ if ((!isTextureGatherOffset && arguments->size() == 3u) ||
+ (isTextureGatherOffset && arguments->size() == 4u))
+ {
+ componentNode = arguments->back();
+ }
+ break;
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ ASSERT(!isTextureGatherOffset);
+ if (arguments->size() == 3u)
+ {
+ componentNode = arguments->back();
+ }
+ break;
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ case EbtSamplerCubeShadow:
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ if (componentNode)
+ {
+ const TIntermConstantUnion *componentConstantUnion =
+ componentNode->getAsConstantUnion();
+ if (componentNode->getAsTyped()->getQualifier() != EvqConst || !componentConstantUnion)
+ {
+ error(functionCall->getLine(), "Texture component must be a constant expression",
+ func->name());
+ }
+ else
+ {
+ int component = componentConstantUnion->getIConst(0);
+ if (component < 0 || component > 3)
+ {
+ error(functionCall->getLine(), "Component must be in the range [0;3]",
+ func->name());
+ }
+ }
+ }
+ }
+}
+
+void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
+{
+ ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
+ const TFunction *func = functionCall->getFunction();
+ TIntermNode *offset = nullptr;
+ TIntermSequence *arguments = functionCall->getSequence();
+ bool useTextureGatherOffsetConstraints = false;
+ if (BuiltInGroup::isTextureOffsetNoBias(func))
+ {
+ offset = arguments->back();
+ }
+ else if (BuiltInGroup::isTextureOffsetBias(func))
+ {
+ // A bias parameter follows the offset parameter.
+ ASSERT(arguments->size() >= 3);
+ offset = (*arguments)[2];
+ }
+ else if (BuiltInGroup::isTextureGatherOffset(func))
+ {
+ ASSERT(arguments->size() >= 3u);
+ const TIntermTyped *sampler = arguments->front()->getAsTyped();
+ ASSERT(sampler != nullptr);
+ switch (sampler->getBasicType())
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ offset = (*arguments)[2];
+ break;
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ offset = (*arguments)[3];
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ useTextureGatherOffsetConstraints = true;
+ }
+ if (offset != nullptr)
+ {
+ TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
+ if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
+ {
+ error(functionCall->getLine(), "Texture offset must be a constant expression",
+ func->name());
+ }
+ else
+ {
+ ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
+ size_t size = offsetConstantUnion->getType().getObjectSize();
+ const TConstantUnion *values = offsetConstantUnion->getConstantValue();
+ int minOffsetValue = useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset
+ : mMinProgramTexelOffset;
+ int maxOffsetValue = useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset
+ : mMaxProgramTexelOffset;
+ for (size_t i = 0u; i < size; ++i)
+ {
+ int offsetValue = values[i].getIConst();
+ if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue)
+ {
+ std::stringstream tokenStream = sh::InitializeStream<std::stringstream>();
+ tokenStream << offsetValue;
+ std::string token = tokenStream.str();
+ error(offset->getLine(), "Texture offset value out of valid range",
+ token.c_str());
+ }
+ }
+ }
+ }
+}
+
+void TParseContext::checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall)
+{
+ const TFunction *func = functionCall->getFunction();
+ if (BuiltInGroup::isAtomicMemory(func))
+ {
+ ASSERT(IsAtomicFunction(functionCall->getOp()));
+ TIntermSequence *arguments = functionCall->getSequence();
+ TIntermTyped *memNode = (*arguments)[0]->getAsTyped();
+
+ if (IsBufferOrSharedVariable(memNode))
+ {
+ return;
+ }
+
+ while (memNode->getAsBinaryNode())
+ {
+ memNode = memNode->getAsBinaryNode()->getLeft();
+ if (IsBufferOrSharedVariable(memNode))
+ {
+ return;
+ }
+ }
+
+ error(memNode->getLine(),
+ "The value passed to the mem argument of an atomic memory function does not "
+ "correspond to a buffer or shared variable.",
+ func->name());
+ }
+}
+
+// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
+void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall)
+{
+ ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
+
+ const TFunction *func = functionCall->getFunction();
+
+ if (BuiltInGroup::isImage(func))
+ {
+ TIntermSequence *arguments = functionCall->getSequence();
+ TIntermTyped *imageNode = (*arguments)[0]->getAsTyped();
+
+ const TMemoryQualifier &memoryQualifier = imageNode->getMemoryQualifier();
+
+ if (BuiltInGroup::isImageStore(func))
+ {
+ if (memoryQualifier.readonly)
+ {
+ error(imageNode->getLine(),
+ "'imageStore' cannot be used with images qualified as 'readonly'",
+ GetImageArgumentToken(imageNode));
+ }
+ }
+ else if (BuiltInGroup::isImageLoad(func))
+ {
+ if (memoryQualifier.writeonly)
+ {
+ error(imageNode->getLine(),
+ "'imageLoad' cannot be used with images qualified as 'writeonly'",
+ GetImageArgumentToken(imageNode));
+ }
+ }
+ }
+}
+
+// GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters
+void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
+ const TFunction *functionDefinition,
+ const TIntermAggregate *functionCall)
+{
+ ASSERT(functionCall->getOp() == EOpCallFunctionInAST);
+
+ const TIntermSequence &arguments = *functionCall->getSequence();
+
+ ASSERT(functionDefinition->getParamCount() == arguments.size());
+
+ for (size_t i = 0; i < arguments.size(); ++i)
+ {
+ TIntermTyped *typedArgument = arguments[i]->getAsTyped();
+ const TType &functionArgumentType = typedArgument->getType();
+ const TType &functionParameterType = functionDefinition->getParam(i)->getType();
+ ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType());
+
+ if (IsImage(functionArgumentType.getBasicType()))
+ {
+ const TMemoryQualifier &functionArgumentMemoryQualifier =
+ functionArgumentType.getMemoryQualifier();
+ const TMemoryQualifier &functionParameterMemoryQualifier =
+ functionParameterType.getMemoryQualifier();
+ if (functionArgumentMemoryQualifier.readonly &&
+ !functionParameterMemoryQualifier.readonly)
+ {
+ error(functionCall->getLine(),
+ "Function call discards the 'readonly' qualifier from image",
+ GetImageArgumentToken(typedArgument));
+ }
+
+ if (functionArgumentMemoryQualifier.writeonly &&
+ !functionParameterMemoryQualifier.writeonly)
+ {
+ error(functionCall->getLine(),
+ "Function call discards the 'writeonly' qualifier from image",
+ GetImageArgumentToken(typedArgument));
+ }
+
+ if (functionArgumentMemoryQualifier.coherent &&
+ !functionParameterMemoryQualifier.coherent)
+ {
+ error(functionCall->getLine(),
+ "Function call discards the 'coherent' qualifier from image",
+ GetImageArgumentToken(typedArgument));
+ }
+
+ if (functionArgumentMemoryQualifier.volatileQualifier &&
+ !functionParameterMemoryQualifier.volatileQualifier)
+ {
+ error(functionCall->getLine(),
+ "Function call discards the 'volatile' qualifier from image",
+ GetImageArgumentToken(typedArgument));
+ }
+ }
+ }
+}
+
+TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc)
+{
+ if (fnCall->thisNode() != nullptr)
+ {
+ return addMethod(fnCall, loc);
+ }
+ if (fnCall->isConstructor())
+ {
+ return addConstructor(fnCall, loc);
+ }
+ return addNonConstructorFunctionCall(fnCall, loc);
+}
+
+TIntermTyped *TParseContext::addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc)
+{
+ TIntermTyped *thisNode = fnCall->thisNode();
+ // It's possible for the name pointer in the TFunction to be null in case it gets parsed as
+ // a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS
+ // mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead.
+ // So accessing fnCall->name() below is safe.
+ if (fnCall->name() != "length")
+ {
+ error(loc, "invalid method", fnCall->name());
+ }
+ else if (!fnCall->arguments().empty())
+ {
+ error(loc, "method takes no parameters", "length");
+ }
+ else if (!thisNode->isArray())
+ {
+ error(loc, "length can only be called on arrays", "length");
+ }
+ else if (thisNode->getQualifier() == EvqPerVertexIn &&
+ mGeometryShaderInputPrimitiveType == EptUndefined)
+ {
+ ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT);
+ error(loc, "missing input primitive declaration before calling length on gl_in", "length");
+ }
+ else
+ {
+ TIntermUnary *node = new TIntermUnary(EOpArrayLength, thisNode, nullptr);
+ markStaticReadIfSymbol(thisNode);
+ node->setLine(loc);
+ return node->fold(mDiagnostics);
+ }
+ return CreateZeroNode(TType(EbtInt, EbpUndefined, EvqConst));
+}
+
+TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunctionLookup *fnCall,
+ const TSourceLoc &loc)
+{
+ // First check whether the function has been hidden by a variable name or struct typename by
+ // using the symbol looked up in the lexical phase. If the function is not hidden, look for one
+ // with a matching argument list.
+ if (fnCall->symbol() != nullptr && !fnCall->symbol()->isFunction())
+ {
+ error(loc, "function name expected", fnCall->name());
+ }
+ else
+ {
+ // There are no inner functions, so it's enough to look for user-defined functions in the
+ // global scope.
+ const TSymbol *symbol = symbolTable.findGlobal(fnCall->getMangledName());
+
+ if (symbol == nullptr && IsDesktopGLSpec(mShaderSpec))
+ {
+ // If using Desktop GL spec, need to check for implicit conversion
+ symbol = symbolTable.findGlobalWithConversion(
+ fnCall->getMangledNamesForImplicitConversions());
+ }
+
+ if (symbol != nullptr)
+ {
+ // A user-defined function - could be an overloaded built-in as well.
+ ASSERT(symbol->symbolType() == SymbolType::UserDefined);
+ const TFunction *fnCandidate = static_cast<const TFunction *>(symbol);
+ TIntermAggregate *callNode =
+ TIntermAggregate::CreateFunctionCall(*fnCandidate, &fnCall->arguments());
+ callNode->setLine(loc);
+ checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode);
+ functionCallRValueLValueErrorCheck(fnCandidate, callNode);
+ return callNode;
+ }
+
+ symbol = symbolTable.findBuiltIn(fnCall->getMangledName(), mShaderVersion);
+
+ if (symbol == nullptr && IsDesktopGLSpec(mShaderSpec))
+ {
+ // If using Desktop GL spec, need to check for implicit conversion
+ symbol = symbolTable.findBuiltInWithConversion(
+ fnCall->getMangledNamesForImplicitConversions(), mShaderVersion);
+ }
+
+ if (symbol != nullptr)
+ {
+ // A built-in function.
+ ASSERT(symbol->symbolType() == SymbolType::BuiltIn);
+ const TFunction *fnCandidate = static_cast<const TFunction *>(symbol);
+
+ if (fnCandidate->extension() != TExtension::UNDEFINED)
+ {
+ checkCanUseExtension(loc, fnCandidate->extension());
+ }
+ TOperator op = fnCandidate->getBuiltInOp();
+ if (op != EOpCallBuiltInFunction)
+ {
+ // A function call mapped to a built-in operation.
+ if (fnCandidate->getParamCount() == 1)
+ {
+ // Treat it like a built-in unary operator.
+ TIntermNode *unaryParamNode = fnCall->arguments().front();
+ TIntermTyped *callNode =
+ createUnaryMath(op, unaryParamNode->getAsTyped(), loc, fnCandidate);
+ ASSERT(callNode != nullptr);
+ return callNode;
+ }
+
+ TIntermAggregate *callNode =
+ TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments());
+ callNode->setLine(loc);
+
+ checkAtomicMemoryBuiltinFunctions(callNode);
+
+ // Some built-in functions have out parameters too.
+ functionCallRValueLValueErrorCheck(fnCandidate, callNode);
+
+ // See if we can constant fold a built-in. Note that this may be possible
+ // even if it is not const-qualified.
+ return callNode->fold(mDiagnostics);
+ }
+
+ // This is a built-in function with no op associated with it.
+ TIntermAggregate *callNode =
+ TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments());
+ callNode->setLine(loc);
+ checkTextureOffsetConst(callNode);
+ checkTextureGather(callNode);
+ checkImageMemoryAccessForBuiltinFunctions(callNode);
+ functionCallRValueLValueErrorCheck(fnCandidate, callNode);
+ return callNode;
+ }
+ else
+ {
+ error(loc, "no matching overloaded function found", fnCall->name());
+ }
+ }
+
+ // Error message was already written. Put on a dummy node for error recovery.
+ return CreateZeroNode(TType(EbtFloat, EbpMedium, EvqConst));
+}
+
+TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &loc)
+{
+ if (!checkIsScalarBool(loc, cond))
+ {
+ return falseExpression;
+ }
+
+ if (trueExpression->getType() != falseExpression->getType())
+ {
+ TInfoSinkBase reasonStream;
+ reasonStream << "mismatching ternary operator operand types '" << trueExpression->getType()
+ << " and '" << falseExpression->getType() << "'";
+ error(loc, reasonStream.c_str(), "?:");
+ return falseExpression;
+ }
+ if (IsOpaqueType(trueExpression->getBasicType()))
+ {
+ // ESSL 1.00 section 4.1.7
+ // ESSL 3.00.6 section 4.1.7
+ // Opaque/sampler types are not allowed in most types of expressions, including ternary.
+ // Note that structs containing opaque types don't need to be checked as structs are
+ // forbidden below.
+ error(loc, "ternary operator is not allowed for opaque types", "?:");
+ return falseExpression;
+ }
+
+ if (cond->getMemoryQualifier().writeonly || trueExpression->getMemoryQualifier().writeonly ||
+ falseExpression->getMemoryQualifier().writeonly)
+ {
+ error(loc, "ternary operator is not allowed for variables with writeonly", "?:");
+ return falseExpression;
+ }
+
+ // ESSL 1.00.17 sections 5.2 and 5.7:
+ // Ternary operator is not among the operators allowed for structures/arrays.
+ // ESSL 3.00.6 section 5.7:
+ // Ternary operator support is optional for arrays. No certainty that it works across all
+ // devices with struct either, so we err on the side of caution here. TODO (oetuaho@nvidia.com):
+ // Would be nice to make the spec and implementation agree completely here.
+ if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct)
+ {
+ error(loc, "ternary operator is not allowed for structures or arrays", "?:");
+ return falseExpression;
+ }
+ if (trueExpression->getBasicType() == EbtInterfaceBlock)
+ {
+ error(loc, "ternary operator is not allowed for interface blocks", "?:");
+ return falseExpression;
+ }
+
+ // WebGL2 section 5.26, the following results in an error:
+ // "Ternary operator applied to void, arrays, or structs containing arrays"
+ if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid)
+ {
+ error(loc, "ternary operator is not allowed for void", "?:");
+ return falseExpression;
+ }
+
+ TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
+ markStaticReadIfSymbol(cond);
+ markStaticReadIfSymbol(trueExpression);
+ markStaticReadIfSymbol(falseExpression);
+ node->setLine(loc);
+ return expressionOrFoldedResult(node);
+}
+
+//
+// Parse an array of strings using yyparse.
+//
+// Returns 0 for success.
+//
+int PaParseStrings(size_t count,
+ const char *const string[],
+ const int length[],
+ TParseContext *context)
+{
+ if ((count == 0) || (string == nullptr))
+ return 1;
+
+ if (glslang_initialize(context))
+ return 1;
+
+ int error = glslang_scan(count, string, length, context);
+ if (!error)
+ error = glslang_parse(context);
+
+ glslang_finalize(context);
+
+ return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ParseContext.h b/gfx/angle/checkout/src/compiler/translator/ParseContext.h
new file mode 100644
index 0000000000..22707d57aa
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ParseContext.h
@@ -0,0 +1,667 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_H_
+#define COMPILER_TRANSLATOR_PARSECONTEXT_H_
+
+#include "compiler/preprocessor/Preprocessor.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/Declarator.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/DirectiveHandler.h"
+#include "compiler/translator/FunctionLookup.h"
+#include "compiler/translator/QualifierTypes.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+struct TMatrixFields
+{
+ bool wholeRow;
+ bool wholeCol;
+ int row;
+ int col;
+};
+
+//
+// The following are extra variables needed during parsing, grouped together so
+// they can be passed to the parser without needing a global.
+//
+class TParseContext : angle::NonCopyable
+{
+ public:
+ TParseContext(TSymbolTable &symt,
+ TExtensionBehavior &ext,
+ sh::GLenum type,
+ ShShaderSpec spec,
+ ShCompileOptions options,
+ bool checksPrecErrors,
+ TDiagnostics *diagnostics,
+ const ShBuiltInResources &resources);
+ ~TParseContext();
+
+ bool anyMultiviewExtensionAvailable();
+ const angle::pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
+ angle::pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
+ void *getScanner() const { return mScanner; }
+ void setScanner(void *scanner) { mScanner = scanner; }
+ int getShaderVersion() const { return mShaderVersion; }
+ sh::GLenum getShaderType() const { return mShaderType; }
+ ShShaderSpec getShaderSpec() const { return mShaderSpec; }
+ int numErrors() const { return mDiagnostics->numErrors(); }
+ void error(const TSourceLoc &loc, const char *reason, const char *token);
+ void error(const TSourceLoc &loc, const char *reason, const ImmutableString &token);
+ void warning(const TSourceLoc &loc, const char *reason, const char *token);
+
+ // If isError is false, a warning will be reported instead.
+ void outOfRangeError(bool isError,
+ const TSourceLoc &loc,
+ const char *reason,
+ const char *token);
+
+ TIntermBlock *getTreeRoot() const { return mTreeRoot; }
+ void setTreeRoot(TIntermBlock *treeRoot) { mTreeRoot = treeRoot; }
+
+ bool getFragmentPrecisionHigh() const
+ {
+ return mFragmentPrecisionHighOnESSL1 || mShaderVersion >= 300;
+ }
+ void setFragmentPrecisionHighOnESSL1(bool fragmentPrecisionHigh)
+ {
+ mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh;
+ }
+
+ void setLoopNestingLevel(int loopNestintLevel) { mLoopNestingLevel = loopNestintLevel; }
+
+ void incrLoopNestingLevel() { ++mLoopNestingLevel; }
+ void decrLoopNestingLevel() { --mLoopNestingLevel; }
+
+ void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
+ void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
+
+ bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
+ sh::WorkGroupSize getComputeShaderLocalSize() const;
+
+ int getNumViews() const { return mNumViews; }
+
+ void enterFunctionDeclaration() { mDeclaringFunction = true; }
+
+ void exitFunctionDeclaration() { mDeclaringFunction = false; }
+
+ bool declaringFunction() const { return mDeclaringFunction; }
+
+ TIntermConstantUnion *addScalarLiteral(const TConstantUnion *constantUnion,
+ const TSourceLoc &line);
+
+ // This method is guaranteed to succeed, even if no variable with 'name' exists.
+ const TVariable *getNamedVariable(const TSourceLoc &location,
+ const ImmutableString &name,
+ const TSymbol *symbol);
+ TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
+ const ImmutableString &name,
+ const TSymbol *symbol);
+
+ // Look at a '.' field selector string and change it into offsets for a vector.
+ bool parseVectorFields(const TSourceLoc &line,
+ const ImmutableString &compString,
+ int vecSize,
+ TVector<int> *fieldOffsets);
+
+ void assignError(const TSourceLoc &line, const char *op, const TType &left, const TType &right);
+ void unaryOpError(const TSourceLoc &line, const char *op, const TType &operand);
+ void binaryOpError(const TSourceLoc &line,
+ const char *op,
+ const TType &left,
+ const TType &right);
+
+ // Check functions - the ones that return bool return false if an error was generated.
+
+ bool checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier);
+ void checkPrecisionSpecified(const TSourceLoc &line, TPrecision precision, TBasicType type);
+ bool checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node);
+ void checkIsConst(TIntermTyped *node);
+ void checkIsScalarInteger(TIntermTyped *node, const char *token);
+ bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token);
+ bool checkConstructorArguments(const TSourceLoc &line,
+ const TIntermSequence &arguments,
+ const TType &type);
+
+ // Returns a sanitized array size to use (the size is at least 1).
+ unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr);
+ bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier);
+ bool checkArrayElementIsNotArray(const TSourceLoc &line, const TPublicType &elementType);
+ bool checkIsNonVoid(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ const TBasicType &type);
+ bool checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
+ void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
+ bool checkIsNotOpaqueType(const TSourceLoc &line,
+ const TTypeSpecifierNonArray &pType,
+ const char *reason);
+ void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
+ void checkLocationIsNotSpecified(const TSourceLoc &location,
+ const TLayoutQualifier &layoutQualifier);
+ void checkStd430IsForShaderStorageBlock(const TSourceLoc &location,
+ const TLayoutBlockStorage &blockStorage,
+ const TQualifier &qualifier);
+ void checkIsParameterQualifierValid(const TSourceLoc &line,
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TType *type);
+
+ // Check if at least one of the specified extensions can be used, and generate error/warning as
+ // appropriate according to the spec.
+ // This function is only needed for a few different small constant sizes of extension array, and
+ // we want to avoid unnecessary dynamic allocations. That's why checkCanUseOneOfExtensions is a
+ // template function rather than one taking a vector.
+ template <size_t size>
+ bool checkCanUseOneOfExtensions(const TSourceLoc &line,
+ const std::array<TExtension, size> &extensions);
+ bool checkCanUseExtension(const TSourceLoc &line, TExtension extension);
+
+ // Done for all declarations, whether empty or not.
+ void declarationQualifierErrorCheck(const sh::TQualifier qualifier,
+ const sh::TLayoutQualifier &layoutQualifier,
+ const TSourceLoc &location);
+ // Done for the first non-empty declarator in a declaration.
+ void nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation);
+ // Done only for empty declarations.
+ void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location);
+
+ void checkLayoutQualifierSupported(const TSourceLoc &location,
+ const ImmutableString &layoutQualifierName,
+ int versionRequired);
+ bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
+ const TLayoutQualifier &layoutQualifier);
+ void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
+ void checkInvariantVariableQualifier(bool invariant,
+ const TQualifier qualifier,
+ const TSourceLoc &invariantLocation);
+ void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
+ const TPublicType &type,
+ const TSourceLoc &qualifierLocation);
+ void checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier);
+ const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
+ const TExtensionBehavior &extensionBehavior() const
+ {
+ return mDirectiveHandler.extensionBehavior();
+ }
+
+ bool isExtensionEnabled(TExtension extension) const;
+ void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior);
+ void handlePragmaDirective(const TSourceLoc &loc,
+ const char *name,
+ const char *value,
+ bool stdgl);
+
+ // Returns true on success. *initNode may still be nullptr on success in case the initialization
+ // is not needed in the AST.
+ bool executeInitializer(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ TType *type,
+ TIntermTyped *initializer,
+ TIntermBinary **initNode);
+ TIntermNode *addConditionInitializer(const TPublicType &pType,
+ const ImmutableString &identifier,
+ TIntermTyped *initializer,
+ const TSourceLoc &loc);
+ TIntermNode *addLoop(TLoopType type,
+ TIntermNode *init,
+ TIntermNode *cond,
+ TIntermTyped *expr,
+ TIntermNode *body,
+ const TSourceLoc &loc);
+
+ // For "if" test nodes. There are three children: a condition, a true path, and a false path.
+ // The two paths are in TIntermNodePair code.
+ TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &loc);
+
+ void addFullySpecifiedType(TPublicType *typeSpecifier);
+ TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TPublicType &typeSpecifier);
+
+ TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const ImmutableString &identifier);
+ TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &indexLocation,
+ const TVector<unsigned int> &arraySizes);
+ TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ // Parse a declaration like "type a[n] = initializer"
+ // Note that this does not apply to declarations like "type[n] a = initializer"
+ TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &indexLocation,
+ const TVector<unsigned int> &arraySizes,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ TIntermInvariantDeclaration *parseInvariantDeclaration(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &identifierLoc,
+ const ImmutableString &identifier,
+ const TSymbol *symbol);
+
+ void parseDeclarator(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ TIntermDeclaration *declarationOut);
+ void parseArrayDeclarator(TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &arrayLocation,
+ const TVector<unsigned int> &arraySizes,
+ TIntermDeclaration *declarationOut);
+ void parseInitDeclarator(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer,
+ TIntermDeclaration *declarationOut);
+
+ // Parse a declarator like "a[n] = initializer"
+ void parseArrayInitDeclarator(const TPublicType &elementType,
+ const TSourceLoc &identifierLocation,
+ const ImmutableString &identifier,
+ const TSourceLoc &indexLocation,
+ const TVector<unsigned int> &arraySizes,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer,
+ TIntermDeclaration *declarationOut);
+
+ TIntermNode *addEmptyStatement(const TSourceLoc &location);
+
+ void parseDefaultPrecisionQualifier(const TPrecision precision,
+ const TPublicType &type,
+ const TSourceLoc &loc);
+ void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
+
+ TIntermFunctionPrototype *addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
+ const TSourceLoc &location);
+ TIntermFunctionDefinition *addFunctionDefinition(TIntermFunctionPrototype *functionPrototype,
+ TIntermBlock *functionBody,
+ const TSourceLoc &location);
+ void parseFunctionDefinitionHeader(const TSourceLoc &location,
+ const TFunction *function,
+ TIntermFunctionPrototype **prototypeOut);
+ TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function);
+ TFunction *parseFunctionHeader(const TPublicType &type,
+ const ImmutableString &name,
+ const TSourceLoc &location);
+
+ TFunctionLookup *addNonConstructorFunc(const ImmutableString &name, const TSymbol *symbol);
+ TFunctionLookup *addConstructorFunc(const TPublicType &publicType);
+
+ TParameter parseParameterDeclarator(const TPublicType &publicType,
+ const ImmutableString &name,
+ const TSourceLoc &nameLoc);
+
+ TParameter parseParameterArrayDeclarator(const ImmutableString &name,
+ const TSourceLoc &nameLoc,
+ const TVector<unsigned int> &arraySizes,
+ const TSourceLoc &arrayLoc,
+ TPublicType *elementType);
+
+ TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &location,
+ TIntermTyped *indexExpression);
+ TIntermTyped *addFieldSelectionExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &dotLocation,
+ const ImmutableString &fieldString,
+ const TSourceLoc &fieldLocation);
+
+ // Parse declarator for a single field
+ TDeclarator *parseStructDeclarator(const ImmutableString &identifier, const TSourceLoc &loc);
+ TDeclarator *parseStructArrayDeclarator(const ImmutableString &identifier,
+ const TSourceLoc &loc,
+ const TVector<unsigned int> *arraySizes);
+
+ void checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
+ const TFieldList::const_iterator end,
+ const ImmutableString &name,
+ const TSourceLoc &location);
+ TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
+ TFieldList *combineStructFieldLists(TFieldList *processedFields,
+ const TFieldList *newlyAddedFields,
+ const TSourceLoc &location);
+ TFieldList *addStructDeclaratorListWithQualifiers(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TPublicType *typeSpecifier,
+ const TDeclaratorList *declaratorList);
+ TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier,
+ const TDeclaratorList *declaratorList);
+ TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const ImmutableString &structName,
+ TFieldList *fieldList);
+
+ TIntermDeclaration *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &nameLine,
+ const ImmutableString &blockName,
+ TFieldList *fieldList,
+ const ImmutableString &instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc &arrayIndexLine);
+
+ void parseLocalSize(const ImmutableString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ size_t index,
+ sh::WorkGroupSize *localSize);
+ void parseNumViews(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *numViews);
+ void parseInvocations(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *numInvocations);
+ void parseMaxVertices(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *numMaxVertices);
+ void parseIndexLayoutQualifier(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *index);
+ TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
+ const TSourceLoc &qualifierTypeLine);
+ TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ int intValue,
+ const TSourceLoc &intValueLine);
+ TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc);
+ TStorageQualifierWrapper *parseGlobalStorageQualifier(TQualifier qualifier,
+ const TSourceLoc &loc);
+ TStorageQualifierWrapper *parseVaryingQualifier(const TSourceLoc &loc);
+ TStorageQualifierWrapper *parseInQualifier(const TSourceLoc &loc);
+ TStorageQualifierWrapper *parseOutQualifier(const TSourceLoc &loc);
+ TStorageQualifierWrapper *parseInOutQualifier(const TSourceLoc &loc);
+ TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier,
+ const TSourceLoc &rightQualifierLocation);
+
+ // Performs an error check for embedded struct declarations.
+ void enterStructDeclaration(const TSourceLoc &line, const ImmutableString &identifier);
+ void exitStructDeclaration();
+
+ void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field);
+
+ TIntermSwitch *addSwitch(TIntermTyped *init,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc);
+ TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
+ TIntermCase *addDefault(const TSourceLoc &loc);
+
+ TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
+ TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
+ TIntermTyped *addBinaryMath(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc);
+ TIntermTyped *addBinaryMathBooleanResult(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc);
+ TIntermTyped *addAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc);
+
+ TIntermTyped *addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+
+ TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
+ TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc);
+
+ void appendStatement(TIntermBlock *block, TIntermNode *statement);
+
+ void checkTextureGather(TIntermAggregate *functionCall);
+ void checkTextureOffsetConst(TIntermAggregate *functionCall);
+ void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
+ void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
+ const TIntermAggregate *functionCall);
+ void checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall);
+
+ // fnCall is only storing the built-in op, and function name or constructor type. arguments
+ // has the arguments.
+ TIntermTyped *addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc);
+
+ TIntermTyped *addTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line);
+
+ int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
+ int getGeometryShaderInvocations() const
+ {
+ return (mGeometryShaderInvocations > 0) ? mGeometryShaderInvocations : 1;
+ }
+ TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const
+ {
+ return mGeometryShaderInputPrimitiveType;
+ }
+ TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const
+ {
+ return mGeometryShaderOutputPrimitiveType;
+ }
+
+ // TODO(jmadill): make this private
+ TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
+
+ private:
+ class AtomicCounterBindingState;
+ constexpr static size_t kAtomicCounterSize = 4;
+ // UNIFORM_ARRAY_STRIDE for atomic counter arrays is an implementation-dependent value which
+ // can be queried after a program is linked according to ES 3.10 section 7.7.1. This is
+ // controversial with the offset inheritance as described in ESSL 3.10 section 4.4.6. Currently
+ // we treat it as always 4 in favour of the original interpretation in
+ // "ARB_shader_atomic_counters".
+ // TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved.
+ // Note that there may be tests in AtomicCounter_test that will need to be updated as well.
+ constexpr static size_t kAtomicCounterArrayStride = 4;
+
+ void markStaticReadIfSymbol(TIntermNode *node);
+
+ // Returns a clamped index. If it prints out an error message, the token is "[]".
+ int checkIndexLessThan(bool outOfRangeIndexIsError,
+ const TSourceLoc &location,
+ int index,
+ int arraySize,
+ const char *reason);
+
+ bool declareVariable(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ const TType *type,
+ TVariable **variable);
+
+ void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
+ const ImmutableString &identifier,
+ TType *type);
+
+ TParameter parseParameterDeclarator(TType *type,
+ const ImmutableString &name,
+ const TSourceLoc &nameLoc);
+
+ bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
+ const TPublicType &elementType);
+ // Done for all atomic counter declarations, whether empty or not.
+ void atomicCounterQualifierErrorCheck(const TPublicType &publicType,
+ const TSourceLoc &location);
+
+ // Assumes that multiplication op has already been set based on the types.
+ bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right);
+
+ void checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
+ TQualifier qualifier,
+ const TType &type);
+
+ void checkInternalFormatIsNotSpecified(const TSourceLoc &location,
+ TLayoutImageInternalFormat internalFormat);
+ void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier,
+ const TSourceLoc &location);
+ void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
+ const TSourceLoc &loc,
+ TType *type);
+ void checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type);
+
+ void checkIndexIsNotSpecified(const TSourceLoc &location, int index);
+ void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type);
+ void checkBindingIsNotSpecified(const TSourceLoc &location, int binding);
+ void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset);
+ void checkImageBindingIsValid(const TSourceLoc &location,
+ int binding,
+ int arrayTotalElementCount);
+ void checkSamplerBindingIsValid(const TSourceLoc &location,
+ int binding,
+ int arrayTotalElementCount);
+ void checkBlockBindingIsValid(const TSourceLoc &location,
+ const TQualifier &qualifier,
+ int binding,
+ int arraySize);
+ void checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding);
+
+ void checkUniformLocationInRange(const TSourceLoc &location,
+ int objectLocationCount,
+ const TLayoutQualifier &layoutQualifier);
+
+ void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv);
+
+ bool checkUnsizedArrayConstructorArgumentDimensionality(const TIntermSequence &arguments,
+ TType type,
+ const TSourceLoc &line);
+
+ // Will set the size of the outermost array according to geometry shader input layout.
+ void checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location,
+ const ImmutableString &token,
+ TType *type);
+
+ // Will size any unsized array type so unsized arrays won't need to be taken into account
+ // further along the line in parsing.
+ void checkIsNotUnsizedArray(const TSourceLoc &line,
+ const char *errorMessage,
+ const ImmutableString &token,
+ TType *arrayType);
+
+ TIntermTyped *addBinaryMathInternal(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc);
+ TIntermTyped *createUnaryMath(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc,
+ const TFunction *func);
+
+ TIntermTyped *addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc);
+ TIntermTyped *addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line);
+ TIntermTyped *addNonConstructorFunctionCall(TFunctionLookup *fnCall, const TSourceLoc &loc);
+
+ // Return either the original expression or the folded version of the expression in case the
+ // folded node will validate the same way during subsequent parsing.
+ TIntermTyped *expressionOrFoldedResult(TIntermTyped *expression);
+
+ // Return true if the checks pass
+ bool binaryOpCommonCheck(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc);
+
+ TIntermFunctionPrototype *createPrototypeNodeFromFunction(const TFunction &function,
+ const TSourceLoc &location,
+ bool insertParametersToSymbolTable);
+
+ void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration,
+ const TSourceLoc &location);
+
+ bool checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier);
+ bool parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
+ bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
+ void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line);
+
+ // Set to true when the last/current declarator list was started with an empty declaration. The
+ // non-empty declaration error check will need to be performed if the empty declaration is
+ // followed by a declarator.
+ bool mDeferredNonEmptyDeclarationErrorCheck;
+
+ sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
+ ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
+ ShCompileOptions mCompileOptions; // Options passed to TCompiler
+ int mShaderVersion;
+ TIntermBlock *mTreeRoot; // root of parse tree being created
+ int mLoopNestingLevel; // 0 if outside all loops
+ int mStructNestingLevel; // incremented while parsing a struct declaration
+ int mSwitchNestingLevel; // 0 if outside all switch statements
+ const TType
+ *mCurrentFunctionType; // the return type of the function that's currently being parsed
+ bool mFunctionReturnsValue; // true if a non-void function has a return
+ bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared
+ // without precision, explicit or implicit.
+ bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling
+ // ESSL1.
+ TLayoutMatrixPacking mDefaultUniformMatrixPacking;
+ TLayoutBlockStorage mDefaultUniformBlockStorage;
+ TLayoutMatrixPacking mDefaultBufferMatrixPacking;
+ TLayoutBlockStorage mDefaultBufferBlockStorage;
+ TString mHashErrMsg;
+ TDiagnostics *mDiagnostics;
+ TDirectiveHandler mDirectiveHandler;
+ angle::pp::Preprocessor mPreprocessor;
+ void *mScanner;
+ int mMinProgramTexelOffset;
+ int mMaxProgramTexelOffset;
+
+ int mMinProgramTextureGatherOffset;
+ int mMaxProgramTextureGatherOffset;
+
+ // keep track of local group size declared in layout. It should be declared only once.
+ bool mComputeShaderLocalSizeDeclared;
+ sh::WorkGroupSize mComputeShaderLocalSize;
+ // keep track of number of views declared in layout.
+ int mNumViews;
+ int mMaxNumViews;
+ int mMaxImageUnits;
+ int mMaxCombinedTextureImageUnits;
+ int mMaxUniformLocations;
+ int mMaxUniformBufferBindings;
+ int mMaxAtomicCounterBindings;
+ int mMaxShaderStorageBufferBindings;
+
+ // keeps track whether we are declaring / defining a function
+ bool mDeclaringFunction;
+
+ // Track the state of each atomic counter binding.
+ std::map<int, AtomicCounterBindingState> mAtomicCounterBindingStates;
+
+ // Track the geometry shader global parameters declared in layout.
+ TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
+ TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
+ int mGeometryShaderInvocations;
+ int mGeometryShaderMaxVertices;
+ int mMaxGeometryShaderInvocations;
+ int mMaxGeometryShaderMaxVertices;
+
+ // Track when we add new scope for func body in ESSL 1.00 spec
+ bool mFunctionBodyNewScope;
+};
+
+int PaParseStrings(size_t count,
+ const char *const string[],
+ const int length[],
+ TParseContext *context);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h b/gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h
new file mode 100644
index 0000000000..8310be80b5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h
@@ -0,0 +1,66 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_builtin_symbols.py using data from builtin_variables.json and
+// builtin_function_declarations.txt.
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ParseContext_autogen.h:
+// Helpers for built-in related checks.
+
+#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_
+#define COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_
+
+namespace sh
+{
+
+namespace BuiltInGroup
+{
+
+bool isTextureOffsetNoBias(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 677 && id <= 746;
+}
+bool isTextureOffsetBias(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 747 && id <= 766;
+}
+bool isTextureGatherOffset(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 844 && id <= 857;
+}
+bool isTextureGather(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 820 && id <= 857;
+}
+bool isAtomicMemory(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 874 && id <= 891;
+}
+bool isImageLoad(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 916 && id <= 927;
+}
+bool isImageStore(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 928 && id <= 939;
+}
+bool isImage(const TFunction *func)
+{
+ int id = func->uniqueId().get();
+ return id >= 892 && id <= 939;
+}
+
+} // namespace BuiltInGroup
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp
new file mode 100644
index 0000000000..7a95658e7b
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/PoolAlloc.h"
+
+#include <assert.h>
+#include "common/tls.h"
+
+TLSIndex PoolIndex = TLS_INVALID_INDEX;
+
+bool InitializePoolIndex()
+{
+ assert(PoolIndex == TLS_INVALID_INDEX);
+
+ PoolIndex = CreateTLSIndex();
+ return PoolIndex != TLS_INVALID_INDEX;
+}
+
+void FreePoolIndex()
+{
+ assert(PoolIndex != TLS_INVALID_INDEX);
+
+ DestroyTLSIndex(PoolIndex);
+ PoolIndex = TLS_INVALID_INDEX;
+}
+
+angle::PoolAllocator *GetGlobalPoolAllocator()
+{
+ assert(PoolIndex != TLS_INVALID_INDEX);
+ return static_cast<angle::PoolAllocator *>(GetTLSValue(PoolIndex));
+}
+
+void SetGlobalPoolAllocator(angle::PoolAllocator *poolAllocator)
+{
+ assert(PoolIndex != TLS_INVALID_INDEX);
+ SetTLSValue(PoolIndex, poolAllocator);
+}
diff --git a/gfx/angle/checkout/src/compiler/translator/PoolAlloc.h b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.h
new file mode 100644
index 0000000000..86980b43a1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.h
@@ -0,0 +1,102 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_POOLALLOC_H_
+#define COMPILER_TRANSLATOR_POOLALLOC_H_
+
+//
+// This header defines the pool_allocator class that allows STL containers
+// to use the angle::PoolAllocator class by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+// It also defines functions for managing the GlobalPoolAllocator used by the compiler.
+//
+
+#include <stddef.h>
+#include <string.h>
+#include <vector>
+
+#include "common/PoolAlloc.h"
+
+//
+// There could potentially be many pools with pops happening at
+// different times. But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+extern angle::PoolAllocator *GetGlobalPoolAllocator();
+extern void SetGlobalPoolAllocator(angle::PoolAllocator *poolAllocator);
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template <class T>
+class pool_allocator
+{
+ public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T *pointer;
+ typedef const T *const_pointer;
+ typedef T &reference;
+ typedef const T &const_reference;
+ typedef T value_type;
+
+ template <class Other>
+ struct rebind
+ {
+ typedef pool_allocator<Other> other;
+ };
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pool_allocator() {}
+
+ template <class Other>
+ pool_allocator(const pool_allocator<Other> &p)
+ {}
+
+ template <class Other>
+ pool_allocator<T> &operator=(const pool_allocator<Other> &p)
+ {
+ return *this;
+ }
+
+#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
+ // libCStd on some platforms have a different allocate/deallocate interface.
+ // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
+ // allocated, not the number of elements.
+ void *allocate(size_type n) { return getAllocator().allocate(n); }
+ void *allocate(size_type n, const void *) { return getAllocator().allocate(n); }
+ void deallocate(void *, size_type) {}
+#else
+ pointer allocate(size_type n)
+ {
+ return static_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ pointer allocate(size_type n, const void *)
+ {
+ return static_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ void deallocate(pointer, size_type) {}
+#endif // _RWSTD_ALLOCATOR
+
+ void construct(pointer p, const T &val) { new ((void *)p) T(val); }
+ void destroy(pointer p) { p->T::~T(); }
+
+ bool operator==(const pool_allocator &rhs) const { return true; }
+ bool operator!=(const pool_allocator &rhs) const { return false; }
+
+ size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
+ size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
+
+ angle::PoolAllocator &getAllocator() const { return *GetGlobalPoolAllocator(); }
+};
+
+#endif // COMPILER_TRANSLATOR_POOLALLOC_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Pragma.h b/gfx/angle/checkout/src/compiler/translator/Pragma.h
new file mode 100644
index 0000000000..8c419fc17e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Pragma.h
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_PRAGMA_H_
+#define COMPILER_TRANSLATOR_PRAGMA_H_
+
+struct TPragma
+{
+ struct STDGL
+ {
+ STDGL() : invariantAll(false) {}
+
+ bool invariantAll;
+ };
+
+ // By default optimization is turned on and debug is turned off.
+ // Precision emulation is turned on by default, but has no effect unless
+ // the extension is enabled.
+ TPragma() : optimize(true), debug(false), debugShaderPrecision(true) {}
+ TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) {}
+
+ bool optimize;
+ bool debug;
+ bool debugShaderPrecision;
+ STDGL stdgl;
+};
+
+#endif // COMPILER_TRANSLATOR_PRAGMA_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp
new file mode 100644
index 0000000000..f9b4474b50
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp
@@ -0,0 +1,829 @@
+//
+// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/QualifierTypes.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+
+#include <algorithm>
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kSpecifiedMultipleTimes(" specified multiple times");
+constexpr const ImmutableString kInvariantMultipleTimes(
+ "The invariant qualifier specified multiple times.");
+constexpr const ImmutableString kPrecisionMultipleTimes(
+ "The precision qualifier specified multiple times.");
+constexpr const ImmutableString kLayoutMultipleTimes(
+ "The layout qualifier specified multiple times.");
+constexpr const ImmutableString kLayoutAndInvariantDisallowed(
+ "The layout qualifier and invariant qualifier cannot coexist in the same "
+ "declaration according to the grammar.");
+constexpr const ImmutableString kInterpolationMultipleTimes(
+ "The interpolation qualifier specified multiple times.");
+constexpr const ImmutableString kOutputLayoutMultipleTimes(
+ "Output layout location specified multiple times.");
+constexpr const ImmutableString kInvariantQualifierFirst(
+ "The invariant qualifier has to be first in the expression.");
+constexpr const ImmutableString kStorageAfterInterpolation(
+ "Storage qualifiers have to be after interpolation qualifiers.");
+constexpr const ImmutableString kPrecisionAfterInterpolation(
+ "Precision qualifiers have to be after interpolation qualifiers.");
+constexpr const ImmutableString kStorageAfterLayout(
+ "Storage qualifiers have to be after layout qualifiers.");
+constexpr const ImmutableString kPrecisionAfterLayout(
+ "Precision qualifiers have to be after layout qualifiers.");
+constexpr const ImmutableString kPrecisionAfterStorage(
+ "Precision qualifiers have to be after storage qualifiers.");
+constexpr const ImmutableString kPrecisionAfterMemory(
+ "Precision qualifiers have to be after memory qualifiers.");
+
+// GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout
+// declarations.
+// GLSL ES 3.10 Revision 4, 4.10 Order of Qualification
+bool AreTypeQualifierChecksRelaxed(int shaderVersion)
+{
+ return shaderVersion >= 310;
+}
+
+bool IsScopeQualifier(TQualifier qualifier)
+{
+ return qualifier == EvqGlobal || qualifier == EvqTemporary;
+}
+
+bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier)
+{
+ if (qualifier->getType() != QtStorage)
+ return false;
+ const TStorageQualifierWrapper *storageQualifier =
+ static_cast<const TStorageQualifierWrapper *>(qualifier);
+ TQualifier q = storageQualifier->getQualifier();
+ return IsScopeQualifier(q);
+}
+
+// Returns true if the invariant for the qualifier sequence holds
+bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers)
+{
+ // We should have at least one qualifier.
+ // The first qualifier always tells the scope.
+ return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]);
+}
+
+ImmutableString QualifierSpecifiedMultipleTimesErrorMessage(const ImmutableString &qualifierString)
+{
+ ImmutableStringBuilder errorMsg(qualifierString.length() + kSpecifiedMultipleTimes.length());
+ errorMsg << qualifierString << kSpecifiedMultipleTimes;
+ return errorMsg;
+}
+
+// Returns true if there are qualifiers which have been specified multiple times
+// If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed.
+bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
+ bool areQualifierChecksRelaxed,
+ ImmutableString *errorMessage)
+{
+ bool invariantFound = false;
+ bool precisionFound = false;
+ bool layoutFound = false;
+ bool interpolationFound = false;
+
+ unsigned int locationsSpecified = 0;
+ bool isOut = false;
+
+ // The iteration starts from one since the first qualifier only reveals the scope of the
+ // expression. It is inserted first whenever the sequence gets created.
+ for (size_t i = 1; i < qualifiers.size(); ++i)
+ {
+ switch (qualifiers[i]->getType())
+ {
+ case QtInvariant:
+ {
+ if (invariantFound)
+ {
+ *errorMessage = kInvariantMultipleTimes;
+ return true;
+ }
+ invariantFound = true;
+ break;
+ }
+ case QtPrecision:
+ {
+ if (precisionFound)
+ {
+ *errorMessage = kPrecisionMultipleTimes;
+ return true;
+ }
+ precisionFound = true;
+ break;
+ }
+ case QtLayout:
+ {
+ if (layoutFound && !areQualifierChecksRelaxed)
+ {
+ *errorMessage = kLayoutMultipleTimes;
+ return true;
+ }
+ if (invariantFound && !areQualifierChecksRelaxed)
+ {
+ // This combination is not correct according to the syntax specified in the
+ // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have
+ // a similar restriction.
+ *errorMessage = kLayoutAndInvariantDisallowed;
+ return true;
+ }
+ layoutFound = true;
+ const TLayoutQualifier &currentQualifier =
+ static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
+ locationsSpecified += currentQualifier.locationsSpecified;
+ break;
+ }
+ case QtInterpolation:
+ {
+ // 'centroid' is treated as a storage qualifier
+ // 'flat centroid' will be squashed to 'flat'
+ // 'smooth centroid' will be squashed to 'centroid'
+ if (interpolationFound)
+ {
+ *errorMessage = kInterpolationMultipleTimes;
+ return true;
+ }
+ interpolationFound = true;
+ break;
+ }
+ case QtStorage:
+ {
+ // Go over all of the storage qualifiers up until the current one and check for
+ // repetitions.
+ TQualifier currentQualifier =
+ static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
+ if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut)
+ {
+ isOut = true;
+ }
+ for (size_t j = 1; j < i; ++j)
+ {
+ if (qualifiers[j]->getType() == QtStorage)
+ {
+ const TStorageQualifierWrapper *previousQualifierWrapper =
+ static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
+ TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
+ if (currentQualifier == previousQualifier)
+ {
+ *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
+ previousQualifierWrapper->getQualifierString());
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case QtMemory:
+ {
+ // Go over all of the memory qualifiers up until the current one and check for
+ // repetitions.
+ // Having both readonly and writeonly in a sequence is valid.
+ // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
+ TQualifier currentQualifier =
+ static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
+ for (size_t j = 1; j < i; ++j)
+ {
+ if (qualifiers[j]->getType() == QtMemory)
+ {
+ const TMemoryQualifierWrapper *previousQualifierWrapper =
+ static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
+ TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
+ if (currentQualifier == previousQualifier)
+ {
+ *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
+ previousQualifierWrapper->getQualifierString());
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ if (locationsSpecified > 1 && isOut)
+ {
+ // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
+ // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
+ // "The qualifier may appear at most once within a declaration."
+ *errorMessage = kOutputLayoutMultipleTimes;
+ return true;
+ }
+
+ return false;
+}
+
+// GLSL ES 3.00_6, 4.7 Order of Qualification
+// The correct order of qualifiers is:
+// invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
+// layout-qualifier has to be before storage-qualifier.
+bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
+ ImmutableString *errorMessage)
+{
+ bool foundInterpolation = false;
+ bool foundStorage = false;
+ bool foundPrecision = false;
+ for (size_t i = 1; i < qualifiers.size(); ++i)
+ {
+ switch (qualifiers[i]->getType())
+ {
+ case QtInvariant:
+ if (foundInterpolation || foundStorage || foundPrecision)
+ {
+ *errorMessage = kInvariantQualifierFirst;
+ return false;
+ }
+ break;
+ case QtInterpolation:
+ if (foundStorage)
+ {
+ *errorMessage = kStorageAfterInterpolation;
+ return false;
+ }
+ else if (foundPrecision)
+ {
+ *errorMessage = kPrecisionAfterInterpolation;
+ return false;
+ }
+ foundInterpolation = true;
+ break;
+ case QtLayout:
+ if (foundStorage)
+ {
+ *errorMessage = kStorageAfterLayout;
+ return false;
+ }
+ else if (foundPrecision)
+ {
+ *errorMessage = kPrecisionAfterLayout;
+ return false;
+ }
+ break;
+ case QtStorage:
+ if (foundPrecision)
+ {
+ *errorMessage = kPrecisionAfterStorage;
+ return false;
+ }
+ foundStorage = true;
+ break;
+ case QtMemory:
+ if (foundPrecision)
+ {
+ *errorMessage = kPrecisionAfterMemory;
+ return false;
+ }
+ break;
+ case QtPrecision:
+ foundPrecision = true;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ return true;
+}
+
+struct QualifierComparator
+{
+ bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
+ {
+ return q1->getRank() < q2->getRank();
+ }
+};
+
+void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
+{
+ // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
+ // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
+ // and we always want it to be first.
+ std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
+}
+
+// Handles the joining of storage qualifiers for variables.
+bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
+{
+ switch (*joinedQualifier)
+ {
+ case EvqGlobal:
+ *joinedQualifier = storageQualifier;
+ break;
+ case EvqTemporary:
+ {
+ switch (storageQualifier)
+ {
+ case EvqConst:
+ *joinedQualifier = storageQualifier;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ case EvqSmooth:
+ {
+ switch (storageQualifier)
+ {
+ case EvqCentroid:
+ *joinedQualifier = EvqCentroid;
+ break;
+ case EvqVertexOut:
+ case EvqGeometryOut:
+ *joinedQualifier = EvqSmoothOut;
+ break;
+ case EvqFragmentIn:
+ case EvqGeometryIn:
+ *joinedQualifier = EvqSmoothIn;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ case EvqFlat:
+ {
+ switch (storageQualifier)
+ {
+ case EvqCentroid:
+ *joinedQualifier = EvqFlat;
+ break;
+ case EvqVertexOut:
+ case EvqGeometryOut:
+ *joinedQualifier = EvqFlatOut;
+ break;
+ case EvqFragmentIn:
+ case EvqGeometryIn:
+ *joinedQualifier = EvqFlatIn;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ case EvqCentroid:
+ {
+ switch (storageQualifier)
+ {
+ case EvqVertexOut:
+ case EvqGeometryOut:
+ *joinedQualifier = EvqCentroidOut;
+ break;
+ case EvqFragmentIn:
+ case EvqGeometryIn:
+ *joinedQualifier = EvqCentroidIn;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+// Handles the joining of storage qualifiers for a parameter in a function.
+bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
+{
+ switch (*joinedQualifier)
+ {
+ case EvqTemporary:
+ *joinedQualifier = storageQualifier;
+ break;
+ case EvqConst:
+ {
+ switch (storageQualifier)
+ {
+ case EvqIn:
+ *joinedQualifier = EvqConstReadOnly;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
+{
+ switch (memoryQualifier)
+ {
+ case EvqReadOnly:
+ joinedMemoryQualifier->readonly = true;
+ break;
+ case EvqWriteOnly:
+ joinedMemoryQualifier->writeonly = true;
+ break;
+ case EvqCoherent:
+ joinedMemoryQualifier->coherent = true;
+ break;
+ case EvqRestrict:
+ joinedMemoryQualifier->restrictQualifier = true;
+ break;
+ case EvqVolatile:
+ // Variables having the volatile qualifier are automatcally treated as coherent as well.
+ // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
+ joinedMemoryQualifier->volatileQualifier = true;
+ joinedMemoryQualifier->coherent = true;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return true;
+}
+
+TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
+ const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
+ TDiagnostics *diagnostics)
+{
+ TTypeQualifier typeQualifier(
+ static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
+ sortedSequence[0]->getLine());
+ for (size_t i = 1; i < sortedSequence.size(); ++i)
+ {
+ const TQualifierWrapperBase *qualifier = sortedSequence[i];
+ bool isQualifierValid = false;
+ switch (qualifier->getType())
+ {
+ case QtInvariant:
+ isQualifierValid = true;
+ typeQualifier.invariant = true;
+ break;
+ case QtInterpolation:
+ {
+ switch (typeQualifier.qualifier)
+ {
+ case EvqGlobal:
+ isQualifierValid = true;
+ typeQualifier.qualifier =
+ static_cast<const TInterpolationQualifierWrapper *>(qualifier)
+ ->getQualifier();
+ break;
+ default:
+ isQualifierValid = false;
+ }
+ break;
+ }
+ case QtLayout:
+ {
+ const TLayoutQualifierWrapper *layoutQualifierWrapper =
+ static_cast<const TLayoutQualifierWrapper *>(qualifier);
+ isQualifierValid = true;
+ typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
+ typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
+ layoutQualifierWrapper->getLine(), diagnostics);
+ break;
+ }
+ case QtStorage:
+ isQualifierValid = JoinVariableStorageQualifier(
+ &typeQualifier.qualifier,
+ static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
+ break;
+ case QtPrecision:
+ isQualifierValid = true;
+ typeQualifier.precision =
+ static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
+ ASSERT(typeQualifier.precision != EbpUndefined);
+ break;
+ case QtMemory:
+ isQualifierValid = JoinMemoryQualifier(
+ &typeQualifier.memoryQualifier,
+ static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ if (!isQualifierValid)
+ {
+ const ImmutableString &qualifierString = qualifier->getQualifierString();
+ diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
+ qualifierString.data());
+ break;
+ }
+ }
+ return typeQualifier;
+}
+
+TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
+ const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
+ TDiagnostics *diagnostics)
+{
+ TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
+ for (size_t i = 1; i < sortedSequence.size(); ++i)
+ {
+ const TQualifierWrapperBase *qualifier = sortedSequence[i];
+ bool isQualifierValid = false;
+ switch (qualifier->getType())
+ {
+ case QtInvariant:
+ case QtInterpolation:
+ case QtLayout:
+ break;
+ case QtMemory:
+ isQualifierValid = JoinMemoryQualifier(
+ &typeQualifier.memoryQualifier,
+ static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
+ break;
+ case QtStorage:
+ isQualifierValid = JoinParameterStorageQualifier(
+ &typeQualifier.qualifier,
+ static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
+ break;
+ case QtPrecision:
+ isQualifierValid = true;
+ typeQualifier.precision =
+ static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
+ ASSERT(typeQualifier.precision != EbpUndefined);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ if (!isQualifierValid)
+ {
+ const ImmutableString &qualifierString = qualifier->getQualifierString();
+ diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
+ qualifierString.data());
+ break;
+ }
+ }
+
+ switch (typeQualifier.qualifier)
+ {
+ case EvqIn:
+ case EvqConstReadOnly: // const in
+ case EvqOut:
+ case EvqInOut:
+ break;
+ case EvqConst:
+ typeQualifier.qualifier = EvqConstReadOnly;
+ break;
+ case EvqTemporary:
+ // no qualifier has been specified, set it to EvqIn which is the default
+ typeQualifier.qualifier = EvqIn;
+ break;
+ default:
+ diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
+ getQualifierString(typeQualifier.qualifier));
+ }
+ return typeQualifier;
+}
+} // namespace
+
+TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier,
+ const TSourceLoc &rightQualifierLocation,
+ TDiagnostics *diagnostics)
+{
+ TLayoutQualifier joinedQualifier = leftQualifier;
+
+ if (rightQualifier.location != -1)
+ {
+ joinedQualifier.location = rightQualifier.location;
+ ++joinedQualifier.locationsSpecified;
+ }
+ if (rightQualifier.yuv != false)
+ {
+ joinedQualifier.yuv = rightQualifier.yuv;
+ }
+ if (rightQualifier.binding != -1)
+ {
+ joinedQualifier.binding = rightQualifier.binding;
+ }
+ if (rightQualifier.offset != -1)
+ {
+ joinedQualifier.offset = rightQualifier.offset;
+ }
+ if (rightQualifier.matrixPacking != EmpUnspecified)
+ {
+ joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
+ }
+ if (rightQualifier.blockStorage != EbsUnspecified)
+ {
+ joinedQualifier.blockStorage = rightQualifier.blockStorage;
+ }
+
+ for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
+ {
+ if (rightQualifier.localSize[i] != -1)
+ {
+ if (joinedQualifier.localSize[i] != -1 &&
+ joinedQualifier.localSize[i] != rightQualifier.localSize[i])
+ {
+ diagnostics->error(rightQualifierLocation,
+ "Cannot have multiple different work group size specifiers",
+ getWorkGroupSizeString(i));
+ }
+ joinedQualifier.localSize[i] = rightQualifier.localSize[i];
+ }
+ }
+
+ if (rightQualifier.numViews != -1)
+ {
+ joinedQualifier.numViews = rightQualifier.numViews;
+ }
+
+ if (rightQualifier.imageInternalFormat != EiifUnspecified)
+ {
+ joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
+ }
+
+ if (rightQualifier.primitiveType != EptUndefined)
+ {
+ if (joinedQualifier.primitiveType != EptUndefined &&
+ joinedQualifier.primitiveType != rightQualifier.primitiveType)
+ {
+ diagnostics->error(rightQualifierLocation,
+ "Cannot have multiple different primitive specifiers",
+ getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
+ }
+ joinedQualifier.primitiveType = rightQualifier.primitiveType;
+ }
+
+ if (rightQualifier.invocations != 0)
+ {
+ if (joinedQualifier.invocations != 0 &&
+ joinedQualifier.invocations != rightQualifier.invocations)
+ {
+ diagnostics->error(rightQualifierLocation,
+ "Cannot have multiple different invocations specifiers",
+ "invocations");
+ }
+ joinedQualifier.invocations = rightQualifier.invocations;
+ }
+
+ if (rightQualifier.maxVertices != -1)
+ {
+ if (joinedQualifier.maxVertices != -1 &&
+ joinedQualifier.maxVertices != rightQualifier.maxVertices)
+ {
+ diagnostics->error(rightQualifierLocation,
+ "Cannot have multiple different max_vertices specifiers",
+ "max_vertices");
+ }
+ joinedQualifier.maxVertices = rightQualifier.maxVertices;
+ }
+
+ if (rightQualifier.index != -1)
+ {
+ if (joinedQualifier.index != -1)
+ {
+ // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
+ diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
+ "index");
+ }
+ joinedQualifier.index = rightQualifier.index;
+ }
+
+ return joinedQualifier;
+}
+
+unsigned int TInvariantQualifierWrapper::getRank() const
+{
+ return 0u;
+}
+
+unsigned int TInterpolationQualifierWrapper::getRank() const
+{
+ return 1u;
+}
+
+unsigned int TLayoutQualifierWrapper::getRank() const
+{
+ return 2u;
+}
+
+unsigned int TStorageQualifierWrapper::getRank() const
+{
+ // Force the 'centroid' auxilary storage qualifier to be always first among all storage
+ // qualifiers.
+ if (mStorageQualifier == EvqCentroid)
+ {
+ return 3u;
+ }
+ else
+ {
+ return 4u;
+ }
+}
+
+unsigned int TMemoryQualifierWrapper::getRank() const
+{
+ return 4u;
+}
+
+unsigned int TPrecisionQualifierWrapper::getRank() const
+{
+ return 5u;
+}
+
+TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
+ : layoutQualifier(TLayoutQualifier::Create()),
+ memoryQualifier(TMemoryQualifier::Create()),
+ precision(EbpUndefined),
+ qualifier(scope),
+ invariant(false),
+ line(loc)
+{
+ ASSERT(IsScopeQualifier(qualifier));
+}
+
+TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
+ int shaderVersion)
+ : mShaderVersion(shaderVersion)
+{
+ ASSERT(IsScopeQualifier(scope->getQualifier()));
+ mQualifiers.push_back(scope);
+}
+
+void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
+{
+ mQualifiers.push_back(qualifier);
+}
+
+bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
+{
+ bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
+ ImmutableString errorMessage("");
+ if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
+ {
+ diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
+ return false;
+ }
+
+ if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage))
+ {
+ diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
+ return false;
+ }
+
+ return true;
+}
+
+TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
+{
+ ASSERT(IsInvariantCorrect(mQualifiers));
+ ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
+ EvqTemporary);
+
+ if (!checkSequenceIsValid(diagnostics))
+ {
+ return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
+ }
+
+ // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
+ // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
+ // combine the qualifiers.
+ if (AreTypeQualifierChecksRelaxed(mShaderVersion))
+ {
+ // Copy the qualifier sequence so that we can sort them.
+ QualifierSequence sortedQualifierSequence = mQualifiers;
+ SortSequence(sortedQualifierSequence);
+ return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
+ }
+ return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
+}
+
+TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
+{
+ ASSERT(IsInvariantCorrect(mQualifiers));
+
+ if (!checkSequenceIsValid(diagnostics))
+ {
+ return TTypeQualifier(
+ static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
+ mQualifiers[0]->getLine());
+ }
+
+ // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
+ // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
+ // combine the qualifiers.
+ if (AreTypeQualifierChecksRelaxed(mShaderVersion))
+ {
+ // Copy the qualifier sequence so that we can sort them.
+ QualifierSequence sortedQualifierSequence = mQualifiers;
+ SortSequence(sortedQualifierSequence);
+ return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
+ }
+ return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/QualifierTypes.h b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.h
new file mode 100644
index 0000000000..950ba5f93e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.h
@@ -0,0 +1,200 @@
+//
+// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_
+#define COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_
+
+#include "common/angleutils.h"
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/Types.h"
+
+namespace sh
+{
+class TDiagnostics;
+
+TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier,
+ const TSourceLoc &rightQualifierLocation,
+ TDiagnostics *diagnostics);
+
+enum TQualifierType
+{
+ QtInvariant,
+ QtInterpolation,
+ QtLayout,
+ QtStorage,
+ QtPrecision,
+ QtMemory
+};
+
+class TQualifierWrapperBase : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TQualifierWrapperBase(const TSourceLoc &line) : mLine(line) {}
+ virtual ~TQualifierWrapperBase() {}
+ virtual TQualifierType getType() const = 0;
+ virtual ImmutableString getQualifierString() const = 0;
+ virtual unsigned int getRank() const = 0;
+ const TSourceLoc &getLine() const { return mLine; }
+
+ private:
+ TSourceLoc mLine;
+};
+
+class TInvariantQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TInvariantQualifierWrapper(const TSourceLoc &line) : TQualifierWrapperBase(line) {}
+ ~TInvariantQualifierWrapper() {}
+
+ TQualifierType getType() const override { return QtInvariant; }
+ ImmutableString getQualifierString() const override { return ImmutableString("invariant"); }
+ unsigned int getRank() const override;
+};
+
+class TInterpolationQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TInterpolationQualifierWrapper(TQualifier interpolationQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mInterpolationQualifier(interpolationQualifier)
+ {}
+ ~TInterpolationQualifierWrapper() {}
+
+ TQualifierType getType() const override { return QtInterpolation; }
+ ImmutableString getQualifierString() const override
+ {
+ return ImmutableString(sh::getQualifierString(mInterpolationQualifier));
+ }
+ TQualifier getQualifier() const { return mInterpolationQualifier; }
+ unsigned int getRank() const override;
+
+ private:
+ TQualifier mInterpolationQualifier;
+};
+
+class TLayoutQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TLayoutQualifierWrapper(TLayoutQualifier layoutQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mLayoutQualifier(layoutQualifier)
+ {}
+ ~TLayoutQualifierWrapper() {}
+
+ TQualifierType getType() const override { return QtLayout; }
+ ImmutableString getQualifierString() const override { return ImmutableString("layout"); }
+ const TLayoutQualifier &getQualifier() const { return mLayoutQualifier; }
+ unsigned int getRank() const override;
+
+ private:
+ TLayoutQualifier mLayoutQualifier;
+};
+
+class TStorageQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TStorageQualifierWrapper(TQualifier storageQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mStorageQualifier(storageQualifier)
+ {}
+ ~TStorageQualifierWrapper() {}
+
+ TQualifierType getType() const override { return QtStorage; }
+ ImmutableString getQualifierString() const override
+ {
+ return ImmutableString(sh::getQualifierString(mStorageQualifier));
+ }
+ TQualifier getQualifier() const { return mStorageQualifier; }
+ unsigned int getRank() const override;
+
+ private:
+ TQualifier mStorageQualifier;
+};
+
+class TPrecisionQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TPrecisionQualifierWrapper(TPrecision precisionQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mPrecisionQualifier(precisionQualifier)
+ {}
+ ~TPrecisionQualifierWrapper() {}
+
+ TQualifierType getType() const override { return QtPrecision; }
+ ImmutableString getQualifierString() const override
+ {
+ return ImmutableString(sh::getPrecisionString(mPrecisionQualifier));
+ }
+ TPrecision getQualifier() const { return mPrecisionQualifier; }
+ unsigned int getRank() const override;
+
+ private:
+ TPrecision mPrecisionQualifier;
+};
+
+class TMemoryQualifierWrapper final : public TQualifierWrapperBase
+{
+ public:
+ TMemoryQualifierWrapper(TQualifier memoryQualifier, const TSourceLoc &line)
+ : TQualifierWrapperBase(line), mMemoryQualifier(memoryQualifier)
+ {}
+ ~TMemoryQualifierWrapper() {}
+
+ TQualifierType getType() const override { return QtMemory; }
+ ImmutableString getQualifierString() const override
+ {
+ return ImmutableString(sh::getQualifierString(mMemoryQualifier));
+ }
+ TQualifier getQualifier() const { return mMemoryQualifier; }
+ unsigned int getRank() const override;
+
+ private:
+ TQualifier mMemoryQualifier;
+};
+
+// TTypeQualifier tightly covers type_qualifier from the grammar
+struct TTypeQualifier
+{
+ // initializes all of the qualifiers and sets the scope
+ TTypeQualifier(TQualifier scope, const TSourceLoc &loc);
+
+ TLayoutQualifier layoutQualifier;
+ TMemoryQualifier memoryQualifier;
+ TPrecision precision;
+ TQualifier qualifier;
+ bool invariant;
+ TSourceLoc line;
+};
+
+// TTypeQualifierBuilder contains all of the qualifiers when type_qualifier gets parsed.
+// It is to be used to validate the qualifier sequence and build a TTypeQualifier from it.
+class TTypeQualifierBuilder : angle::NonCopyable
+{
+ public:
+ using QualifierSequence = TVector<const TQualifierWrapperBase *>;
+
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, int shaderVersion);
+ // Adds the passed qualifier to the end of the sequence.
+ void appendQualifier(const TQualifierWrapperBase *qualifier);
+ // Checks for the order of qualification and repeating qualifiers.
+ bool checkSequenceIsValid(TDiagnostics *diagnostics) const;
+ // Goes over the qualifier sequence and parses it to form a type qualifier for a function
+ // parameter.
+ // The returned object is initialized even if the parsing fails.
+ TTypeQualifier getParameterTypeQualifier(TDiagnostics *diagnostics) const;
+ // Goes over the qualifier sequence and parses it to form a type qualifier for a variable.
+ // The returned object is initialized even if the parsing fails.
+ TTypeQualifier getVariableTypeQualifier(TDiagnostics *diagnostics) const;
+
+ private:
+ QualifierSequence mQualifiers;
+ int mShaderVersion;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp
new file mode 100644
index 0000000000..4b600a9ae2
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp
@@ -0,0 +1,790 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ResourcesHLSL.cpp:
+// Methods for GLSL to HLSL translation for uniforms and interface blocks.
+//
+
+#include "compiler/translator/ResourcesHLSL.h"
+
+#include "common/utilities.h"
+#include "compiler/translator/AtomicCounterFunctionHLSL.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/StructureHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kAngleDecorString("angle_");
+
+static const char *UniformRegisterPrefix(const TType &type)
+{
+ if (IsSampler(type.getBasicType()))
+ {
+ return "s";
+ }
+ else
+ {
+ return "c";
+ }
+}
+
+static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
+{
+ const TType &fieldType = *field.type();
+ const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
+ ASSERT(matrixPacking != EmpUnspecified);
+ const TStructure *structure = fieldType.getStruct();
+
+ if (fieldType.isMatrix())
+ {
+ // Use HLSL row-major packing for GLSL column-major matrices
+ const TString &matrixPackString =
+ (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
+ return matrixPackString + " " + TypeString(fieldType);
+ }
+ else if (structure)
+ {
+ // Use HLSL row-major packing for GLSL column-major matrices
+ return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
+ blockStorage == EbsStd140);
+ }
+ else
+ {
+ return TypeString(fieldType);
+ }
+}
+
+static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
+{
+ return DecoratePrivate(interfaceBlock.name()) + "_type";
+}
+
+void OutputUniformIndexArrayInitializer(TInfoSinkBase &out,
+ const TType &type,
+ unsigned int startIndex)
+{
+ out << "{";
+ TType elementType(type);
+ elementType.toArrayElementType();
+ for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
+ {
+ if (i > 0u)
+ {
+ out << ", ";
+ }
+ if (elementType.isArray())
+ {
+ OutputUniformIndexArrayInitializer(out, elementType,
+ startIndex + i * elementType.getArraySizeProduct());
+ }
+ else
+ {
+ out << (startIndex + i);
+ }
+ }
+ out << "}";
+}
+
+} // anonymous namespace
+
+ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
+ ShShaderOutput outputType,
+ const std::vector<Uniform> &uniforms,
+ unsigned int firstUniformRegister)
+ : mUniformRegister(firstUniformRegister),
+ mUniformBlockRegister(0),
+ mTextureRegister(0),
+ mUAVRegister(0),
+ mSamplerCount(0),
+ mStructureHLSL(structureHLSL),
+ mOutputType(outputType),
+ mUniforms(uniforms)
+{}
+
+void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount)
+{
+ mUniformRegister = registerCount;
+}
+
+void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount)
+{
+ mUniformBlockRegister = registerCount;
+}
+
+const Uniform *ResourcesHLSL::findUniformByName(const ImmutableString &name) const
+{
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
+ {
+ if (name == mUniforms[uniformIndex].name)
+ {
+ return &mUniforms[uniformIndex];
+ }
+ }
+
+ return nullptr;
+}
+
+unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
+ const ImmutableString &name,
+ unsigned int *outRegisterCount)
+{
+ unsigned int registerIndex;
+ const Uniform *uniform = findUniformByName(name);
+ ASSERT(uniform);
+
+ if (IsSampler(type.getBasicType()) ||
+ (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
+ {
+ registerIndex = mTextureRegister;
+ }
+ else if (IsImage(type.getBasicType()))
+ {
+ registerIndex = mUAVRegister;
+ }
+ else
+ {
+ registerIndex = mUniformRegister;
+ }
+
+ if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID")
+ {
+ mUniformRegisterMap["gl_DrawID"] = registerIndex;
+ }
+ else
+ {
+ mUniformRegisterMap[uniform->name] = registerIndex;
+ }
+
+ unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
+
+ if (IsSampler(type.getBasicType()) ||
+ (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
+ {
+ mTextureRegister += registerCount;
+ }
+ else if (IsImage(type.getBasicType()))
+ {
+ mUAVRegister += registerCount;
+ }
+ else
+ {
+ mUniformRegister += registerCount;
+ }
+ if (outRegisterCount)
+ {
+ *outRegisterCount = registerCount;
+ }
+ return registerIndex;
+}
+
+unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type,
+ const TString &name,
+ unsigned int *outRegisterCount)
+{
+ // Sampler that is a field of a uniform structure.
+ ASSERT(IsSampler(type.getBasicType()));
+ unsigned int registerIndex = mTextureRegister;
+ mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
+ unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
+ mTextureRegister += registerCount;
+ if (outRegisterCount)
+ {
+ *outRegisterCount = registerCount;
+ }
+ return registerIndex;
+}
+
+void ResourcesHLSL::outputHLSLSamplerUniformGroup(
+ TInfoSinkBase &out,
+ const HLSLTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+ unsigned int groupRegisterCount = 0;
+ for (const TVariable *uniform : group)
+ {
+ const TType &type = uniform->getType();
+ const ImmutableString &name = uniform->name();
+ unsigned int registerCount;
+
+ // The uniform might be just a regular sampler or one extracted from a struct.
+ unsigned int samplerArrayIndex = 0u;
+ const Uniform *uniformByName = findUniformByName(name);
+ if (uniformByName)
+ {
+ samplerArrayIndex = assignUniformRegister(type, name, &registerCount);
+ }
+ else
+ {
+ ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
+ samplerInStructSymbolsToAPINames.end());
+ samplerArrayIndex = assignSamplerInStructUniformRegister(
+ type, samplerInStructSymbolsToAPINames.at(uniform), &registerCount);
+ }
+ groupRegisterCount += registerCount;
+
+ if (type.isArray())
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
+ << " = ";
+ OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex);
+ out << ";\n";
+ }
+ else
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
+ << samplerArrayIndex << ";\n";
+ }
+ }
+ TString suffix = TextureGroupSuffix(textureGroup);
+ // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
+ if (textureGroup != HLSL_TEXTURE_2D)
+ {
+ out << "static const uint textureIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ out << "static const uint samplerIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ }
+ out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
+ out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
+
+void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
+ const TVector<const TVariable *> &group,
+ unsigned int imageArrayIndex,
+ unsigned int *groupRegisterCount)
+{
+ for (const TVariable *uniform : group)
+ {
+ const TType &type = uniform->getType();
+ const ImmutableString &name = uniform->name();
+ unsigned int registerCount = 0;
+
+ assignUniformRegister(type, name, &registerCount);
+ *groupRegisterCount += registerCount;
+
+ if (type.isArray())
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
+ << " = ";
+ OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
+ out << ";\n";
+ }
+ else
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
+ << imageArrayIndex << ";\n";
+ }
+
+ imageArrayIndex += registerCount;
+ }
+}
+
+void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
+ const HLSLTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+
+ unsigned int groupRegisterCount = 0;
+ outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
+
+ TString suffix = TextureGroupSuffix(textureGroup);
+ out << "static const uint readonlyImageIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
+
+void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
+ const HLSLRWTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+
+ unsigned int groupRegisterCount = 0;
+ outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
+
+ TString suffix = RWTextureGroupSuffix(textureGroup);
+ out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
+ << ";\n";
+ out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
+
+void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
+ const TType &type,
+ const TVariable &variable,
+ const unsigned int registerIndex)
+{
+ out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
+ << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s"
+ << str(registerIndex) << ");\n";
+ out << "uniform " << TextureString(type.getBasicType()) << " texture_"
+ << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t"
+ << str(registerIndex) << ");\n";
+}
+
+void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
+ const TType &type,
+ const TVariable &variable,
+ const unsigned int registerIndex)
+{
+ const TStructure *structure = type.getStruct();
+ // If this is a nameless struct, we need to use its full definition, rather than its (empty)
+ // name.
+ // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
+ // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
+ // are permitted.
+ const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
+ ? QualifiedStructNameString(*structure, false, false)
+ : TypeString(type));
+
+ const TString &registerString =
+ TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
+
+ out << "uniform " << typeName << " ";
+
+ out << DecorateVariableIfNeeded(variable);
+
+ out << ArrayString(type) << " : " << registerString << ";\n";
+}
+
+void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
+ const int binding,
+ const unsigned int registerIndex)
+{
+ // Atomic counter memory access is not incoherent
+ out << "uniform globallycoherent RWByteAddressBuffer "
+ << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
+}
+
+void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedVariables &referencedUniforms,
+ TSymbolTable *symbolTable)
+{
+ if (!referencedUniforms.empty())
+ {
+ out << "// Uniforms\n\n";
+ }
+ // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
+ // written. They are grouped based on the combination of the HLSL texture type and
+ // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
+ TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
+ TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
+ TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
+ TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
+
+ TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
+ unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
+ for (auto &uniformIt : referencedUniforms)
+ {
+ // Output regular uniforms. Group sampler uniforms by type.
+ const TVariable &variable = *uniformIt.second;
+ const TType &type = variable.getType();
+
+ if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ HLSLTextureGroup group = TextureGroup(type.getBasicType());
+ groupedSamplerUniforms[group].push_back(&variable);
+ }
+ else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
+ outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex);
+ }
+ else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
+ {
+ if (IsImage2D(type.getBasicType()))
+ {
+ const Uniform *uniform = findUniformByName(variable.name());
+ if (type.getMemoryQualifier().readonly)
+ {
+ reservedReadonlyImageRegisterCount +=
+ HLSLVariableRegisterCount(*uniform, mOutputType);
+ }
+ else
+ {
+ reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
+ }
+ continue;
+ }
+ if (type.getMemoryQualifier().readonly)
+ {
+ HLSLTextureGroup group = TextureGroup(
+ type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
+ groupedReadonlyImageUniforms[group].push_back(&variable);
+ }
+ else
+ {
+ HLSLRWTextureGroup group = RWTextureGroup(
+ type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
+ groupedImageUniforms[group].push_back(&variable);
+ }
+ }
+ else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
+ {
+ TLayoutQualifier layout = type.getLayoutQualifier();
+ int binding = layout.binding;
+ unsigned int registerIndex;
+ if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
+ {
+ registerIndex = mUAVRegister++;
+ assignedAtomicCounterBindings[binding] = registerIndex;
+ outputAtomicCounterBuffer(out, binding, registerIndex);
+ }
+ else
+ {
+ registerIndex = assignedAtomicCounterBindings[binding];
+ }
+ const Uniform *uniform = findUniformByName(variable.name());
+ mUniformRegisterMap[uniform->name] = registerIndex;
+ }
+ else
+ {
+ if (type.isStructureContainingSamplers())
+ {
+ TVector<const TVariable *> samplerSymbols;
+ TMap<const TVariable *, TString> symbolsToAPINames;
+ ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
+ variable.name().length());
+ namePrefix << kAngleDecorString;
+ namePrefix << variable.name();
+ type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
+ &samplerSymbols, &symbolsToAPINames, symbolTable);
+ for (const TVariable *sampler : samplerSymbols)
+ {
+ const TType &samplerType = sampler->getType();
+
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
+ groupedSamplerUniforms[group].push_back(sampler);
+ samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
+ }
+ else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ unsigned int registerIndex = assignSamplerInStructUniformRegister(
+ samplerType, symbolsToAPINames[sampler], nullptr);
+ outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex);
+ }
+ else
+ {
+ ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
+ unsigned int registerIndex = assignSamplerInStructUniformRegister(
+ samplerType, symbolsToAPINames[sampler], nullptr);
+ outputUniform(out, samplerType, *sampler, registerIndex);
+ }
+ }
+ }
+ unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
+ outputUniform(out, type, variable, registerIndex);
+ }
+ }
+
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ unsigned int groupTextureRegisterIndex = 0;
+ // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
+ // start counting after the last atomic counter.
+ unsigned int groupRWTextureRegisterIndex = mUAVRegister;
+ // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
+ ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
+ for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
+ {
+ outputHLSLSamplerUniformGroup(
+ out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
+ samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
+ }
+ mSamplerCount = groupTextureRegisterIndex;
+
+ // Reserve t type register for readonly image2D variables.
+ mReadonlyImage2DRegisterIndex = mTextureRegister;
+ groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
+ mTextureRegister += reservedReadonlyImageRegisterCount;
+
+ for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
+ {
+ outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
+ groupedReadonlyImageUniforms[groupId],
+ &groupTextureRegisterIndex);
+ }
+ mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
+ if (mReadonlyImageCount)
+ {
+ out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
+ << ";\n";
+ }
+
+ // Reserve u type register for writable image2D variables.
+ mImage2DRegisterIndex = mUAVRegister;
+ groupRWTextureRegisterIndex += reservedImageRegisterCount;
+ mUAVRegister += reservedImageRegisterCount;
+
+ for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
+ {
+ outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
+ groupedImageUniforms[groupId],
+ &groupRWTextureRegisterIndex);
+ }
+ mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
+ if (mImageCount)
+ {
+ out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
+ }
+ }
+}
+
+void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
+{
+ // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
+ if (mSamplerCount > 0)
+ {
+ out << " struct SamplerMetadata\n"
+ " {\n"
+ " int baseLevel;\n"
+ " int internalFormatBits;\n"
+ " int wrapModes;\n"
+ " int padding;\n"
+ " int4 intBorderColor;\n"
+ " };\n"
+ " SamplerMetadata samplerMetadata["
+ << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
+ }
+}
+
+void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
+{
+ if (mReadonlyImageCount > 0 || mImageCount > 0)
+ {
+ out << " struct ImageMetadata\n"
+ " {\n"
+ " int layer;\n"
+ " uint level;\n"
+ " int2 padding;\n"
+ " };\n";
+
+ if (mReadonlyImageCount > 0)
+ {
+ out << " ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
+ << "] : packoffset(c" << regIndex << ");\n";
+ }
+
+ if (mImageCount > 0)
+ {
+ out << " ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
+ << regIndex + mReadonlyImageCount << ");\n";
+ }
+ }
+}
+
+TString ResourcesHLSL::uniformBlocksHeader(
+ const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
+{
+ TString interfaceBlocks;
+
+ for (const auto &blockReference : referencedInterfaceBlocks)
+ {
+ const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
+ const TVariable *instanceVariable = blockReference.second->instanceVariable;
+ if (instanceVariable != nullptr)
+ {
+ interfaceBlocks += uniformBlockStructString(interfaceBlock);
+ }
+
+ unsigned int activeRegister = mUniformBlockRegister;
+ mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
+
+ if (instanceVariable != nullptr && instanceVariable->getType().isArray())
+ {
+ unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
+ for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
+ {
+ interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable,
+ activeRegister + arrayIndex, arrayIndex);
+ }
+ mUniformBlockRegister += instanceArraySize;
+ }
+ else
+ {
+ interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
+ GL_INVALID_INDEX);
+ mUniformBlockRegister += 1u;
+ }
+ }
+
+ return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
+}
+
+TString ResourcesHLSL::shaderStorageBlocksHeader(
+ const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
+{
+ TString interfaceBlocks;
+
+ for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
+ {
+ const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
+ const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable;
+
+ unsigned int activeRegister = mUAVRegister;
+ mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
+
+ if (instanceVariable != nullptr && instanceVariable->getType().isArray())
+ {
+ unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
+ for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
+ {
+ interfaceBlocks += shaderStorageBlockString(
+ interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
+ }
+ mUAVRegister += instanceArraySize;
+ }
+ else
+ {
+ interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
+ activeRegister, GL_INVALID_INDEX);
+ mUAVRegister += 1u;
+ }
+ }
+
+ return (interfaceBlocks.empty() ? "" : ("// Shader Storage Blocks\n\n" + interfaceBlocks));
+}
+
+TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
+ const TVariable *instanceVariable,
+ unsigned int registerIndex,
+ unsigned int arrayIndex)
+{
+ const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
+ const TString &blockName = TString(interfaceBlock.name().data()) + arrayIndexString;
+ TString hlsl;
+
+ hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
+ ")\n"
+ "{\n";
+
+ if (instanceVariable != nullptr)
+ {
+ hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
+ InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
+ }
+ else
+ {
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+ hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
+ }
+
+ hlsl += "};\n\n";
+
+ return hlsl;
+}
+
+TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
+ const TVariable *instanceVariable,
+ unsigned int registerIndex,
+ unsigned int arrayIndex)
+{
+ TString hlsl;
+ if (instanceVariable != nullptr)
+ {
+ hlsl += "RWByteAddressBuffer " +
+ InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
+ ": register(u" + str(registerIndex) + ");\n";
+ }
+ else
+ {
+ hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
+ str(registerIndex) + ");\n";
+ }
+ return hlsl;
+}
+
+TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
+ unsigned int arrayIndex)
+{
+ if (arrayIndex != GL_INVALID_INDEX)
+ {
+ return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
+ }
+ else
+ {
+ return Decorate(instanceName);
+ }
+}
+
+TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
+ TLayoutBlockStorage blockStorage)
+{
+ TString hlsl;
+
+ Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
+
+ for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
+ {
+ const TField &field = *interfaceBlock.fields()[typeIndex];
+ const TType &fieldType = *field.type();
+
+ if (blockStorage == EbsStd140)
+ {
+ // 2 and 3 component vector types in some cases need pre-padding
+ hlsl += padHelper.prePaddingString(fieldType);
+ }
+
+ hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + " " +
+ Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
+
+ // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
+ // stuff
+ if (blockStorage == EbsStd140)
+ {
+ const bool useHLSLRowMajorPacking =
+ (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
+ hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
+ }
+ }
+
+ return hlsl;
+}
+
+TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
+{
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+
+ return "struct " + InterfaceBlockStructName(interfaceBlock) +
+ "\n"
+ "{\n" +
+ uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h
new file mode 100644
index 0000000000..0c028224b0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h
@@ -0,0 +1,139 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ResourcesHLSL.h:
+// Methods for GLSL to HLSL translation for uniforms and interface blocks.
+//
+
+#ifndef COMPILER_TRANSLATOR_RESOURCESHLSL_H_
+#define COMPILER_TRANSLATOR_RESOURCESHLSL_H_
+
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+
+namespace sh
+{
+class ImmutableString;
+class StructureHLSL;
+class TSymbolTable;
+
+class ResourcesHLSL : angle::NonCopyable
+{
+ public:
+ ResourcesHLSL(StructureHLSL *structureHLSL,
+ ShShaderOutput outputType,
+ const std::vector<Uniform> &uniforms,
+ unsigned int firstUniformRegister);
+
+ void reserveUniformRegisters(unsigned int registerCount);
+ void reserveUniformBlockRegisters(unsigned int registerCount);
+ void uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedVariables &referencedUniforms,
+ TSymbolTable *symbolTable);
+
+ // Must be called after uniformsHeader
+ void samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex);
+ unsigned int getSamplerCount() const { return mSamplerCount; }
+ void imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex);
+ TString uniformBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks);
+ TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks);
+
+ // Used for direct index references
+ static TString InterfaceBlockInstanceString(const ImmutableString &instanceName,
+ unsigned int arrayIndex);
+
+ const std::map<std::string, unsigned int> &getShaderStorageBlockRegisterMap() const
+ {
+ return mShaderStorageBlockRegisterMap;
+ }
+
+ const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const
+ {
+ return mUniformBlockRegisterMap;
+ }
+ const std::map<std::string, unsigned int> &getUniformRegisterMap() const
+ {
+ return mUniformRegisterMap;
+ }
+
+ unsigned int getReadonlyImage2DRegisterIndex() const { return mReadonlyImage2DRegisterIndex; }
+ unsigned int getImage2DRegisterIndex() const { return mImage2DRegisterIndex; }
+
+ private:
+ TString uniformBlockString(const TInterfaceBlock &interfaceBlock,
+ const TVariable *instanceVariable,
+ unsigned int registerIndex,
+ unsigned int arrayIndex);
+
+ TString shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
+ const TVariable *instanceVariable,
+ unsigned int registerIndex,
+ unsigned int arrayIndex);
+ TString uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
+ TLayoutBlockStorage blockStorage);
+ TString uniformBlockStructString(const TInterfaceBlock &interfaceBlock);
+ const Uniform *findUniformByName(const ImmutableString &name) const;
+
+ void outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
+ const TType &type,
+ const TVariable &variable,
+ const unsigned int registerIndex);
+ void outputUniform(TInfoSinkBase &out,
+ const TType &type,
+ const TVariable &variable,
+ const unsigned int registerIndex);
+ void outputAtomicCounterBuffer(TInfoSinkBase &out,
+ const int binding,
+ const unsigned int registerIndex);
+
+ // Returns the uniform's register index
+ unsigned int assignUniformRegister(const TType &type,
+ const ImmutableString &name,
+ unsigned int *outRegisterCount);
+ unsigned int assignSamplerInStructUniformRegister(const TType &type,
+ const TString &name,
+ unsigned int *outRegisterCount);
+
+ void outputHLSLSamplerUniformGroup(
+ TInfoSinkBase &out,
+ const HLSLTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
+ unsigned int *groupTextureRegisterIndex);
+
+ void outputHLSLImageUniformIndices(TInfoSinkBase &out,
+ const TVector<const TVariable *> &group,
+ unsigned int imageArrayIndex,
+ unsigned int *groupRegisterCount);
+ void outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
+ const HLSLTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ unsigned int *groupTextureRegisterIndex);
+ void outputHLSLImageUniformGroup(TInfoSinkBase &out,
+ const HLSLRWTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ unsigned int *groupTextureRegisterIndex);
+
+ unsigned int mUniformRegister;
+ unsigned int mUniformBlockRegister;
+ unsigned int mTextureRegister;
+ unsigned int mUAVRegister;
+ unsigned int mSamplerCount;
+ unsigned int mReadonlyImageCount;
+ unsigned int mImageCount;
+ StructureHLSL *mStructureHLSL;
+ ShShaderOutput mOutputType;
+
+ const std::vector<Uniform> &mUniforms;
+ std::map<std::string, unsigned int> mUniformBlockRegisterMap;
+ std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap;
+ std::map<std::string, unsigned int> mUniformRegisterMap;
+ unsigned int mReadonlyImage2DRegisterIndex;
+ unsigned int mImage2DRegisterIndex;
+};
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_RESOURCESHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Severity.h b/gfx/angle/checkout/src/compiler/translator/Severity.h
new file mode 100644
index 0000000000..47808a16a7
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Severity.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_SEVERITY_H_
+#define COMPILER_TRANSLATOR_SEVERITY_H_
+
+namespace sh
+{
+
+// Severity is used to classify info log messages.
+enum Severity
+{
+ SH_WARNING,
+ SH_ERROR
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SEVERITY_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp
new file mode 100644
index 0000000000..3a947d3c09
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp
@@ -0,0 +1,675 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Implement the top-level of interface to the compiler,
+// as defined in ShaderLang.h
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/InitializeDll.h"
+#include "compiler/translator/length_limits.h"
+#ifdef ANGLE_ENABLE_HLSL
+# include "compiler/translator/TranslatorHLSL.h"
+#endif // ANGLE_ENABLE_HLSL
+#include "angle_gl.h"
+#include "compiler/translator/VariablePacker.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool isInitialized = false;
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+template <typename VarT>
+const std::vector<VarT> *GetVariableList(const TCompiler *compiler);
+
+template <>
+const std::vector<Uniform> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getUniforms();
+}
+
+template <>
+const std::vector<Varying> *GetVariableList(const TCompiler *compiler)
+{
+ switch (compiler->getShaderType())
+ {
+ case GL_VERTEX_SHADER:
+ return &compiler->getOutputVaryings();
+ case GL_FRAGMENT_SHADER:
+ return &compiler->getInputVaryings();
+ case GL_COMPUTE_SHADER:
+ ASSERT(compiler->getOutputVaryings().empty() && compiler->getInputVaryings().empty());
+ return &compiler->getOutputVaryings();
+ // Since geometry shaders have both input and output varyings, we shouldn't call GetVaryings
+ // on a geometry shader.
+ default:
+ return nullptr;
+ }
+}
+
+template <>
+const std::vector<Attribute> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getAttributes();
+}
+
+template <>
+const std::vector<OutputVariable> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getOutputVariables();
+}
+
+template <>
+const std::vector<InterfaceBlock> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getInterfaceBlocks();
+}
+
+TCompiler *GetCompilerFromHandle(ShHandle handle)
+{
+ if (!handle)
+ {
+ return nullptr;
+ }
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ return base->getAsCompiler();
+}
+
+template <typename VarT>
+const std::vector<VarT> *GetShaderVariables(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ if (!compiler)
+ {
+ return nullptr;
+ }
+
+ return GetVariableList<VarT>(compiler);
+}
+
+#ifdef ANGLE_ENABLE_HLSL
+TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle)
+{
+ if (!handle)
+ return nullptr;
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ return base->getAsTranslatorHLSL();
+}
+#endif // ANGLE_ENABLE_HLSL
+
+GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType)
+{
+ switch (primitiveType)
+ {
+ case EptPoints:
+ return GL_POINTS;
+ case EptLines:
+ return GL_LINES;
+ case EptLinesAdjacency:
+ return GL_LINES_ADJACENCY_EXT;
+ case EptTriangles:
+ return GL_TRIANGLES;
+ case EptTrianglesAdjacency:
+ return GL_TRIANGLES_ADJACENCY_EXT;
+
+ case EptLineStrip:
+ return GL_LINE_STRIP;
+ case EptTriangleStrip:
+ return GL_TRIANGLE_STRIP;
+
+ case EptUndefined:
+ default:
+ UNREACHABLE();
+ return GL_INVALID_VALUE;
+ }
+}
+
+} // anonymous namespace
+
+//
+// Driver must call this first, once, before doing any other compiler operations.
+// Subsequent calls to this function are no-op.
+//
+bool Initialize()
+{
+ if (!isInitialized)
+ {
+ isInitialized = InitProcess();
+ }
+ return isInitialized;
+}
+
+//
+// Cleanup symbol tables
+//
+bool Finalize()
+{
+ if (isInitialized)
+ {
+ DetachProcess();
+ isInitialized = false;
+ }
+ return true;
+}
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void InitBuiltInResources(ShBuiltInResources *resources)
+{
+ // Make comparable.
+ memset(resources, 0, sizeof(*resources));
+
+ // Constants.
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ // Extensions.
+ resources->OES_standard_derivatives = 0;
+ resources->OES_EGL_image_external = 0;
+ resources->OES_EGL_image_external_essl3 = 0;
+ resources->NV_EGL_stream_consumer_external = 0;
+ resources->ARB_texture_rectangle = 0;
+ resources->EXT_blend_func_extended = 0;
+ resources->EXT_draw_buffers = 0;
+ resources->EXT_frag_depth = 0;
+ resources->EXT_shader_texture_lod = 0;
+ resources->WEBGL_debug_shader_precision = 0;
+ resources->EXT_shader_framebuffer_fetch = 0;
+ resources->NV_shader_framebuffer_fetch = 0;
+ resources->ARM_shader_framebuffer_fetch = 0;
+ resources->OVR_multiview = 0;
+ resources->OVR_multiview2 = 0;
+ resources->EXT_YUV_target = 0;
+ resources->EXT_geometry_shader = 0;
+ resources->OES_texture_storage_multisample_2d_array = 0;
+ resources->OES_texture_3D = 0;
+ resources->ANGLE_texture_multisample = 0;
+ resources->ANGLE_multi_draw = 0;
+ resources->ANGLE_base_vertex_base_instance = 0;
+
+ resources->NV_draw_buffers = 0;
+
+ // Disable highp precision in fragment shader by default.
+ resources->FragmentPrecisionHigh = 0;
+
+ // GLSL ES 3.0 constants.
+ resources->MaxVertexOutputVectors = 16;
+ resources->MaxFragmentInputVectors = 15;
+ resources->MinProgramTexelOffset = -8;
+ resources->MaxProgramTexelOffset = 7;
+
+ // Extensions constants.
+ resources->MaxDualSourceDrawBuffers = 0;
+
+ resources->MaxViewsOVR = 4;
+
+ // Disable name hashing by default.
+ resources->HashFunction = nullptr;
+
+ resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
+
+ resources->MaxExpressionComplexity = 256;
+ resources->MaxCallStackDepth = 256;
+ resources->MaxFunctionParameters = 1024;
+
+ // ES 3.1 Revision 4, 7.2 Built-in Constants
+
+ // ES 3.1, Revision 4, 8.13 Texture minification
+ // "The value of MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be less than or equal to the value of
+ // MIN_PROGRAM_TEXEL_OFFSET. The value of MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be greater than
+ // or equal to the value of MAX_PROGRAM_TEXEL_OFFSET"
+ resources->MinProgramTextureGatherOffset = -8;
+ resources->MaxProgramTextureGatherOffset = 7;
+
+ resources->MaxImageUnits = 4;
+ resources->MaxVertexImageUniforms = 0;
+ resources->MaxFragmentImageUniforms = 0;
+ resources->MaxComputeImageUniforms = 4;
+ resources->MaxCombinedImageUniforms = 4;
+
+ resources->MaxUniformLocations = 1024;
+
+ resources->MaxCombinedShaderOutputResources = 4;
+
+ resources->MaxComputeWorkGroupCount[0] = 65535;
+ resources->MaxComputeWorkGroupCount[1] = 65535;
+ resources->MaxComputeWorkGroupCount[2] = 65535;
+ resources->MaxComputeWorkGroupSize[0] = 128;
+ resources->MaxComputeWorkGroupSize[1] = 128;
+ resources->MaxComputeWorkGroupSize[2] = 64;
+ resources->MaxComputeUniformComponents = 512;
+ resources->MaxComputeTextureImageUnits = 16;
+
+ resources->MaxComputeAtomicCounters = 8;
+ resources->MaxComputeAtomicCounterBuffers = 1;
+
+ resources->MaxVertexAtomicCounters = 0;
+ resources->MaxFragmentAtomicCounters = 0;
+ resources->MaxCombinedAtomicCounters = 8;
+ resources->MaxAtomicCounterBindings = 1;
+
+ resources->MaxVertexAtomicCounterBuffers = 0;
+ resources->MaxFragmentAtomicCounterBuffers = 0;
+ resources->MaxCombinedAtomicCounterBuffers = 1;
+ resources->MaxAtomicCounterBufferSize = 32;
+
+ resources->MaxUniformBufferBindings = 32;
+ resources->MaxShaderStorageBufferBindings = 4;
+
+ resources->MaxGeometryUniformComponents = 1024;
+ resources->MaxGeometryUniformBlocks = 12;
+ resources->MaxGeometryInputComponents = 64;
+ resources->MaxGeometryOutputComponents = 64;
+ resources->MaxGeometryOutputVertices = 256;
+ resources->MaxGeometryTotalOutputComponents = 1024;
+ resources->MaxGeometryTextureImageUnits = 16;
+ resources->MaxGeometryAtomicCounterBuffers = 0;
+ resources->MaxGeometryAtomicCounters = 0;
+ resources->MaxGeometryShaderStorageBlocks = 0;
+ resources->MaxGeometryShaderInvocations = 32;
+ resources->MaxGeometryImageUniforms = 0;
+}
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+ShHandle ConstructCompiler(sh::GLenum type,
+ ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources *resources)
+{
+ TShHandleBase *base = static_cast<TShHandleBase *>(ConstructCompiler(type, spec, output));
+ if (base == nullptr)
+ {
+ return 0;
+ }
+
+ TCompiler *compiler = base->getAsCompiler();
+ if (compiler == nullptr)
+ {
+ return 0;
+ }
+
+ // Generate built-in symbol table.
+ if (!compiler->Init(*resources))
+ {
+ Destruct(base);
+ return 0;
+ }
+
+ return base;
+}
+
+void Destruct(ShHandle handle)
+{
+ if (handle == 0)
+ return;
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+
+ if (base->getAsCompiler())
+ DeleteCompiler(base->getAsCompiler());
+}
+
+const std::string &GetBuiltInResourcesString(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return compiler->getBuiltInResourcesString();
+}
+
+//
+// Do an actual compile on the given strings. The result is left
+// in the given compile object.
+//
+// Return: The return value of ShCompile is really boolean, indicating
+// success or failure.
+//
+bool Compile(const ShHandle handle,
+ const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+
+ return compiler->compile(shaderStrings, numStrings, compileOptions);
+}
+
+void ClearResults(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ compiler->clearResults();
+}
+
+int GetShaderVersion(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return compiler->getShaderVersion();
+}
+
+ShShaderOutput GetShaderOutputType(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return compiler->getOutputType();
+}
+
+//
+// Return any compiler log of messages for the application.
+//
+const std::string &GetInfoLog(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+
+ TInfoSink &infoSink = compiler->getInfoSink();
+ return infoSink.info.str();
+}
+
+//
+// Return any object code.
+//
+const std::string &GetObjectCode(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+
+ TInfoSink &infoSink = compiler->getInfoSink();
+ return infoSink.obj.str();
+}
+
+const std::map<std::string, std::string> *GetNameHashingMap(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ return &(compiler->getNameMap());
+}
+
+const std::vector<Uniform> *GetUniforms(const ShHandle handle)
+{
+ return GetShaderVariables<Uniform>(handle);
+}
+
+const std::vector<Varying> *GetInputVaryings(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ if (compiler == nullptr)
+ {
+ return nullptr;
+ }
+ return &compiler->getInputVaryings();
+}
+
+const std::vector<Varying> *GetOutputVaryings(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ if (compiler == nullptr)
+ {
+ return nullptr;
+ }
+ return &compiler->getOutputVaryings();
+}
+
+const std::vector<Varying> *GetVaryings(const ShHandle handle)
+{
+ return GetShaderVariables<Varying>(handle);
+}
+
+const std::vector<Attribute> *GetAttributes(const ShHandle handle)
+{
+ return GetShaderVariables<Attribute>(handle);
+}
+
+const std::vector<OutputVariable> *GetOutputVariables(const ShHandle handle)
+{
+ return GetShaderVariables<OutputVariable>(handle);
+}
+
+const std::vector<InterfaceBlock> *GetInterfaceBlocks(const ShHandle handle)
+{
+ return GetShaderVariables<InterfaceBlock>(handle);
+}
+
+const std::vector<InterfaceBlock> *GetUniformBlocks(const ShHandle handle)
+{
+ ASSERT(handle);
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return &compiler->getUniformBlocks();
+}
+
+const std::vector<InterfaceBlock> *GetShaderStorageBlocks(const ShHandle handle)
+{
+ ASSERT(handle);
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return &compiler->getShaderStorageBlocks();
+}
+
+WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getComputeShaderLocalSize();
+}
+
+int GetVertexShaderNumViews(const ShHandle handle)
+{
+ ASSERT(handle);
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getNumViews();
+}
+
+bool CheckVariablesWithinPackingLimits(int maxVectors, const std::vector<ShaderVariable> &variables)
+{
+ return CheckVariablesInPackingLimits(maxVectors, variables);
+}
+
+bool GetShaderStorageBlockRegister(const ShHandle handle,
+ const std::string &shaderStorageBlockName,
+ unsigned int *indexOut)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ ASSERT(indexOut);
+
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ if (!translator->hasShaderStorageBlock(shaderStorageBlockName))
+ {
+ return false;
+ }
+
+ *indexOut = translator->getShaderStorageBlockRegister(shaderStorageBlockName);
+ return true;
+#else
+ return false;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+bool GetUniformBlockRegister(const ShHandle handle,
+ const std::string &uniformBlockName,
+ unsigned int *indexOut)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ ASSERT(indexOut);
+
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ if (!translator->hasUniformBlock(uniformBlockName))
+ {
+ return false;
+ }
+
+ *indexOut = translator->getUniformBlockRegister(uniformBlockName);
+ return true;
+#else
+ return false;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle handle)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ return translator->getUniformRegisterMap();
+#else
+ return nullptr;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+unsigned int GetReadonlyImage2DRegisterIndex(const ShHandle handle)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ return translator->getReadonlyImage2DRegisterIndex();
+#else
+ return 0;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+unsigned int GetImage2DRegisterIndex(const ShHandle handle)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ return translator->getImage2DRegisterIndex();
+#else
+ return 0;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+const std::set<std::string> *GetUsedImage2DFunctionNames(const ShHandle handle)
+{
+#ifdef ANGLE_ENABLE_HLSL
+ TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
+ ASSERT(translator);
+
+ return translator->getUsedImage2DFunctionNames();
+#else
+ return nullptr;
+#endif // ANGLE_ENABLE_HLSL
+}
+
+bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getGeometryShaderInputPrimitiveType() != EptUndefined;
+}
+
+bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getGeometryShaderOutputPrimitiveType() != EptUndefined;
+}
+
+bool HasValidGeometryShaderMaxVertices(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getGeometryShaderMaxVertices() >= 0;
+}
+
+GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return GetGeometryShaderPrimitiveTypeEnum(compiler->getGeometryShaderInputPrimitiveType());
+}
+
+GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return GetGeometryShaderPrimitiveTypeEnum(compiler->getGeometryShaderOutputPrimitiveType());
+}
+
+int GetGeometryShaderInvocations(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ return compiler->getGeometryShaderInvocations();
+}
+
+int GetGeometryShaderMaxVertices(const ShHandle handle)
+{
+ ASSERT(handle);
+
+ TShHandleBase *base = static_cast<TShHandleBase *>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ ASSERT(compiler);
+
+ int maxVertices = compiler->getGeometryShaderMaxVertices();
+ ASSERT(maxVertices >= 0);
+ return maxVertices;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp
new file mode 100644
index 0000000000..01b246d1d7
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp
@@ -0,0 +1,435 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ShaderStorageBlockFunctionHLSL: Wrapper functions for RWByteAddressBuffer Load/Store functions.
+//
+
+#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h"
+
+#include "common/utilities.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/blocklayout.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+// static
+void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
+ TInfoSinkBase &out,
+ const ShaderStorageBlockFunction &ssboFunction)
+{
+ const char *convertString;
+ switch (ssboFunction.type.getBasicType())
+ {
+ case EbtFloat:
+ convertString = "asfloat(";
+ break;
+ case EbtInt:
+ convertString = "asint(";
+ break;
+ case EbtUInt:
+ convertString = "asuint(";
+ break;
+ case EbtBool:
+ convertString = "asint(";
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+
+ size_t bytesPerComponent =
+ gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type)));
+ out << " " << ssboFunction.typeString << " result";
+ if (ssboFunction.type.isScalar())
+ {
+ size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent;
+ out << " = " << convertString << "buffer.Load(loc + " << offset << "));\n ";
+ }
+ else if (ssboFunction.type.isVector())
+ {
+ if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle)
+ {
+ size_t componentStride = bytesPerComponent;
+ if (ssboFunction.rowMajor)
+ {
+ componentStride = ssboFunction.matrixStride;
+ }
+
+ out << " = {";
+ for (const int offset : ssboFunction.swizzleOffsets)
+ {
+ size_t offsetInBytes = offset * componentStride;
+ out << convertString << "buffer.Load(loc + " << offsetInBytes << ")),";
+ }
+ out << "};\n";
+ }
+ else
+ {
+ out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize()
+ << "(loc));\n";
+ }
+ }
+ else if (ssboFunction.type.isMatrix())
+ {
+ if (ssboFunction.rowMajor)
+ {
+ out << ";";
+ out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
+ << " tmp_ = {";
+ for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
+ {
+ out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc + "
+ << rowIndex * ssboFunction.matrixStride << ")), ";
+ }
+ out << "};\n";
+ out << " result = transpose(tmp_);\n";
+ }
+ else
+ {
+ out << " = {";
+ for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
+ {
+ out << "asfloat(buffer.Load" << ssboFunction.type.getRows() << "(loc + "
+ << columnIndex * ssboFunction.matrixStride << ")), ";
+ }
+ out << "};\n";
+ }
+ }
+ else
+ {
+ // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951
+ out << ";\n";
+ }
+
+ out << " return result;\n";
+ return;
+}
+
+// static
+void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
+ TInfoSinkBase &out,
+ const ShaderStorageBlockFunction &ssboFunction)
+{
+ size_t bytesPerComponent =
+ gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type)));
+ if (ssboFunction.type.isScalar())
+ {
+ size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent;
+ if (ssboFunction.type.getBasicType() == EbtBool)
+ {
+ out << " buffer.Store(loc + " << offset << ", uint(value));\n";
+ }
+ else
+ {
+ out << " buffer.Store(loc + " << offset << ", asuint(value));\n";
+ }
+ }
+ else if (ssboFunction.type.isVector())
+ {
+ out << " uint" << ssboFunction.type.getNominalSize() << " _value;\n";
+ if (ssboFunction.type.getBasicType() == EbtBool)
+ {
+ out << " _value = uint" << ssboFunction.type.getNominalSize() << "(value);\n";
+ }
+ else
+ {
+ out << " _value = asuint(value);\n";
+ }
+
+ if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle)
+ {
+ size_t componentStride = bytesPerComponent;
+ if (ssboFunction.rowMajor)
+ {
+ componentStride = ssboFunction.matrixStride;
+ }
+ const TVector<int> &swizzleOffsets = ssboFunction.swizzleOffsets;
+ for (int index = 0; index < static_cast<int>(swizzleOffsets.size()); index++)
+ {
+ size_t offsetInBytes = swizzleOffsets[index] * componentStride;
+ out << "buffer.Store(loc + " << offsetInBytes << ", _value[" << index << "]);\n";
+ }
+ }
+ else
+ {
+ out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _value);\n";
+ }
+ }
+ else if (ssboFunction.type.isMatrix())
+ {
+ if (ssboFunction.rowMajor)
+ {
+ out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
+ << " tmp_ = transpose(value);\n";
+ for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
+ {
+ out << " buffer.Store" << ssboFunction.type.getCols() << "(loc + "
+ << rowIndex * ssboFunction.matrixStride << ", asuint(tmp_[" << rowIndex
+ << "]));\n";
+ }
+ }
+ else
+ {
+ for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
+ {
+ out << " buffer.Store" << ssboFunction.type.getRows() << "(loc + "
+ << columnIndex * ssboFunction.matrixStride << ", asuint(value[" << columnIndex
+ << "]));\n";
+ }
+ }
+ }
+ else
+ {
+ // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951
+ }
+}
+
+// static
+void ShaderStorageBlockFunctionHLSL::OutputSSBOLengthFunctionBody(TInfoSinkBase &out,
+ int unsizedArrayStride)
+{
+ out << " uint dim = 0;\n";
+ out << " buffer.GetDimensions(dim);\n";
+ out << " return int((dim - loc)/uint(" << unsizedArrayStride << "));\n";
+}
+
+// static
+void ShaderStorageBlockFunctionHLSL::OutputSSBOAtomicMemoryFunctionBody(
+ TInfoSinkBase &out,
+ const ShaderStorageBlockFunction &ssboFunction)
+{
+ out << " " << ssboFunction.typeString << " original_value;\n";
+ switch (ssboFunction.method)
+ {
+ case SSBOMethod::ATOMIC_ADD:
+ out << " buffer.InterlockedAdd(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_MIN:
+ out << " buffer.InterlockedMin(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_MAX:
+ out << " buffer.InterlockedMax(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_AND:
+ out << " buffer.InterlockedAnd(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_OR:
+ out << " buffer.InterlockedOr(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_XOR:
+ out << " buffer.InterlockedXor(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_EXCHANGE:
+ out << " buffer.InterlockedExchange(loc, value, original_value);\n";
+ break;
+ case SSBOMethod::ATOMIC_COMPSWAP:
+ out << " buffer.InterlockedCompareExchange(loc, compare_value, value, "
+ "original_value);\n";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ out << " return original_value;\n";
+}
+
+bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
+ const ShaderStorageBlockFunction &rhs) const
+{
+ return functionName < rhs.functionName;
+}
+
+TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
+ const TType &type,
+ SSBOMethod method,
+ TLayoutBlockStorage storage,
+ bool rowMajor,
+ int matrixStride,
+ int unsizedArrayStride,
+ TIntermSwizzle *swizzleNode)
+{
+ ShaderStorageBlockFunction ssboFunction;
+ ssboFunction.typeString = TypeString(type);
+ ssboFunction.method = method;
+ switch (method)
+ {
+ case SSBOMethod::LOAD:
+ ssboFunction.functionName = "_Load_";
+ break;
+ case SSBOMethod::STORE:
+ ssboFunction.functionName = "_Store_";
+ break;
+ case SSBOMethod::LENGTH:
+ ssboFunction.unsizedArrayStride = unsizedArrayStride;
+ ssboFunction.functionName = "_Length_" + str(unsizedArrayStride);
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_ADD:
+ ssboFunction.functionName = "_ssbo_atomicAdd_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_MIN:
+ ssboFunction.functionName = "_ssbo_atomicMin_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_MAX:
+ ssboFunction.functionName = "_ssbo_atomicMax_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_AND:
+ ssboFunction.functionName = "_ssbo_atomicAnd_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_OR:
+ ssboFunction.functionName = "_ssbo_atomicOr_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_XOR:
+ ssboFunction.functionName = "_ssbo_atomicXor_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_EXCHANGE:
+ ssboFunction.functionName = "_ssbo_atomicExchange_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ case SSBOMethod::ATOMIC_COMPSWAP:
+ ssboFunction.functionName = "_ssbo_atomicCompSwap_" + ssboFunction.typeString;
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+ default:
+ UNREACHABLE();
+ }
+
+ ssboFunction.functionName += ssboFunction.typeString;
+ ssboFunction.type = type;
+ if (swizzleNode != nullptr)
+ {
+ ssboFunction.swizzleOffsets = swizzleNode->getSwizzleOffsets();
+ ssboFunction.isDefaultSwizzle = false;
+ }
+ else
+ {
+ if (ssboFunction.type.getNominalSize() > 1)
+ {
+ for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
+ {
+ ssboFunction.swizzleOffsets.push_back(index);
+ }
+ }
+ else
+ {
+ ssboFunction.swizzleOffsets.push_back(0);
+ }
+
+ ssboFunction.isDefaultSwizzle = true;
+ }
+ ssboFunction.rowMajor = rowMajor;
+ ssboFunction.matrixStride = matrixStride;
+ ssboFunction.functionName += "_" + TString(getBlockStorageString(storage));
+
+ if (rowMajor)
+ {
+ ssboFunction.functionName += "_rm_";
+ }
+ else
+ {
+ ssboFunction.functionName += "_cm_";
+ }
+
+ for (const int offset : ssboFunction.swizzleOffsets)
+ {
+ switch (offset)
+ {
+ case 0:
+ ssboFunction.functionName += "x";
+ break;
+ case 1:
+ ssboFunction.functionName += "y";
+ break;
+ case 2:
+ ssboFunction.functionName += "z";
+ break;
+ case 3:
+ ssboFunction.functionName += "w";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
+ return ssboFunction.functionName;
+}
+
+void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkBase &out)
+{
+ for (const ShaderStorageBlockFunction &ssboFunction : mRegisteredShaderStorageBlockFunctions)
+ {
+ switch (ssboFunction.method)
+ {
+ case SSBOMethod::LOAD:
+ {
+ // Function header
+ out << ssboFunction.typeString << " " << ssboFunction.functionName
+ << "(RWByteAddressBuffer buffer, uint loc)\n";
+ out << "{\n";
+ OutputSSBOLoadFunctionBody(out, ssboFunction);
+ break;
+ }
+ case SSBOMethod::STORE:
+ {
+ // Function header
+ out << "void " << ssboFunction.functionName
+ << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
+ << " value)\n";
+ out << "{\n";
+ OutputSSBOStoreFunctionBody(out, ssboFunction);
+ break;
+ }
+ case SSBOMethod::LENGTH:
+ {
+ out << "int " << ssboFunction.functionName
+ << "(RWByteAddressBuffer buffer, uint loc)\n";
+ out << "{\n";
+ OutputSSBOLengthFunctionBody(out, ssboFunction.unsizedArrayStride);
+ break;
+ }
+ case SSBOMethod::ATOMIC_ADD:
+ case SSBOMethod::ATOMIC_MIN:
+ case SSBOMethod::ATOMIC_MAX:
+ case SSBOMethod::ATOMIC_AND:
+ case SSBOMethod::ATOMIC_OR:
+ case SSBOMethod::ATOMIC_XOR:
+ case SSBOMethod::ATOMIC_EXCHANGE:
+ {
+ out << ssboFunction.typeString << " " << ssboFunction.functionName
+ << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
+ << " value)\n";
+ out << "{\n";
+
+ OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction);
+ break;
+ }
+ case SSBOMethod::ATOMIC_COMPSWAP:
+ {
+ out << ssboFunction.typeString << " " << ssboFunction.functionName
+ << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
+ << " compare_value, " << ssboFunction.typeString << " value)\n";
+ out << "{\n";
+ OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ out << "}\n"
+ "\n";
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h
new file mode 100644
index 0000000000..0d3cd0291b
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h
@@ -0,0 +1,94 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of
+// RWByteAddressBuffer.
+// //EOpIndexDirectInterfaceBlock
+// ssbo_variable :=
+// | the name of the SSBO
+// | the name of a variable in an SSBO backed interface block
+
+// // EOpIndexInDirect
+// // EOpIndexDirect
+// ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo]
+
+// // EOpIndexDirectStruct
+// ssbo_structure_access := ssbo_access_chain.identifier
+
+// ssbo_access_chain :=
+// | ssbo_variable
+// | ssbo_array_indexing
+// | ssbo_structure_access
+//
+
+#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_
+#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_
+
+#include <set>
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/Types.h"
+
+namespace sh
+{
+
+class TIntermSwizzle;
+enum class SSBOMethod
+{
+ LOAD,
+ STORE,
+ LENGTH,
+ ATOMIC_ADD,
+ ATOMIC_MIN,
+ ATOMIC_MAX,
+ ATOMIC_AND,
+ ATOMIC_OR,
+ ATOMIC_XOR,
+ ATOMIC_EXCHANGE,
+ ATOMIC_COMPSWAP
+};
+
+class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
+{
+ public:
+ TString registerShaderStorageBlockFunction(const TType &type,
+ SSBOMethod method,
+ TLayoutBlockStorage storage,
+ bool rowMajor,
+ int matrixStride,
+ int unsizedArrayStride,
+ TIntermSwizzle *node);
+
+ void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
+
+ private:
+ struct ShaderStorageBlockFunction
+ {
+ bool operator<(const ShaderStorageBlockFunction &rhs) const;
+ TString functionName;
+ TString typeString;
+ SSBOMethod method;
+ TType type;
+ bool rowMajor;
+ int matrixStride;
+ int unsizedArrayStride;
+ TVector<int> swizzleOffsets;
+ bool isDefaultSwizzle;
+ };
+
+ static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
+ const ShaderStorageBlockFunction &ssboFunction);
+ static void OutputSSBOStoreFunctionBody(TInfoSinkBase &out,
+ const ShaderStorageBlockFunction &ssboFunction);
+ static void OutputSSBOLengthFunctionBody(TInfoSinkBase &out, int unsizedArrayStride);
+ static void OutputSSBOAtomicMemoryFunctionBody(TInfoSinkBase &out,
+ const ShaderStorageBlockFunction &ssboFunction);
+ using ShaderStorageBlockFunctionSet = std::set<ShaderStorageBlockFunction>;
+ ShaderStorageBlockFunctionSet mRegisteredShaderStorageBlockFunctions;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp
new file mode 100644
index 0000000000..bef88db386
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp
@@ -0,0 +1,762 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of
+// RWByteAddressBuffer.
+// //EOpIndexDirectInterfaceBlock
+// ssbo_variable :=
+// | the name of the SSBO
+// | the name of a variable in an SSBO backed interface block
+
+// // EOpIndexInDirect
+// // EOpIndexDirect
+// ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo]
+
+// // EOpIndexDirectStruct
+// ssbo_structure_access := ssbo_access_chain.identifier
+
+// ssbo_access_chain :=
+// | ssbo_variable
+// | ssbo_array_indexing
+// | ssbo_structure_access
+//
+
+#include "compiler/translator/ShaderStorageBlockOutputHLSL.h"
+
+#include "compiler/translator/ResourcesHLSL.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void GetBlockLayoutInfo(TIntermTyped *node,
+ bool rowMajorAlreadyAssigned,
+ TLayoutBlockStorage *storage,
+ bool *rowMajor)
+{
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ return GetBlockLayoutInfo(swizzleNode->getOperand(), rowMajorAlreadyAssigned, storage,
+ rowMajor);
+ }
+
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ {
+ // The column_major/row_major qualifier of a field member overrides the interface
+ // block's row_major/column_major. So we can assign rowMajor here and don't need to
+ // assign it again. But we still need to call recursively to get the storage's
+ // value.
+ const TType &type = node->getType();
+ *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
+ return GetBlockLayoutInfo(binaryNode->getLeft(), true, storage, rowMajor);
+ }
+ case EOpIndexIndirect:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ return GetBlockLayoutInfo(binaryNode->getLeft(), rowMajorAlreadyAssigned, storage,
+ rowMajor);
+ default:
+ UNREACHABLE();
+ return;
+ }
+ }
+
+ const TType &type = node->getType();
+ ASSERT(type.getQualifier() == EvqBuffer);
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ ASSERT(interfaceBlock);
+ *storage = interfaceBlock->blockStorage();
+ // If the block doesn't have an instance name, rowMajorAlreadyAssigned will be false. In
+ // this situation, we still need to set rowMajor's value.
+ if (!rowMajorAlreadyAssigned)
+ {
+ *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
+ }
+}
+
+// It's possible that the current type has lost the original layout information. So we should pass
+// the right layout information to GetBlockMemberInfoByType.
+const BlockMemberInfo GetBlockMemberInfoByType(const TType &type,
+ TLayoutBlockStorage storage,
+ bool rowMajor)
+{
+ sh::Std140BlockEncoder std140Encoder;
+ sh::Std430BlockEncoder std430Encoder;
+ sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
+ sh::BlockLayoutEncoder *encoder = nullptr;
+
+ if (storage == EbsStd140)
+ {
+ encoder = &std140Encoder;
+ }
+ else if (storage == EbsStd430)
+ {
+ encoder = &std430Encoder;
+ }
+ else
+ {
+ encoder = &hlslEncoder;
+ }
+
+ std::vector<unsigned int> arraySizes;
+ auto *typeArraySizes = type.getArraySizes();
+ if (typeArraySizes != nullptr)
+ {
+ arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
+ }
+ return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
+}
+
+const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
+ const ImmutableString &variableName)
+{
+ for (const TField *field : interfaceBlock->fields())
+ {
+ if (field->name() == variableName)
+ {
+ return field;
+ }
+ }
+ return nullptr;
+}
+
+const InterfaceBlock *FindInterfaceBlock(const TInterfaceBlock *needle,
+ const std::vector<InterfaceBlock> &haystack)
+{
+ for (const InterfaceBlock &block : haystack)
+ {
+ if (strcmp(block.name.c_str(), needle->name().data()) == 0)
+ {
+ ASSERT(block.fields.size() == needle->fields().size());
+ return &block;
+ }
+ }
+
+ UNREACHABLE();
+ return nullptr;
+}
+
+std::string StripArrayIndices(const std::string &nameIn)
+{
+ std::string name = nameIn;
+ size_t pos = name.find('[');
+ while (pos != std::string::npos)
+ {
+ size_t closePos = name.find(']', pos);
+ ASSERT(closePos != std::string::npos);
+ name.erase(pos, closePos - pos + 1);
+ pos = name.find('[', pos);
+ }
+ ASSERT(name.find(']') == std::string::npos);
+ return name;
+}
+
+// Does not include any array indices.
+void MapVariableToField(const ShaderVariable &variable,
+ const TField *field,
+ std::string currentName,
+ ShaderVarToFieldMap *shaderVarToFieldMap)
+{
+ ASSERT((field->type()->getStruct() == nullptr) == variable.fields.empty());
+ (*shaderVarToFieldMap)[currentName] = field;
+
+ if (!variable.fields.empty())
+ {
+ const TStructure *subStruct = field->type()->getStruct();
+ ASSERT(variable.fields.size() == subStruct->fields().size());
+
+ for (size_t index = 0; index < variable.fields.size(); ++index)
+ {
+ const TField *subField = subStruct->fields()[index];
+ const ShaderVariable &subVariable = variable.fields[index];
+ std::string subName = currentName + "." + subVariable.name;
+ MapVariableToField(subVariable, subField, subName, shaderVarToFieldMap);
+ }
+ }
+}
+
+class BlockInfoVisitor final : public BlockEncoderVisitor
+{
+ public:
+ BlockInfoVisitor(const std::string &prefix,
+ TLayoutBlockStorage storage,
+ const ShaderVarToFieldMap &shaderVarToFieldMap,
+ BlockMemberInfoMap *blockInfoOut)
+ : BlockEncoderVisitor(prefix, "", getEncoder(storage)),
+ mShaderVarToFieldMap(shaderVarToFieldMap),
+ mBlockInfoOut(blockInfoOut),
+ mHLSLEncoder(HLSLBlockEncoder::ENCODE_PACKED, false),
+ mStorage(storage)
+ {}
+
+ BlockLayoutEncoder *getEncoder(TLayoutBlockStorage storage)
+ {
+ switch (storage)
+ {
+ case EbsStd140:
+ return &mStd140Encoder;
+ case EbsStd430:
+ return &mStd430Encoder;
+ default:
+ return &mHLSLEncoder;
+ }
+ }
+
+ void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override
+ {
+ BlockEncoderVisitor::enterStructAccess(structVar, isRowMajor);
+
+ std::string variableName = StripArrayIndices(collapseNameStack());
+
+ // Remove the trailing "."
+ variableName.pop_back();
+
+ BlockInfoVisitor childVisitor(variableName, mStorage, mShaderVarToFieldMap, mBlockInfoOut);
+ childVisitor.getEncoder(mStorage)->enterAggregateType(structVar);
+ TraverseShaderVariables(structVar.fields, isRowMajor, &childVisitor);
+ childVisitor.getEncoder(mStorage)->exitAggregateType(structVar);
+
+ int offset = getEncoder(mStorage)->getCurrentOffset();
+ int arrayStride = childVisitor.getEncoder(mStorage)->getCurrentOffset();
+
+ auto iter = mShaderVarToFieldMap.find(variableName);
+ if (iter == mShaderVarToFieldMap.end())
+ return;
+
+ const TField *structField = iter->second;
+ if (mBlockInfoOut->count(structField) == 0)
+ {
+ mBlockInfoOut->emplace(structField, BlockMemberInfo(offset, arrayStride, -1, false));
+ }
+ }
+
+ void encodeVariable(const ShaderVariable &variable,
+ const BlockMemberInfo &variableInfo,
+ const std::string &name,
+ const std::string &mappedName) override
+ {
+ auto iter = mShaderVarToFieldMap.find(StripArrayIndices(name));
+ if (iter == mShaderVarToFieldMap.end())
+ return;
+
+ const TField *field = iter->second;
+ if (mBlockInfoOut->count(field) == 0)
+ {
+ mBlockInfoOut->emplace(field, variableInfo);
+ }
+ }
+
+ private:
+ const ShaderVarToFieldMap &mShaderVarToFieldMap;
+ BlockMemberInfoMap *mBlockInfoOut;
+ Std140BlockEncoder mStd140Encoder;
+ Std430BlockEncoder mStd430Encoder;
+ HLSLBlockEncoder mHLSLEncoder;
+ TLayoutBlockStorage mStorage;
+};
+
+void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks,
+ BlockMemberInfoMap *blockInfoOut)
+{
+ // Find the sh::InterfaceBlock.
+ const InterfaceBlock *block = FindInterfaceBlock(interfaceBlock, shaderStorageBlocks);
+ ASSERT(block);
+
+ // Map ShaderVariable to TField.
+ ShaderVarToFieldMap shaderVarToFieldMap;
+ for (size_t index = 0; index < block->fields.size(); ++index)
+ {
+ const TField *field = interfaceBlock->fields()[index];
+ const ShaderVariable &variable = block->fields[index];
+ MapVariableToField(variable, field, variable.name, &shaderVarToFieldMap);
+ }
+
+ BlockInfoVisitor visitor("", interfaceBlock->blockStorage(), shaderVarToFieldMap, blockInfoOut);
+ TraverseShaderVariables(block->fields, false, &visitor);
+}
+
+bool IsInArrayOfArraysChain(TIntermTyped *node)
+{
+ if (node->getType().isArrayOfArrays())
+ return true;
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ if (binaryNode->getLeft()->getType().isArrayOfArrays())
+ return true;
+ }
+
+ return false;
+}
+} // anonymous namespace
+
+ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL(
+ OutputHLSL *outputHLSL,
+ TSymbolTable *symbolTable,
+ ResourcesHLSL *resourcesHLSL,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks)
+ : TIntermTraverser(true, true, true, symbolTable),
+ mMatrixStride(0),
+ mRowMajor(false),
+ mLocationAsTheLastArgument(false),
+ mOutputHLSL(outputHLSL),
+ mResourcesHLSL(resourcesHLSL),
+ mShaderStorageBlocks(shaderStorageBlocks)
+{
+ mSSBOFunctionHLSL = new ShaderStorageBlockFunctionHLSL;
+}
+
+ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL()
+{
+ SafeDelete(mSSBOFunctionHLSL);
+}
+
+void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node)
+{
+ mLocationAsTheLastArgument = false;
+ traverseSSBOAccess(node, SSBOMethod::STORE);
+}
+
+void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
+{
+ mLocationAsTheLastArgument = true;
+ traverseSSBOAccess(node, SSBOMethod::LOAD);
+}
+
+void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node)
+{
+ mLocationAsTheLastArgument = true;
+ traverseSSBOAccess(node, SSBOMethod::LENGTH);
+}
+
+void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node,
+ TOperator op)
+{
+ mLocationAsTheLastArgument = false;
+
+ switch (op)
+ {
+ case EOpAtomicAdd:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_ADD);
+ break;
+ case EOpAtomicMin:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_MIN);
+ break;
+ case EOpAtomicMax:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_MAX);
+ break;
+ case EOpAtomicAnd:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_AND);
+ break;
+ case EOpAtomicOr:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_OR);
+ break;
+ case EOpAtomicXor:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_XOR);
+ break;
+ case EOpAtomicExchange:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_EXCHANGE);
+ break;
+ case EOpAtomicCompSwap:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_COMPSWAP);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+// Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL.
+// It's because that if the current node's type is a vector which comes from a matrix, we will
+// lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL.
+void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node,
+ TLayoutBlockStorage storage,
+ bool rowMajor)
+{
+ if (node->getType().isMatrix())
+ {
+ mMatrixStride = GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride;
+ mRowMajor = rowMajor;
+ return;
+ }
+
+ if (node->getType().isVector())
+ {
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ return setMatrixStride(binaryNode->getLeft(), storage, rowMajor);
+ }
+ else
+ {
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ return setMatrixStride(swizzleNode->getOperand(), storage, rowMajor);
+ }
+ }
+ }
+}
+
+void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method)
+{
+ mMatrixStride = 0;
+ mRowMajor = false;
+
+ // Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current
+ // point. But we must use those information to generate the right function name. So here we have
+ // to calculate them again.
+ TLayoutBlockStorage storage;
+ bool rowMajor;
+ GetBlockLayoutInfo(node, false, &storage, &rowMajor);
+ int unsizedArrayStride = 0;
+ if (node->getType().isUnsizedArray())
+ {
+ unsizedArrayStride =
+ GetBlockMemberInfoByType(node->getType(), storage, rowMajor).arrayStride;
+ }
+ setMatrixStride(node, storage, rowMajor);
+
+ const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction(
+ node->getType(), method, storage, mRowMajor, mMatrixStride, unsizedArrayStride,
+ node->getAsSwizzleNode());
+ TInfoSinkBase &out = mOutputHLSL->getInfoSink();
+ out << functionName;
+ out << "(";
+ node->traverse(this);
+}
+
+void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(TInfoSinkBase &out) const
+{
+ out << mResourcesHLSL->shaderStorageBlocksHeader(mReferencedShaderStorageBlocks);
+ mSSBOFunctionHLSL->shaderStorageBlockFunctionHeader(out);
+}
+
+// Check if the current node is the end of the SSBO access chain. If true, we should output ')' for
+// Load method.
+bool ShaderStorageBlockOutputHLSL::isEndOfSSBOAccessChain()
+{
+ TIntermNode *parent = getParentNode();
+ if (parent)
+ {
+ TIntermBinary *parentBinary = parent->getAsBinaryNode();
+ if (parentBinary != nullptr)
+ {
+ switch (parentBinary->getOp())
+ {
+ case EOpIndexDirectStruct:
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ {
+ return false;
+ }
+ default:
+ return true;
+ }
+ }
+
+ const TIntermSwizzle *parentSwizzle = parent->getAsSwizzleNode();
+ if (parentSwizzle)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ShaderStorageBlockOutputHLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getInfoSink();
+ const TVariable &variable = node->variable();
+ TQualifier qualifier = variable.getType().getQualifier();
+
+ if (qualifier == EvqBuffer)
+ {
+ const TType &variableType = variable.getType();
+ const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
+ ASSERT(interfaceBlock);
+ if (mReferencedShaderStorageBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ const TVariable *instanceVariable = nullptr;
+ if (variableType.isInterfaceBlock())
+ {
+ instanceVariable = &variable;
+ }
+ mReferencedShaderStorageBlocks[interfaceBlock->uniqueId().get()] =
+ new TReferencedBlock(interfaceBlock, instanceVariable);
+ GetShaderStorageBlockMembersInfo(interfaceBlock, mShaderStorageBlocks,
+ &mBlockMemberInfoMap);
+ }
+ if (variableType.isInterfaceBlock())
+ {
+ out << DecorateVariableIfNeeded(variable);
+ }
+ else
+ {
+ out << Decorate(interfaceBlock->name());
+ out << ", ";
+
+ const TField *field =
+ GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name());
+ writeDotOperatorOutput(out, field);
+ }
+ }
+ else
+ {
+ return mOutputHLSL->visitSymbol(node);
+ }
+}
+
+void ShaderStorageBlockOutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
+{
+ mOutputHLSL->visitConstantUnion(node);
+}
+
+bool ShaderStorageBlockOutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ return mOutputHLSL->visitAggregate(visit, node);
+}
+
+bool ShaderStorageBlockOutputHLSL::visitTernary(Visit visit, TIntermTernary *node)
+{
+ return mOutputHLSL->visitTernary(visit, node);
+}
+
+bool ShaderStorageBlockOutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
+{
+ return mOutputHLSL->visitUnary(visit, node);
+}
+
+bool ShaderStorageBlockOutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+ if (visit == PostVisit)
+ {
+ if (!IsInShaderStorageBlock(node))
+ {
+ return mOutputHLSL->visitSwizzle(visit, node);
+ }
+
+ TInfoSinkBase &out = mOutputHLSL->getInfoSink();
+ // TODO(jiajia.qin@intel.com): add swizzle process if the swizzle node is not the last node
+ // of ssbo access chain. Such as, data.xy[0]
+ if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
+ {
+ out << ")";
+ }
+ }
+ return true;
+}
+
+bool ShaderStorageBlockOutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getInfoSink();
+
+ switch (node->getOp())
+ {
+ case EOpIndexDirect:
+ {
+ if (!IsInShaderStorageBlock(node->getLeft()))
+ {
+ return mOutputHLSL->visitBinary(visit, node);
+ }
+
+ const TType &leftType = node->getLeft()->getType();
+ if (leftType.isInterfaceBlock())
+ {
+ if (visit == PreVisit)
+ {
+ ASSERT(leftType.getQualifier() == EvqBuffer);
+ TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
+ const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
+
+ if (mReferencedShaderStorageBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ mReferencedShaderStorageBlocks[interfaceBlock->uniqueId().get()] =
+ new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
+ GetShaderStorageBlockMembersInfo(interfaceBlock, mShaderStorageBlocks,
+ &mBlockMemberInfoMap);
+ }
+
+ const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
+ out << mResourcesHLSL->InterfaceBlockInstanceString(
+ instanceArraySymbol->getName(), arrayIndex);
+ return false;
+ }
+ }
+ else
+ {
+ writeEOpIndexDirectOrIndirectOutput(out, visit, node);
+ }
+ break;
+ }
+ case EOpIndexIndirect:
+ {
+ if (!IsInShaderStorageBlock(node->getLeft()))
+ {
+ return mOutputHLSL->visitBinary(visit, node);
+ }
+
+ // We do not currently support indirect references to interface blocks
+ ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
+ writeEOpIndexDirectOrIndirectOutput(out, visit, node);
+ break;
+ }
+ case EOpIndexDirectStruct:
+ {
+ if (!IsInShaderStorageBlock(node->getLeft()))
+ {
+ return mOutputHLSL->visitBinary(visit, node);
+ }
+
+ if (visit == InVisit)
+ {
+ ASSERT(IsInShaderStorageBlock(node->getLeft()));
+ const TStructure *structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+ out << " + ";
+ writeDotOperatorOutput(out, field);
+ return false;
+ }
+ break;
+ }
+ case EOpIndexDirectInterfaceBlock:
+ if (!IsInShaderStorageBlock(node->getLeft()))
+ {
+ return mOutputHLSL->visitBinary(visit, node);
+ }
+
+ if (visit == InVisit)
+ {
+ ASSERT(IsInShaderStorageBlock(node->getLeft()));
+ out << ", ";
+ const TInterfaceBlock *interfaceBlock =
+ node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+ writeDotOperatorOutput(out, field);
+ return false;
+ }
+ break;
+ default:
+ // It may have other operators in EOpIndexIndirect. Such as buffer.attribs[(y * gridSize
+ // + x) * 6u + 0u]
+ return mOutputHLSL->visitBinary(visit, node);
+ }
+
+ return true;
+}
+
+void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out,
+ Visit visit,
+ TIntermBinary *node)
+{
+ ASSERT(IsInShaderStorageBlock(node->getLeft()));
+ if (visit == InVisit)
+ {
+ const TType &type = node->getLeft()->getType();
+ // For array of arrays, we calculate the offset using the formula below:
+ // elementStride * (a3 * a2 * a1 * i0 + a3 * a2 * i1 + a3 * i2 + i3)
+ // Note: assume that there are 4 dimensions.
+ // a0, a1, a2, a3 is the size of the array in each dimension. (S s[a0][a1][a2][a3])
+ // i0, i1, i2, i3 is the index of the array in each dimension. (s[i0][i1][i2][i3])
+ if (IsInArrayOfArraysChain(node->getLeft()))
+ {
+ if (type.isArrayOfArrays())
+ {
+ const TVector<unsigned int> &arraySizes = *type.getArraySizes();
+ // Don't need to concern the tail comma which will be used to multiply the index.
+ for (unsigned int i = 0; i < (arraySizes.size() - 1); i++)
+ {
+ out << arraySizes[i];
+ out << " * ";
+ }
+ }
+ }
+ else
+ {
+ if (node->getType().isVector() && type.isMatrix())
+ {
+ if (mRowMajor)
+ {
+ out << " + " << str(BlockLayoutEncoder::kBytesPerComponent);
+ }
+ else
+ {
+ out << " + " << str(mMatrixStride);
+ }
+ }
+ else if (node->getType().isScalar() && !type.isArray())
+ {
+ if (mRowMajor)
+ {
+ out << " + " << str(mMatrixStride);
+ }
+ else
+ {
+ out << " + " << str(BlockLayoutEncoder::kBytesPerComponent);
+ }
+ }
+
+ out << " * ";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ // This is used to output the '+' in the array of arrays formula in above.
+ if (node->getType().isArray() && !isEndOfSSBOAccessChain())
+ {
+ out << " + ";
+ }
+ // This corresponds to '(' in writeDotOperatorOutput when fieldType.isArrayOfArrays() is
+ // true.
+ if (IsInArrayOfArraysChain(node->getLeft()) && !node->getType().isArray())
+ {
+ out << ")";
+ }
+ if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
+ {
+ out << ")";
+ }
+ }
+}
+
+void ShaderStorageBlockOutputHLSL::writeDotOperatorOutput(TInfoSinkBase &out, const TField *field)
+{
+ auto fieldInfoIter = mBlockMemberInfoMap.find(field);
+ ASSERT(fieldInfoIter != mBlockMemberInfoMap.end());
+ const BlockMemberInfo &memberInfo = fieldInfoIter->second;
+ mMatrixStride = memberInfo.matrixStride;
+ mRowMajor = memberInfo.isRowMajorMatrix;
+ out << memberInfo.offset;
+
+ const TType &fieldType = *field->type();
+ if (fieldType.isArray() && !isEndOfSSBOAccessChain())
+ {
+ out << " + ";
+ out << memberInfo.arrayStride;
+ if (fieldType.isArrayOfArrays())
+ {
+ out << " * (";
+ }
+ }
+ if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
+ {
+ out << ")";
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h
new file mode 100644
index 0000000000..2ef2364129
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h
@@ -0,0 +1,92 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ShaderStorageBlockOutputHLSL: A traverser to translate a buffer variable of shader storage block
+// to an offset of RWByteAddressBuffer.
+//
+
+#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
+#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
+
+#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h"
+#include "compiler/translator/blocklayout.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+class ResourcesHLSL;
+class OutputHLSL;
+class TSymbolTable;
+
+struct TReferencedBlock : angle::NonCopyable
+{
+ POOL_ALLOCATOR_NEW_DELETE
+ TReferencedBlock(const TInterfaceBlock *block, const TVariable *instanceVariable);
+ const TInterfaceBlock *block;
+ const TVariable *instanceVariable; // May be nullptr if the block is not instanced.
+};
+
+// Maps from uniqueId to a variable.
+using ReferencedInterfaceBlocks = std::map<int, const TReferencedBlock *>;
+
+// Used to save shader storage block field member information.
+using BlockMemberInfoMap = std::map<const TField *, BlockMemberInfo>;
+
+using ShaderVarToFieldMap = std::map<std::string, const TField *>;
+
+class ShaderStorageBlockOutputHLSL : public TIntermTraverser
+{
+ public:
+ ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLSL,
+ TSymbolTable *symbolTable,
+ ResourcesHLSL *resourcesHLSL,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks);
+
+ ~ShaderStorageBlockOutputHLSL();
+
+ // This writes part of the function call to store a value to a SSBO to the output stream. After
+ // calling this, ", <stored value>)" should be written to the output stream to complete the
+ // function call.
+ void outputStoreFunctionCallPrefix(TIntermTyped *node);
+ // This writes the function call to load a SSBO value to the output stream.
+ void outputLoadFunctionCall(TIntermTyped *node);
+ // This writes the function call to get the lengh of unsized array member of SSBO.
+ void outputLengthFunctionCall(TIntermTyped *node);
+ // Writes the atomic memory function calls for SSBO.
+ void outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node, TOperator op);
+
+ void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const;
+
+ protected:
+ void visitSymbol(TIntermSymbol *) override;
+ void visitConstantUnion(TIntermConstantUnion *) override;
+ bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *) override;
+ bool visitUnary(Visit visit, TIntermUnary *) override;
+
+ private:
+ void traverseSSBOAccess(TIntermTyped *node, SSBOMethod method);
+ void setMatrixStride(TIntermTyped *node, TLayoutBlockStorage storage, bool rowMajor);
+ bool isEndOfSSBOAccessChain();
+ void writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out, Visit visit, TIntermBinary *node);
+ // Common part in dot operations.
+ void writeDotOperatorOutput(TInfoSinkBase &out, const TField *field);
+
+ int mMatrixStride;
+ bool mRowMajor;
+ bool mLocationAsTheLastArgument;
+ OutputHLSL *mOutputHLSL;
+ ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL;
+ ResourcesHLSL *mResourcesHLSL;
+ ReferencedInterfaceBlocks mReferencedShaderStorageBlocks;
+
+ BlockMemberInfoMap mBlockMemberInfoMap;
+ const std::vector<InterfaceBlock> &mShaderStorageBlocks;
+};
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp
new file mode 100644
index 0000000000..202ed21119
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp
@@ -0,0 +1,582 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ShaderVars.cpp:
+// Methods for GL variable types (varyings, uniforms, etc)
+//
+
+#include <GLSLANG/ShaderLang.h>
+
+#include "common/debug.h"
+#include "common/utilities.h"
+
+namespace sh
+{
+
+namespace
+{
+
+InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation)
+{
+ return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation);
+}
+} // namespace
+// The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion
+// on Khronos.org, clarifies that a smooth/flat mismatch produces a link error,
+// but auxiliary qualifier mismatch (centroid) does not.
+bool InterpolationTypesMatch(InterpolationType a, InterpolationType b)
+{
+ return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b));
+}
+
+ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {}
+
+ShaderVariable::ShaderVariable(GLenum typeIn)
+ : type(typeIn),
+ precision(0),
+ staticUse(false),
+ active(false),
+ isRowMajorLayout(false),
+ flattenedOffsetInParentArrays(-1)
+{}
+
+ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
+{
+ ASSERT(arraySizeIn != 0);
+ arraySizes.push_back(arraySizeIn);
+}
+
+ShaderVariable::~ShaderVariable() {}
+
+ShaderVariable::ShaderVariable(const ShaderVariable &other)
+ : type(other.type),
+ precision(other.precision),
+ name(other.name),
+ mappedName(other.mappedName),
+ arraySizes(other.arraySizes),
+ staticUse(other.staticUse),
+ active(other.active),
+ fields(other.fields),
+ structName(other.structName),
+ isRowMajorLayout(other.isRowMajorLayout),
+ flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
+{}
+
+ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
+{
+ type = other.type;
+ precision = other.precision;
+ name = other.name;
+ mappedName = other.mappedName;
+ arraySizes = other.arraySizes;
+ staticUse = other.staticUse;
+ active = other.active;
+ fields = other.fields;
+ structName = other.structName;
+ isRowMajorLayout = other.isRowMajorLayout;
+ flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
+ return *this;
+}
+
+bool ShaderVariable::operator==(const ShaderVariable &other) const
+{
+ if (type != other.type || precision != other.precision || name != other.name ||
+ mappedName != other.mappedName || arraySizes != other.arraySizes ||
+ staticUse != other.staticUse || active != other.active ||
+ fields.size() != other.fields.size() || structName != other.structName ||
+ isRowMajorLayout != other.isRowMajorLayout)
+ {
+ return false;
+ }
+ for (size_t ii = 0; ii < fields.size(); ++ii)
+ {
+ if (fields[ii] != other.fields[ii])
+ return false;
+ }
+ return true;
+}
+
+void ShaderVariable::setArraySize(unsigned int size)
+{
+ arraySizes.clear();
+ if (size != 0)
+ {
+ arraySizes.push_back(size);
+ }
+}
+
+unsigned int ShaderVariable::getInnerArraySizeProduct() const
+{
+ unsigned int arraySizeProduct = 1u;
+ for (size_t index = 1; index < arraySizes.size(); ++index)
+ {
+ arraySizeProduct *= getNestedArraySize(index);
+ }
+ return arraySizeProduct;
+}
+
+unsigned int ShaderVariable::getArraySizeProduct() const
+{
+ return gl::ArraySizeProduct(arraySizes);
+}
+
+void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
+{
+ ASSERT(isArray());
+ flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
+ arraySizes.pop_back();
+}
+
+unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
+{
+ ASSERT(arraySizes.size() > arrayNestingIndex);
+ return arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
+}
+
+unsigned int ShaderVariable::getBasicTypeElementCount() const
+{
+ // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
+ // for each array element when dealing with an array of arrays or an array of structs.
+ ASSERT(!isArrayOfArrays());
+ ASSERT(!isStruct() || !isArray());
+
+ // GLES 3.1 Nov 2016 page 82.
+ if (isArray())
+ {
+ return getOutermostArraySize();
+ }
+ return 1u;
+}
+
+bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
+ const ShaderVariable **leafVar,
+ std::string *originalFullName) const
+{
+ ASSERT(leafVar && originalFullName);
+ // There are three cases:
+ // 1) the top variable is of struct type;
+ // 2) the top variable is an array;
+ // 3) otherwise.
+ size_t pos = mappedFullName.find_first_of(".[");
+
+ if (pos == std::string::npos)
+ {
+ // Case 3.
+ if (mappedFullName != this->mappedName)
+ return false;
+ *originalFullName = this->name;
+ *leafVar = this;
+ return true;
+ }
+ else
+ {
+ std::string topName = mappedFullName.substr(0, pos);
+ if (topName != this->mappedName)
+ return false;
+ std::string originalName = this->name;
+ std::string remaining;
+ if (mappedFullName[pos] == '[')
+ {
+ // Case 2.
+ size_t closePos = mappedFullName.find_first_of(']');
+ if (closePos < pos || closePos == std::string::npos)
+ return false;
+ // Append '[index]'.
+ originalName += mappedFullName.substr(pos, closePos - pos + 1);
+ if (closePos + 1 == mappedFullName.size())
+ {
+ *originalFullName = originalName;
+ *leafVar = this;
+ return true;
+ }
+ else
+ {
+ // In the form of 'a[0].b', so after ']', '.' is expected.
+ if (mappedFullName[closePos + 1] != '.')
+ return false;
+ remaining = mappedFullName.substr(closePos + 2); // Skip "]."
+ }
+ }
+ else
+ {
+ // Case 1.
+ remaining = mappedFullName.substr(pos + 1); // Skip "."
+ }
+ for (size_t ii = 0; ii < this->fields.size(); ++ii)
+ {
+ const ShaderVariable *fieldVar = nullptr;
+ std::string originalFieldName;
+ bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName);
+ if (found)
+ {
+ *originalFullName = originalName + "." + originalFieldName;
+ *leafVar = fieldVar;
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+bool ShaderVariable::isBuiltIn() const
+{
+ return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
+}
+
+bool ShaderVariable::isEmulatedBuiltIn() const
+{
+ return isBuiltIn() && name != mappedName;
+}
+
+bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
+ bool matchPrecision,
+ bool matchName) const
+{
+ if (type != other.type)
+ return false;
+ if (matchPrecision && precision != other.precision)
+ return false;
+ if (matchName && name != other.name)
+ return false;
+ ASSERT(!matchName || mappedName == other.mappedName);
+ if (arraySizes != other.arraySizes)
+ return false;
+ if (isRowMajorLayout != other.isRowMajorLayout)
+ return false;
+ if (fields.size() != other.fields.size())
+ return false;
+
+ // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
+ // Variables declared as structures are considered to match in type if and only if structure
+ // members match in name, type, qualification, and declaration order.
+ for (size_t ii = 0; ii < fields.size(); ++ii)
+ {
+ if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
+ {
+ return false;
+ }
+ }
+ if (structName != other.structName)
+ return false;
+ return true;
+}
+
+Uniform::Uniform()
+ : binding(-1), imageUnitFormat(GL_NONE), offset(-1), readonly(false), writeonly(false)
+{}
+
+Uniform::~Uniform() {}
+
+Uniform::Uniform(const Uniform &other)
+ : VariableWithLocation(other),
+ binding(other.binding),
+ imageUnitFormat(other.imageUnitFormat),
+ offset(other.offset),
+ readonly(other.readonly),
+ writeonly(other.writeonly)
+{}
+
+Uniform &Uniform::operator=(const Uniform &other)
+{
+ VariableWithLocation::operator=(other);
+ binding = other.binding;
+ imageUnitFormat = other.imageUnitFormat;
+ offset = other.offset;
+ readonly = other.readonly;
+ writeonly = other.writeonly;
+ return *this;
+}
+
+bool Uniform::operator==(const Uniform &other) const
+{
+ return VariableWithLocation::operator==(other) && binding == other.binding &&
+ imageUnitFormat == other.imageUnitFormat && offset == other.offset &&
+ readonly == other.readonly && writeonly == other.writeonly;
+}
+
+bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
+{
+ // Enforce a consistent match.
+ // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
+ if (binding != -1 && other.binding != -1 && binding != other.binding)
+ {
+ return false;
+ }
+ if (imageUnitFormat != other.imageUnitFormat)
+ {
+ return false;
+ }
+ if (location != -1 && other.location != -1 && location != other.location)
+ {
+ return false;
+ }
+ if (offset != other.offset)
+ {
+ return false;
+ }
+ if (readonly != other.readonly || writeonly != other.writeonly)
+ {
+ return false;
+ }
+ return VariableWithLocation::isSameVariableAtLinkTime(other, true, true);
+}
+
+VariableWithLocation::VariableWithLocation() : location(-1) {}
+
+VariableWithLocation::~VariableWithLocation() {}
+
+VariableWithLocation::VariableWithLocation(const VariableWithLocation &other)
+ : ShaderVariable(other), location(other.location)
+{}
+
+VariableWithLocation &VariableWithLocation::operator=(const VariableWithLocation &other)
+{
+ ShaderVariable::operator=(other);
+ location = other.location;
+ return *this;
+}
+
+bool VariableWithLocation::operator==(const VariableWithLocation &other) const
+{
+ return (ShaderVariable::operator==(other) && location == other.location);
+}
+
+Attribute::Attribute() {}
+
+Attribute::~Attribute() {}
+
+Attribute::Attribute(const Attribute &other) : VariableWithLocation(other) {}
+
+Attribute &Attribute::operator=(const Attribute &other)
+{
+ VariableWithLocation::operator=(other);
+ return *this;
+}
+
+bool Attribute::operator==(const Attribute &other) const
+{
+ return VariableWithLocation::operator==(other);
+}
+
+OutputVariable::OutputVariable() : index(-1) {}
+
+OutputVariable::~OutputVariable() {}
+
+OutputVariable::OutputVariable(const OutputVariable &other) = default;
+OutputVariable &OutputVariable::operator=(const OutputVariable &other) = default;
+
+bool OutputVariable::operator==(const OutputVariable &other) const
+{
+ return VariableWithLocation::operator==(other) && index == other.index;
+}
+
+InterfaceBlockField::InterfaceBlockField() {}
+
+InterfaceBlockField::~InterfaceBlockField() {}
+
+InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) : ShaderVariable(other)
+{}
+
+InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
+{
+ ShaderVariable::operator=(other);
+ return *this;
+}
+
+bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
+{
+ return ShaderVariable::operator==(other);
+}
+
+bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
+ const InterfaceBlockField &other) const
+{
+ return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
+}
+
+Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {}
+
+Varying::~Varying() {}
+
+Varying::Varying(const Varying &other)
+ : VariableWithLocation(other),
+ interpolation(other.interpolation),
+ isInvariant(other.isInvariant)
+{}
+
+Varying &Varying::operator=(const Varying &other)
+{
+ VariableWithLocation::operator=(other);
+ interpolation = other.interpolation;
+ isInvariant = other.isInvariant;
+ return *this;
+}
+
+bool Varying::operator==(const Varying &other) const
+{
+ return (VariableWithLocation::operator==(other) && interpolation == other.interpolation &&
+ isInvariant == other.isInvariant);
+}
+
+bool Varying::isSameVaryingAtLinkTime(const Varying &other) const
+{
+ return isSameVaryingAtLinkTime(other, 100);
+}
+
+bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const
+{
+ return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
+ InterpolationTypesMatch(interpolation, other.interpolation) &&
+ (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
+ (location == other.location) &&
+ (name == other.name || (shaderVersion >= 310 && location >= 0)));
+}
+
+InterfaceBlock::InterfaceBlock()
+ : arraySize(0),
+ layout(BLOCKLAYOUT_PACKED),
+ isRowMajorLayout(false),
+ binding(-1),
+ staticUse(false),
+ active(false),
+ blockType(BlockType::BLOCK_UNIFORM)
+{}
+
+InterfaceBlock::~InterfaceBlock() {}
+
+InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
+ : name(other.name),
+ mappedName(other.mappedName),
+ instanceName(other.instanceName),
+ arraySize(other.arraySize),
+ layout(other.layout),
+ isRowMajorLayout(other.isRowMajorLayout),
+ binding(other.binding),
+ staticUse(other.staticUse),
+ active(other.active),
+ blockType(other.blockType),
+ fields(other.fields)
+{}
+
+InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
+{
+ name = other.name;
+ mappedName = other.mappedName;
+ instanceName = other.instanceName;
+ arraySize = other.arraySize;
+ layout = other.layout;
+ isRowMajorLayout = other.isRowMajorLayout;
+ binding = other.binding;
+ staticUse = other.staticUse;
+ active = other.active;
+ blockType = other.blockType;
+ fields = other.fields;
+ return *this;
+}
+
+std::string InterfaceBlock::fieldPrefix() const
+{
+ return instanceName.empty() ? "" : name;
+}
+
+std::string InterfaceBlock::fieldMappedPrefix() const
+{
+ return instanceName.empty() ? "" : mappedName;
+}
+
+bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
+{
+ if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
+ layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
+ binding != other.binding || blockType != other.blockType ||
+ fields.size() != other.fields.size())
+ {
+ return false;
+ }
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
+ {
+ if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool InterfaceBlock::isBuiltIn() const
+{
+ return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
+}
+
+void WorkGroupSize::fill(int fillValue)
+{
+ localSizeQualifiers[0] = fillValue;
+ localSizeQualifiers[1] = fillValue;
+ localSizeQualifiers[2] = fillValue;
+}
+
+void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
+{
+ localSizeQualifiers[0] = localSizeX;
+ localSizeQualifiers[1] = localSizeY;
+ localSizeQualifiers[2] = localSizeZ;
+}
+
+// check that if one of them is less than 1, then all of them are.
+// Or if one is positive, then all of them are positive.
+bool WorkGroupSize::isLocalSizeValid() const
+{
+ return (
+ (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
+ (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
+}
+
+bool WorkGroupSize::isAnyValueSet() const
+{
+ return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
+}
+
+bool WorkGroupSize::isDeclared() const
+{
+ bool localSizeDeclared = localSizeQualifiers[0] > 0;
+ ASSERT(isLocalSizeValid());
+ return localSizeDeclared;
+}
+
+bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
+{
+ for (size_t i = 0u; i < size(); ++i)
+ {
+ bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
+ (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
+ (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
+ if (!result)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+int &WorkGroupSize::operator[](size_t index)
+{
+ ASSERT(index < size());
+ return localSizeQualifiers[index];
+}
+
+int WorkGroupSize::operator[](size_t index) const
+{
+ ASSERT(index < size());
+ return localSizeQualifiers[index];
+}
+
+size_t WorkGroupSize::size() const
+{
+ return 3u;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/StaticType.h b/gfx/angle/checkout/src/compiler/translator/StaticType.h
new file mode 100644
index 0000000000..6ecb24fbc9
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/StaticType.h
@@ -0,0 +1,202 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Compile-time instances of many common TType values. These are looked up
+// (statically or dynamically) through the methods defined in the namespace.
+//
+
+#ifndef COMPILER_TRANSLATOR_STATIC_TYPE_H_
+#define COMPILER_TRANSLATOR_STATIC_TYPE_H_
+
+#include "compiler/translator/Types.h"
+
+namespace sh
+{
+
+namespace StaticType
+{
+
+namespace Helpers
+{
+
+//
+// Generation and static allocation of type mangled name values.
+//
+
+// Size of the constexpr-generated mangled name.
+// If this value is too small, the compiler will produce errors.
+static constexpr size_t kStaticMangledNameLength = 2;
+
+// Type which holds the mangled names for constexpr-generated TTypes.
+// This simple struct is needed so that a char array can be returned by value.
+struct StaticMangledName
+{
+ // If this array is too small, the compiler will produce errors.
+ char name[kStaticMangledNameLength + 1] = {};
+};
+
+// Generates a mangled name for a TType given its parameters.
+constexpr StaticMangledName BuildStaticMangledName(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize)
+{
+ StaticMangledName name = {};
+ name.name[0] = TType::GetSizeMangledName(primarySize, secondarySize);
+ name.name[1] = GetBasicMangledName(basicType);
+ name.name[2] = '\0';
+ return name;
+}
+
+// This "variable" contains the mangled names for every constexpr-generated TType.
+// If kMangledNameInstance<B, P, Q, PS, SS> is used anywhere (specifally
+// in instance, below), this is where the appropriate type will be stored.
+template <TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize>
+static constexpr StaticMangledName kMangledNameInstance =
+ BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize);
+
+//
+// Generation and static allocation of TType values.
+//
+
+// This "variable" contains every constexpr-generated TType.
+// If instance<B, P, Q, PS, SS> is used anywhere (specifally
+// in Get, below), this is where the appropriate type will be stored.
+//
+// TODO(crbug.com/981610): This is constexpr but doesn't follow the kConstant naming convention
+// because TType has a mutable member that prevents it from being in .data.rel.ro and makes the
+// Android Binary Size builder complain when ANGLE is rolled in Chromium.
+template <TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize>
+static constexpr TType instance =
+ TType(basicType,
+ precision,
+ qualifier,
+ primarySize,
+ secondarySize,
+ kMangledNameInstance<basicType, precision, qualifier, primarySize, secondarySize>.name);
+
+} // namespace Helpers
+
+//
+// Fully-qualified type lookup.
+//
+
+template <TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize>
+constexpr const TType *Get()
+{
+ static_assert(1 <= primarySize && primarySize <= 4, "primarySize out of bounds");
+ static_assert(1 <= secondarySize && secondarySize <= 4, "secondarySize out of bounds");
+ return &Helpers::instance<basicType, precision, qualifier, primarySize, secondarySize>;
+}
+
+//
+// Overloads
+//
+
+template <TBasicType basicType, unsigned char primarySize = 1, unsigned char secondarySize = 1>
+constexpr const TType *GetBasic()
+{
+ return Get<basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize>();
+}
+
+template <TBasicType basicType,
+ TQualifier qualifier,
+ unsigned char primarySize = 1,
+ unsigned char secondarySize = 1>
+const TType *GetQualified()
+{
+ return Get<basicType, EbpUndefined, qualifier, primarySize, secondarySize>();
+}
+
+// Dynamic lookup methods (convert runtime values to template args)
+
+namespace Helpers
+{
+
+// Helper which takes secondarySize statically but primarySize dynamically.
+template <TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char secondarySize>
+constexpr const TType *GetForVecMatHelper(unsigned char primarySize)
+{
+ static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
+ basicType == EbtBool,
+ "unsupported basicType");
+ switch (primarySize)
+ {
+ case 1:
+ return Get<basicType, precision, qualifier, 1, secondarySize>();
+ case 2:
+ return Get<basicType, precision, qualifier, 2, secondarySize>();
+ case 3:
+ return Get<basicType, precision, qualifier, 3, secondarySize>();
+ case 4:
+ return Get<basicType, precision, qualifier, 4, secondarySize>();
+ default:
+ UNREACHABLE();
+ return GetBasic<EbtVoid>();
+ }
+}
+
+} // namespace Helpers
+
+template <TBasicType basicType,
+ TPrecision precision = EbpUndefined,
+ TQualifier qualifier = EvqGlobal>
+constexpr const TType *GetForVecMat(unsigned char primarySize, unsigned char secondarySize = 1)
+{
+ static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
+ basicType == EbtBool,
+ "unsupported basicType");
+ switch (secondarySize)
+ {
+ case 1:
+ return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 1>(primarySize);
+ case 2:
+ return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 2>(primarySize);
+ case 3:
+ return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 3>(primarySize);
+ case 4:
+ return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 4>(primarySize);
+ default:
+ UNREACHABLE();
+ return GetBasic<EbtVoid>();
+ }
+}
+
+template <TBasicType basicType, TPrecision precision = EbpUndefined>
+constexpr const TType *GetForVec(TQualifier qualifier, unsigned char size)
+{
+ switch (qualifier)
+ {
+ case EvqGlobal:
+ return Helpers::GetForVecMatHelper<basicType, precision, EvqGlobal, 1>(size);
+ case EvqOut:
+ return Helpers::GetForVecMatHelper<basicType, precision, EvqOut, 1>(size);
+ default:
+ UNREACHABLE();
+ return GetBasic<EbtVoid>();
+ }
+}
+
+} // namespace StaticType
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_STATIC_TYPE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp
new file mode 100644
index 0000000000..172ca07fc0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp
@@ -0,0 +1,591 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// StructureHLSL.cpp:
+// HLSL translation of GLSL constructors and structures.
+//
+
+#include "compiler/translator/StructureHLSL.h"
+#include "common/utilities.h"
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/Types.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+TString Define(const TStructure &structure,
+ bool useHLSLRowMajorPacking,
+ bool useStd140Packing,
+ Std140PaddingHelper *padHelper)
+{
+ const TFieldList &fields = structure.fields();
+ const bool isNameless = (structure.symbolType() == SymbolType::Empty);
+ const TString &structName =
+ QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
+ const TString declareString = (isNameless ? "struct" : "struct " + structName);
+
+ TString string;
+ string += declareString +
+ "\n"
+ "{\n";
+
+ for (const TField *field : fields)
+ {
+ const TType &fieldType = *field->type();
+ if (!IsSampler(fieldType.getBasicType()))
+ {
+ const TStructure *fieldStruct = fieldType.getStruct();
+ const TString &fieldTypeString =
+ fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
+ useStd140Packing)
+ : TypeString(fieldType);
+
+ if (padHelper)
+ {
+ string += padHelper->prePaddingString(fieldType);
+ }
+
+ string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
+ ArrayString(fieldType).data() + ";\n";
+
+ if (padHelper)
+ {
+ string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
+ }
+ }
+ }
+
+ // Nameless structs do not finish with a semicolon and newline, to leave room for an instance
+ // variable
+ string += (isNameless ? "} " : "};\n");
+
+ return string;
+}
+
+TString WriteParameterList(const std::vector<TType> &parameters)
+{
+ TString parameterList;
+ for (size_t parameter = 0u; parameter < parameters.size(); parameter++)
+ {
+ const TType &paramType = parameters[parameter];
+
+ parameterList +=
+ TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType).data();
+
+ if (parameter < parameters.size() - 1u)
+ {
+ parameterList += ", ";
+ }
+ }
+ return parameterList;
+}
+
+} // anonymous namespace
+
+Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
+ unsigned *uniqueCounter)
+ : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes)
+{}
+
+Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other)
+ : mPaddingCounter(other.mPaddingCounter),
+ mElementIndex(other.mElementIndex),
+ mStructElementIndexes(other.mStructElementIndexes)
+{}
+
+Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other)
+{
+ mPaddingCounter = other.mPaddingCounter;
+ mElementIndex = other.mElementIndex;
+ mStructElementIndexes = other.mStructElementIndexes;
+ return *this;
+}
+
+TString Std140PaddingHelper::next()
+{
+ unsigned value = (*mPaddingCounter)++;
+ return str(value);
+}
+
+int Std140PaddingHelper::prePadding(const TType &type)
+{
+ if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
+ {
+ // no padding needed, HLSL will align the field to a new register
+ mElementIndex = 0;
+ return 0;
+ }
+
+ const GLenum glType = GLVariableType(type);
+ const int numComponents = gl::VariableComponentCount(glType);
+
+ if (numComponents >= 4)
+ {
+ // no padding needed, HLSL will align the field to a new register
+ mElementIndex = 0;
+ return 0;
+ }
+
+ if (mElementIndex + numComponents > 4)
+ {
+ // no padding needed, HLSL will align the field to a new register
+ mElementIndex = numComponents;
+ return 0;
+ }
+
+ const int alignment = numComponents == 3 ? 4 : numComponents;
+ const int paddingOffset = (mElementIndex % alignment);
+ const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
+
+ mElementIndex += paddingCount;
+ mElementIndex += numComponents;
+ mElementIndex %= 4;
+
+ return paddingCount;
+}
+
+TString Std140PaddingHelper::prePaddingString(const TType &type)
+{
+ int paddingCount = prePadding(type);
+
+ TString padding;
+
+ for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
+ {
+ padding += " float pad_" + next() + ";\n";
+ }
+
+ return padding;
+}
+
+TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
+{
+ if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
+ {
+ return "";
+ }
+
+ int numComponents = 0;
+ const TStructure *structure = type.getStruct();
+
+ if (type.isMatrix())
+ {
+ // This method can also be called from structureString, which does not use layout
+ // qualifiers.
+ // Thus, use the method parameter for determining the matrix packing.
+ //
+ // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
+ // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
+ //
+ const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
+ const GLenum glType = GLVariableType(type);
+ numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
+ }
+ else if (structure)
+ {
+ const TString &structName =
+ QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true);
+ numComponents = mStructElementIndexes->find(structName)->second;
+
+ if (numComponents == 0)
+ {
+ return "";
+ }
+ }
+ else
+ {
+ const GLenum glType = GLVariableType(type);
+ numComponents = gl::VariableComponentCount(glType);
+ }
+
+ TString padding;
+ for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
+ {
+ padding += " float pad_" + next() + ";\n";
+ }
+ return padding;
+}
+
+StructureHLSL::StructureHLSL() : mUniquePaddingCounter(0) {}
+
+Std140PaddingHelper StructureHLSL::getPaddingHelper()
+{
+ return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
+}
+
+TString StructureHLSL::defineQualified(const TStructure &structure,
+ bool useHLSLRowMajorPacking,
+ bool useStd140Packing)
+{
+ if (useStd140Packing)
+ {
+ Std140PaddingHelper padHelper = getPaddingHelper();
+ return Define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
+ }
+ else
+ {
+ return Define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr);
+ }
+}
+
+TString StructureHLSL::defineNameless(const TStructure &structure)
+{
+ return Define(structure, false, false, nullptr);
+}
+
+StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure,
+ const TString &name)
+{
+ ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end());
+
+ for (const TField *field : structure.fields())
+ {
+ const TType *fieldType = field->type();
+ if (fieldType->getBasicType() == EbtStruct)
+ {
+ ensureStructDefined(*fieldType->getStruct());
+ }
+ }
+
+ DefinedStructs::iterator addedStruct =
+ mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first;
+ // Add element index
+ storeStd140ElementIndex(structure, false);
+ storeStd140ElementIndex(structure, true);
+
+ const TString &structString = defineQualified(structure, false, false);
+
+ ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) ==
+ mStructDeclarations.end());
+ // Add row-major packed struct for interface blocks
+ TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
+ defineQualified(structure, true, false) +
+ "#pragma pack_matrix(column_major)\n";
+
+ TString std140String = defineQualified(structure, false, true);
+ TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
+ defineQualified(structure, true, true) +
+ "#pragma pack_matrix(column_major)\n";
+
+ mStructDeclarations.push_back(structString);
+ mStructDeclarations.push_back(rowMajorString);
+ mStructDeclarations.push_back(std140String);
+ mStructDeclarations.push_back(std140RowMajorString);
+ return addedStruct;
+}
+
+void StructureHLSL::ensureStructDefined(const TStructure &structure)
+{
+ const TString name = StructNameString(structure);
+ if (name == "")
+ {
+ return; // Nameless structures are not defined
+ }
+ if (mDefinedStructs.find(name) == mDefinedStructs.end())
+ {
+ defineVariants(structure, name);
+ }
+}
+
+TString StructureHLSL::addStructConstructor(const TStructure &structure)
+{
+ const TString name = StructNameString(structure);
+
+ if (name == "")
+ {
+ return TString(); // Nameless structures don't have constructors
+ }
+
+ auto definedStruct = mDefinedStructs.find(name);
+ if (definedStruct == mDefinedStructs.end())
+ {
+ definedStruct = defineVariants(structure, name);
+ }
+ const TString constructorFunctionName = TString(name) + "_ctor";
+ TString *constructor = &definedStruct->second->constructor;
+ if (!constructor->empty())
+ {
+ return constructorFunctionName; // Already added
+ }
+ *constructor += name + " " + constructorFunctionName + "(";
+
+ std::vector<TType> ctorParameters;
+ const TFieldList &fields = structure.fields();
+ for (const TField *field : fields)
+ {
+ const TType *fieldType = field->type();
+ if (!IsSampler(fieldType->getBasicType()))
+ {
+ ctorParameters.push_back(*fieldType);
+ }
+ }
+ // Structs that have sampler members should not have constructor calls, and otherwise structs
+ // are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations
+ // either.
+ ASSERT(!ctorParameters.empty());
+
+ *constructor += WriteParameterList(ctorParameters);
+
+ *constructor +=
+ ")\n"
+ "{\n"
+ " " +
+ name + " structure = { ";
+
+ for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex)
+ {
+ *constructor += "x" + str(parameterIndex);
+ if (parameterIndex < ctorParameters.size() - 1u)
+ {
+ *constructor += ", ";
+ }
+ }
+ *constructor +=
+ "};\n"
+ " return structure;\n"
+ "}\n";
+
+ return constructorFunctionName;
+}
+
+TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters)
+{
+ ASSERT(!type.isArray());
+ ASSERT(type.getStruct() == nullptr);
+ ASSERT(parameters);
+
+ TType ctorType = type;
+ ctorType.setPrecision(EbpHigh);
+ ctorType.setQualifier(EvqTemporary);
+
+ const TString constructorFunctionName =
+ TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters);
+ TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "(";
+
+ std::vector<TType> ctorParameters;
+ for (auto parameter : *parameters)
+ {
+ const TType &paramType = parameter->getAsTyped()->getType();
+ ASSERT(!paramType.isArray());
+ ctorParameters.push_back(paramType);
+ }
+ constructor += WriteParameterList(ctorParameters);
+
+ constructor +=
+ ")\n"
+ "{\n"
+ " return " +
+ TypeString(ctorType) + "(";
+
+ if (ctorType.isMatrix() && ctorParameters.size() == 1)
+ {
+ int rows = ctorType.getRows();
+ int cols = ctorType.getCols();
+ const TType &parameter = ctorParameters[0];
+
+ if (parameter.isScalar())
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ for (int row = 0; row < rows; row++)
+ {
+ constructor += TString((row == col) ? "x0" : "0.0");
+
+ if (row < rows - 1 || col < cols - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else if (parameter.isMatrix())
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ for (int row = 0; row < rows; row++)
+ {
+ if (row < parameter.getRows() && col < parameter.getCols())
+ {
+ constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
+ }
+ else
+ {
+ constructor += TString((row == col) ? "1.0" : "0.0");
+ }
+
+ if (row < rows - 1 || col < cols - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else
+ {
+ ASSERT(rows == 2 && cols == 2 && parameter.isVector() &&
+ parameter.getNominalSize() == 4);
+
+ constructor += "x0";
+ }
+ }
+ else
+ {
+ size_t remainingComponents = ctorType.getObjectSize();
+ size_t parameterIndex = 0;
+
+ while (remainingComponents > 0)
+ {
+ const TType &parameter = ctorParameters[parameterIndex];
+ const size_t parameterSize = parameter.getObjectSize();
+ bool moreParameters = parameterIndex + 1 < ctorParameters.size();
+
+ constructor += "x" + str(parameterIndex);
+
+ if (parameter.isScalar())
+ {
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else if (parameter.isVector())
+ {
+ if (remainingComponents == parameterSize || moreParameters)
+ {
+ ASSERT(parameterSize <= remainingComponents);
+ remainingComponents -= parameterSize;
+ }
+ else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
+ {
+ switch (remainingComponents)
+ {
+ case 1:
+ constructor += ".x";
+ break;
+ case 2:
+ constructor += ".xy";
+ break;
+ case 3:
+ constructor += ".xyz";
+ break;
+ case 4:
+ constructor += ".xyzw";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ remainingComponents = 0;
+ }
+ else
+ UNREACHABLE();
+ }
+ else if (parameter.isMatrix())
+ {
+ int column = 0;
+ while (remainingComponents > 0 && column < parameter.getCols())
+ {
+ constructor += "[" + str(column) + "]";
+
+ if (remainingComponents < static_cast<size_t>(parameter.getRows()))
+ {
+ switch (remainingComponents)
+ {
+ case 1:
+ constructor += ".x";
+ break;
+ case 2:
+ constructor += ".xy";
+ break;
+ case 3:
+ constructor += ".xyz";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ remainingComponents = 0;
+ }
+ else
+ {
+ remainingComponents -= parameter.getRows();
+
+ if (remainingComponents > 0)
+ {
+ constructor += ", x" + str(parameterIndex);
+ }
+ }
+
+ column++;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+
+ if (moreParameters)
+ {
+ parameterIndex++;
+ }
+
+ if (remainingComponents)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+
+ constructor +=
+ ");\n"
+ "}\n";
+
+ mBuiltInConstructors.insert(constructor);
+
+ return constructorFunctionName;
+}
+
+std::string StructureHLSL::structsHeader() const
+{
+ TInfoSinkBase out;
+
+ for (auto &declaration : mStructDeclarations)
+ {
+ out << declaration;
+ }
+
+ for (auto &structure : mDefinedStructs)
+ {
+ out << structure.second->constructor;
+ }
+
+ for (auto &constructor : mBuiltInConstructors)
+ {
+ out << constructor;
+ }
+
+ return out.str();
+}
+
+void StructureHLSL::storeStd140ElementIndex(const TStructure &structure,
+ bool useHLSLRowMajorPacking)
+{
+ Std140PaddingHelper padHelper = getPaddingHelper();
+ const TFieldList &fields = structure.fields();
+
+ for (const TField *field : fields)
+ {
+ padHelper.prePadding(*field->type());
+ }
+
+ // Add remaining element index to the global map, for use with nested structs in standard
+ // layouts
+ const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
+ mStd140StructElementIndexes[structName] = padHelper.elementIndex();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/StructureHLSL.h b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.h
new file mode 100644
index 0000000000..ba4a8d11bc
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.h
@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// StructureHLSL.h:
+// HLSL translation of GLSL constructors and structures.
+//
+
+#ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_
+#define COMPILER_TRANSLATOR_STRUCTUREHLSL_H_
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/IntermNode.h"
+
+#include <set>
+
+class TInfoSinkBase;
+class TScopeBracket;
+
+namespace sh
+{
+
+// This helper class assists structure and interface block definitions in determining
+// how to pack std140 structs within HLSL's packing rules.
+class Std140PaddingHelper
+{
+ public:
+ explicit Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
+ unsigned int *uniqueCounter);
+ Std140PaddingHelper(const Std140PaddingHelper &other);
+ Std140PaddingHelper &operator=(const Std140PaddingHelper &other);
+
+ int elementIndex() const { return mElementIndex; }
+ int prePadding(const TType &type);
+ TString prePaddingString(const TType &type);
+ TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking);
+
+ private:
+ TString next();
+
+ unsigned *mPaddingCounter;
+ int mElementIndex;
+ const std::map<TString, int> *mStructElementIndexes;
+};
+
+class StructureHLSL : angle::NonCopyable
+{
+ public:
+ StructureHLSL();
+
+ // Returns the name of the constructor function.
+ TString addStructConstructor(const TStructure &structure);
+ TString addBuiltInConstructor(const TType &type, const TIntermSequence *parameters);
+
+ static TString defineNameless(const TStructure &structure);
+ void ensureStructDefined(const TStructure &structure);
+
+ std::string structsHeader() const;
+
+ Std140PaddingHelper getPaddingHelper();
+
+ private:
+ unsigned mUniquePaddingCounter;
+
+ std::map<TString, int> mStd140StructElementIndexes;
+
+ struct TStructProperties : public angle::NonCopyable
+ {
+ POOL_ALLOCATOR_NEW_DELETE
+
+ TStructProperties() {}
+
+ // Constructor is an empty string in case the struct doesn't have a constructor yet.
+ TString constructor;
+ };
+
+ // Map from struct name to struct properties.
+ typedef std::map<TString, TStructProperties *> DefinedStructs;
+ DefinedStructs mDefinedStructs;
+
+ // Struct declarations need to be kept in a vector instead of having them inside mDefinedStructs
+ // since maintaining the original order is necessary for nested structs.
+ typedef std::vector<TString> StructDeclarations;
+ StructDeclarations mStructDeclarations;
+
+ typedef std::set<TString> BuiltInConstructors;
+ BuiltInConstructors mBuiltInConstructors;
+
+ void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking);
+ TString defineQualified(const TStructure &structure,
+ bool useHLSLRowMajorPacking,
+ bool useStd140Packing);
+ DefinedStructs::iterator defineVariants(const TStructure &structure, const TString &name);
+};
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Symbol.cpp b/gfx/angle/checkout/src/compiler/translator/Symbol.cpp
new file mode 100644
index 0000000000..52ad4f319d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Symbol.cpp
@@ -0,0 +1,238 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Symbol.cpp: Symbols representing variables, functions, structures and interface blocks.
+//
+
+#if defined(_MSC_VER)
+# pragma warning(disable : 4718)
+#endif
+
+#include "compiler/translator/Symbol.h"
+
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kMainName("main");
+constexpr const ImmutableString kImageLoadName("imageLoad");
+constexpr const ImmutableString kImageStoreName("imageStore");
+constexpr const ImmutableString kImageSizeName("imageSize");
+constexpr const ImmutableString kAtomicCounterName("atomicCounter");
+
+static const char kFunctionMangledNameSeparator = '(';
+
+} // anonymous namespace
+
+TSymbol::TSymbol(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ SymbolType symbolType,
+ SymbolClass symbolClass,
+ TExtension extension)
+ : mName(name),
+ mUniqueId(symbolTable->nextUniqueId()),
+ mSymbolType(symbolType),
+ mExtension(extension),
+ mSymbolClass(symbolClass)
+{
+ ASSERT(mSymbolType == SymbolType::BuiltIn || mExtension == TExtension::UNDEFINED);
+ ASSERT(mName != "" || mSymbolType == SymbolType::AngleInternal ||
+ mSymbolType == SymbolType::Empty);
+}
+
+ImmutableString TSymbol::name() const
+{
+ if (!mName.empty())
+ {
+ return mName;
+ }
+ // This can be called for nameless function parameters in HLSL.
+ ASSERT(mSymbolType == SymbolType::AngleInternal ||
+ (mSymbolType == SymbolType::Empty && isVariable()));
+ int uniqueId = mUniqueId.get();
+ ImmutableStringBuilder symbolNameOut(sizeof(uniqueId) * 2u + 1u);
+ symbolNameOut << 's';
+ symbolNameOut.appendHex(mUniqueId.get());
+ return symbolNameOut;
+}
+
+ImmutableString TSymbol::getMangledName() const
+{
+ if (mSymbolClass == SymbolClass::Function)
+ {
+ // We do this instead of using proper virtual functions so that we can better support
+ // constexpr symbols.
+ return static_cast<const TFunction *>(this)->getFunctionMangledName();
+ }
+ ASSERT(mSymbolType != SymbolType::Empty);
+ return name();
+}
+
+TVariable::TVariable(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ const TType *type,
+ SymbolType symbolType,
+ TExtension extension)
+ : TSymbol(symbolTable, name, symbolType, SymbolClass::Variable, extension),
+ mType(type),
+ unionArray(nullptr)
+{
+ ASSERT(mType);
+ ASSERT(name.empty() || symbolType != SymbolType::Empty);
+}
+
+TStructure::TStructure(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ const TFieldList *fields,
+ SymbolType symbolType)
+ : TSymbol(symbolTable, name, symbolType, SymbolClass::Struct), TFieldListCollection(fields)
+{}
+
+TStructure::TStructure(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ TExtension extension,
+ const TFieldList *fields)
+ : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::Struct),
+ TFieldListCollection(fields)
+{}
+
+void TStructure::createSamplerSymbols(const char *namePrefix,
+ const TString &apiNamePrefix,
+ TVector<const TVariable *> *outputSymbols,
+ TMap<const TVariable *, TString> *outputSymbolsToAPINames,
+ TSymbolTable *symbolTable) const
+{
+ ASSERT(containsSamplers());
+ for (const auto *field : *mFields)
+ {
+ const TType *fieldType = field->type();
+ if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers())
+ {
+ std::stringstream fieldName = sh::InitializeStream<std::stringstream>();
+ fieldName << namePrefix << "_" << field->name();
+ TString fieldApiName = apiNamePrefix + ".";
+ fieldApiName += field->name().data();
+ fieldType->createSamplerSymbols(ImmutableString(fieldName.str()), fieldApiName,
+ outputSymbols, outputSymbolsToAPINames, symbolTable);
+ }
+ }
+}
+
+void TStructure::setName(const ImmutableString &name)
+{
+ ImmutableString *mutableName = const_cast<ImmutableString *>(&mName);
+ *mutableName = name;
+}
+
+TInterfaceBlock::TInterfaceBlock(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ const TFieldList *fields,
+ const TLayoutQualifier &layoutQualifier,
+ SymbolType symbolType,
+ TExtension extension)
+ : TSymbol(symbolTable, name, symbolType, SymbolClass::InterfaceBlock, extension),
+ TFieldListCollection(fields),
+ mBlockStorage(layoutQualifier.blockStorage),
+ mBinding(layoutQualifier.binding)
+{
+ ASSERT(name != nullptr);
+}
+
+TInterfaceBlock::TInterfaceBlock(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ TExtension extension,
+ const TFieldList *fields)
+ : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::InterfaceBlock),
+ TFieldListCollection(fields),
+ mBlockStorage(EbsUnspecified),
+ mBinding(0)
+{}
+
+TFunction::TFunction(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ SymbolType symbolType,
+ const TType *retType,
+ bool knownToNotHaveSideEffects)
+ : TSymbol(symbolTable, name, symbolType, SymbolClass::Function, TExtension::UNDEFINED),
+ mParametersVector(new TParamVector()),
+ mParameters(nullptr),
+ mParamCount(0u),
+ returnType(retType),
+ mMangledName(""),
+ mOp(EOpNull),
+ defined(false),
+ mHasPrototypeDeclaration(false),
+ mKnownToNotHaveSideEffects(knownToNotHaveSideEffects)
+{
+ // Functions with an empty name are not allowed.
+ ASSERT(symbolType != SymbolType::Empty);
+ ASSERT(name != nullptr || symbolType == SymbolType::AngleInternal);
+}
+
+void TFunction::addParameter(const TVariable *p)
+{
+ ASSERT(mParametersVector);
+ mParametersVector->push_back(p);
+ mParameters = mParametersVector->data();
+ mParamCount = mParametersVector->size();
+ mMangledName = kEmptyImmutableString;
+}
+
+void TFunction::shareParameters(const TFunction &parametersSource)
+{
+ mParametersVector = nullptr;
+ mParameters = parametersSource.mParameters;
+ mParamCount = parametersSource.mParamCount;
+ ASSERT(parametersSource.name() == name());
+ mMangledName = parametersSource.mMangledName;
+}
+
+ImmutableString TFunction::buildMangledName() const
+{
+ std::string newName(name().data(), name().length());
+ newName += kFunctionMangledNameSeparator;
+
+ for (size_t i = 0u; i < mParamCount; ++i)
+ {
+ newName += mParameters[i]->getType().getMangledName();
+ }
+ return ImmutableString(newName);
+}
+
+bool TFunction::isMain() const
+{
+ return symbolType() == SymbolType::UserDefined && name() == kMainName;
+}
+
+bool TFunction::isImageFunction() const
+{
+ return symbolType() == SymbolType::BuiltIn &&
+ (name() == kImageSizeName || name() == kImageLoadName || name() == kImageStoreName);
+}
+
+bool TFunction::isAtomicCounterFunction() const
+{
+ return SymbolType() == SymbolType::BuiltIn && name().beginsWith(kAtomicCounterName);
+}
+
+bool TFunction::hasSamplerInStructParams() const
+{
+ for (size_t paramIndex = 0; paramIndex < mParamCount; ++paramIndex)
+ {
+ const TVariable *param = getParam(paramIndex);
+ if (param->getType().isStructureContainingSamplers())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/Symbol.h b/gfx/angle/checkout/src/compiler/translator/Symbol.h
new file mode 100644
index 0000000000..3b74a0baa4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Symbol.h
@@ -0,0 +1,277 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Symbol.h: Symbols representing variables, functions, structures and interface blocks.
+//
+
+#ifndef COMPILER_TRANSLATOR_SYMBOL_H_
+#define COMPILER_TRANSLATOR_SYMBOL_H_
+
+#include "common/angleutils.h"
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolUniqueId.h"
+
+namespace sh
+{
+
+class TSymbolTable;
+
+// Symbol base class. (Can build functions or variables out of these...)
+class TSymbol : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TSymbol(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ SymbolType symbolType,
+ SymbolClass symbolClass,
+ TExtension extension = TExtension::UNDEFINED);
+
+ // Note that we can't have a virtual destructor in order to support constexpr symbols. Data is
+ // either statically allocated or pool allocated.
+ ~TSymbol() = default;
+
+ // Calling name() for empty symbols (symbolType == SymbolType::Empty) generates a similar name
+ // as for internal variables.
+ ImmutableString name() const;
+ // Don't call getMangledName() for empty symbols (symbolType == SymbolType::Empty).
+ ImmutableString getMangledName() const;
+
+ bool isFunction() const { return mSymbolClass == SymbolClass::Function; }
+ bool isVariable() const { return mSymbolClass == SymbolClass::Variable; }
+ bool isStruct() const { return mSymbolClass == SymbolClass::Struct; }
+ bool isInterfaceBlock() const { return mSymbolClass == SymbolClass::InterfaceBlock; }
+
+ const TSymbolUniqueId &uniqueId() const { return mUniqueId; }
+ SymbolType symbolType() const { return mSymbolType; }
+ TExtension extension() const { return mExtension; }
+
+ protected:
+ constexpr TSymbol(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ SymbolType symbolType,
+ TExtension extension,
+ SymbolClass symbolClass)
+ : mName(name),
+ mUniqueId(id),
+ mSymbolType(symbolType),
+ mExtension(extension),
+ mSymbolClass(symbolClass)
+ {}
+
+ const ImmutableString mName;
+
+ private:
+ const TSymbolUniqueId mUniqueId;
+ const SymbolType mSymbolType;
+ const TExtension mExtension;
+
+ // We use this instead of having virtual functions for querying the class in order to support
+ // constexpr symbols.
+ const SymbolClass mSymbolClass;
+};
+
+// Variable.
+// May store the value of a constant variable of any type (float, int, bool or struct).
+class TVariable : public TSymbol
+{
+ public:
+ TVariable(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ const TType *type,
+ SymbolType symbolType,
+ TExtension ext = TExtension::UNDEFINED);
+
+ const TType &getType() const { return *mType; }
+
+ const TConstantUnion *getConstPointer() const { return unionArray; }
+
+ void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; }
+
+ // Note: only to be used for built-in variables with autogenerated ids!
+ constexpr TVariable(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ SymbolType symbolType,
+ TExtension extension,
+ const TType *type)
+ : TSymbol(id, name, symbolType, extension, SymbolClass::Variable),
+ mType(type),
+ unionArray(nullptr)
+ {}
+
+ private:
+ const TType *mType;
+ const TConstantUnion *unionArray;
+};
+
+// Struct type.
+class TStructure : public TSymbol, public TFieldListCollection
+{
+ public:
+ TStructure(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ const TFieldList *fields,
+ SymbolType symbolType);
+
+ // The char arrays passed in must be pool allocated or static.
+ void createSamplerSymbols(const char *namePrefix,
+ const TString &apiNamePrefix,
+ TVector<const TVariable *> *outputSymbols,
+ TMap<const TVariable *, TString> *outputSymbolsToAPINames,
+ TSymbolTable *symbolTable) const;
+
+ void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; }
+ bool atGlobalScope() const { return mAtGlobalScope; }
+
+ private:
+ friend class TSymbolTable;
+ // For creating built-in structs.
+ TStructure(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ TExtension extension,
+ const TFieldList *fields);
+
+ // TODO(zmo): Find a way to get rid of the const_cast in function
+ // setName(). At the moment keep this function private so only
+ // friend class RegenerateStructNames may call it.
+ friend class RegenerateStructNames;
+ void setName(const ImmutableString &name);
+
+ bool mAtGlobalScope;
+};
+
+// Interface block. Note that this contains the block name, not the instance name. Interface block
+// instances are stored as TVariable.
+class TInterfaceBlock : public TSymbol, public TFieldListCollection
+{
+ public:
+ TInterfaceBlock(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ const TFieldList *fields,
+ const TLayoutQualifier &layoutQualifier,
+ SymbolType symbolType,
+ TExtension extension = TExtension::UNDEFINED);
+
+ TLayoutBlockStorage blockStorage() const { return mBlockStorage; }
+ int blockBinding() const { return mBinding; }
+
+ private:
+ friend class TSymbolTable;
+ // For creating built-in interface blocks.
+ TInterfaceBlock(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ TExtension extension,
+ const TFieldList *fields);
+
+ TLayoutBlockStorage mBlockStorage;
+ int mBinding;
+
+ // Note that we only record matrix packing on a per-field granularity.
+};
+
+// Parameter class used for parsing user-defined function parameters.
+struct TParameter
+{
+ // Destructively converts to TVariable.
+ // This method resets name and type to nullptrs to make sure
+ // their content cannot be modified after the call.
+ const TVariable *createVariable(TSymbolTable *symbolTable)
+ {
+ const ImmutableString constName(name);
+ const TType *constType = type;
+ name = nullptr;
+ type = nullptr;
+ return new TVariable(symbolTable, constName, constType,
+ constName.empty() ? SymbolType::Empty : SymbolType::UserDefined);
+ }
+
+ const char *name; // either pool allocated or static.
+ TType *type;
+};
+
+// The function sub-class of a symbol.
+class TFunction : public TSymbol
+{
+ public:
+ // User-defined function
+ TFunction(TSymbolTable *symbolTable,
+ const ImmutableString &name,
+ SymbolType symbolType,
+ const TType *retType,
+ bool knownToNotHaveSideEffects);
+
+ void addParameter(const TVariable *p);
+ void shareParameters(const TFunction &parametersSource);
+
+ ImmutableString getFunctionMangledName() const
+ {
+ ASSERT(symbolType() != SymbolType::BuiltIn);
+ if (mMangledName.empty())
+ {
+ mMangledName = buildMangledName();
+ }
+ return mMangledName;
+ }
+
+ const TType &getReturnType() const { return *returnType; }
+
+ TOperator getBuiltInOp() const { return mOp; }
+
+ void setDefined() { defined = true; }
+ bool isDefined() { return defined; }
+ void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
+ bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
+
+ size_t getParamCount() const { return mParamCount; }
+ const TVariable *getParam(size_t i) const { return mParameters[i]; }
+
+ bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; }
+
+ bool isMain() const;
+ bool isImageFunction() const;
+ bool isAtomicCounterFunction() const;
+ bool hasSamplerInStructParams() const;
+
+ // Note: Only to be used for static built-in functions!
+ constexpr TFunction(const TSymbolUniqueId &id,
+ const ImmutableString &name,
+ TExtension extension,
+ const TVariable *const *parameters,
+ size_t paramCount,
+ const TType *retType,
+ TOperator op,
+ bool knownToNotHaveSideEffects)
+ : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::Function),
+ mParametersVector(nullptr),
+ mParameters(parameters),
+ mParamCount(paramCount),
+ returnType(retType),
+ mMangledName(nullptr),
+ mOp(op),
+ defined(false),
+ mHasPrototypeDeclaration(false),
+ mKnownToNotHaveSideEffects(knownToNotHaveSideEffects)
+ {}
+
+ private:
+ ImmutableString buildMangledName() const;
+
+ typedef TVector<const TVariable *> TParamVector;
+ TParamVector *mParametersVector;
+ const TVariable *const *mParameters;
+ size_t mParamCount;
+ const TType *const returnType;
+ mutable ImmutableString mMangledName;
+ const TOperator mOp; // Only set for built-ins
+ bool defined;
+ bool mHasPrototypeDeclaration;
+ bool mKnownToNotHaveSideEffects;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SYMBOL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
new file mode 100644
index 0000000000..cc9e72e880
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
@@ -0,0 +1,417 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Symbol table for parsing. The design principles and most of the functionality are documented in
+// the header file.
+//
+
+#if defined(_MSC_VER)
+# pragma warning(disable : 4718)
+#endif
+
+#include "compiler/translator/SymbolTable.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+class TSymbolTable::TSymbolTableLevel
+{
+ public:
+ TSymbolTableLevel() = default;
+
+ bool insert(TSymbol *symbol);
+
+ // Insert a function using its unmangled name as the key.
+ void insertUnmangled(TFunction *function);
+
+ TSymbol *find(const ImmutableString &name) const;
+
+ private:
+ using tLevel = TUnorderedMap<ImmutableString,
+ TSymbol *,
+ ImmutableString::FowlerNollVoHash<sizeof(size_t)>>;
+ using tLevelPair = const tLevel::value_type;
+ using tInsertResult = std::pair<tLevel::iterator, bool>;
+
+ tLevel level;
+};
+
+bool TSymbolTable::TSymbolTableLevel::insert(TSymbol *symbol)
+{
+ // returning true means symbol was added to the table
+ tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol));
+ return result.second;
+}
+
+void TSymbolTable::TSymbolTableLevel::insertUnmangled(TFunction *function)
+{
+ level.insert(tLevelPair(function->name(), function));
+}
+
+TSymbol *TSymbolTable::TSymbolTableLevel::find(const ImmutableString &name) const
+{
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return nullptr;
+ else
+ return (*it).second;
+}
+
+TSymbolTable::TSymbolTable()
+ : mGlobalInvariant(false),
+ mUniqueIdCounter(0),
+ mShaderType(GL_FRAGMENT_SHADER),
+ mGlInVariableWithArraySize(nullptr)
+{}
+
+TSymbolTable::~TSymbolTable() = default;
+
+bool TSymbolTable::isEmpty() const
+{
+ return mTable.empty();
+}
+
+bool TSymbolTable::atGlobalLevel() const
+{
+ return mTable.size() == 1u;
+}
+
+void TSymbolTable::push()
+{
+ mTable.emplace_back(new TSymbolTableLevel);
+ mPrecisionStack.emplace_back(new PrecisionStackLevel);
+}
+
+void TSymbolTable::pop()
+{
+ mTable.pop_back();
+ mPrecisionStack.pop_back();
+}
+
+const TFunction *TSymbolTable::markFunctionHasPrototypeDeclaration(
+ const ImmutableString &mangledName,
+ bool *hadPrototypeDeclarationOut) const
+{
+ TFunction *function = findUserDefinedFunction(mangledName);
+ *hadPrototypeDeclarationOut = function->hasPrototypeDeclaration();
+ function->setHasPrototypeDeclaration();
+ return function;
+}
+
+const TFunction *TSymbolTable::setFunctionParameterNamesFromDefinition(const TFunction *function,
+ bool *wasDefinedOut) const
+{
+ TFunction *firstDeclaration = findUserDefinedFunction(function->getMangledName());
+ ASSERT(firstDeclaration);
+ // Note: 'firstDeclaration' could be 'function' if this is the first time we've seen function as
+ // it would have just been put in the symbol table. Otherwise, we're looking up an earlier
+ // occurance.
+ if (function != firstDeclaration)
+ {
+ // The previous declaration should have the same parameters as the function definition
+ // (parameter names may differ).
+ firstDeclaration->shareParameters(*function);
+ }
+
+ *wasDefinedOut = firstDeclaration->isDefined();
+ firstDeclaration->setDefined();
+ return firstDeclaration;
+}
+
+bool TSymbolTable::setGlInArraySize(unsigned int inputArraySize)
+{
+ if (mGlInVariableWithArraySize)
+ {
+ return mGlInVariableWithArraySize->getType().getOutermostArraySize() == inputArraySize;
+ }
+ const TInterfaceBlock *glPerVertex = mVar_gl_PerVertex;
+ TType *glInType = new TType(glPerVertex, EvqPerVertexIn, TLayoutQualifier::Create());
+ glInType->makeArray(inputArraySize);
+ mGlInVariableWithArraySize =
+ new TVariable(this, ImmutableString("gl_in"), glInType, SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader);
+ return true;
+}
+
+TVariable *TSymbolTable::getGlInVariableWithArraySize() const
+{
+ return mGlInVariableWithArraySize;
+}
+
+const TVariable *TSymbolTable::gl_FragData() const
+{
+ return mVar_gl_FragData;
+}
+
+const TVariable *TSymbolTable::gl_SecondaryFragDataEXT() const
+{
+ return mVar_gl_SecondaryFragDataEXT;
+}
+
+TSymbolTable::VariableMetadata *TSymbolTable::getOrCreateVariableMetadata(const TVariable &variable)
+{
+ int id = variable.uniqueId().get();
+ auto iter = mVariableMetadata.find(id);
+ if (iter == mVariableMetadata.end())
+ {
+ iter = mVariableMetadata.insert(std::make_pair(id, VariableMetadata())).first;
+ }
+ return &iter->second;
+}
+
+void TSymbolTable::markStaticWrite(const TVariable &variable)
+{
+ auto metadata = getOrCreateVariableMetadata(variable);
+ metadata->staticWrite = true;
+}
+
+void TSymbolTable::markStaticRead(const TVariable &variable)
+{
+ auto metadata = getOrCreateVariableMetadata(variable);
+ metadata->staticRead = true;
+}
+
+bool TSymbolTable::isStaticallyUsed(const TVariable &variable) const
+{
+ ASSERT(!variable.getConstPointer());
+ int id = variable.uniqueId().get();
+ auto iter = mVariableMetadata.find(id);
+ return iter != mVariableMetadata.end() && (iter->second.staticRead || iter->second.staticWrite);
+}
+
+void TSymbolTable::addInvariantVarying(const TVariable &variable)
+{
+ ASSERT(atGlobalLevel());
+ auto metadata = getOrCreateVariableMetadata(variable);
+ metadata->invariant = true;
+}
+
+bool TSymbolTable::isVaryingInvariant(const TVariable &variable) const
+{
+ ASSERT(atGlobalLevel());
+ if (mGlobalInvariant && (IsShaderOutput(variable.getType().getQualifier())))
+ {
+ return true;
+ }
+ int id = variable.uniqueId().get();
+ auto iter = mVariableMetadata.find(id);
+ return iter != mVariableMetadata.end() && iter->second.invariant;
+}
+
+void TSymbolTable::setGlobalInvariant(bool invariant)
+{
+ ASSERT(atGlobalLevel());
+ mGlobalInvariant = invariant;
+}
+
+const TSymbol *TSymbolTable::find(const ImmutableString &name, int shaderVersion) const
+{
+ const TSymbol *userSymbol = findUserDefined(name);
+ if (userSymbol)
+ {
+ return userSymbol;
+ }
+
+ return findBuiltIn(name, shaderVersion);
+}
+
+const TSymbol *TSymbolTable::findUserDefined(const ImmutableString &name) const
+{
+ int userDefinedLevel = static_cast<int>(mTable.size()) - 1;
+ while (userDefinedLevel >= 0)
+ {
+ const TSymbol *symbol = mTable[userDefinedLevel]->find(name);
+ if (symbol)
+ {
+ return symbol;
+ }
+ userDefinedLevel--;
+ }
+
+ return nullptr;
+}
+
+TFunction *TSymbolTable::findUserDefinedFunction(const ImmutableString &name) const
+{
+ // User-defined functions are always declared at the global level.
+ ASSERT(!mTable.empty());
+ return static_cast<TFunction *>(mTable[0]->find(name));
+}
+
+const TSymbol *TSymbolTable::findGlobal(const ImmutableString &name) const
+{
+ ASSERT(!mTable.empty());
+ return mTable[0]->find(name);
+}
+
+const TSymbol *TSymbolTable::findGlobalWithConversion(
+ const std::vector<ImmutableString> &names) const
+{
+ const TSymbol *target;
+ for (ImmutableString name : names)
+ {
+ target = findGlobal(name);
+ if (target != nullptr)
+ break;
+ }
+ return target;
+}
+
+const TSymbol *TSymbolTable::findBuiltInWithConversion(const std::vector<ImmutableString> &names,
+ int shaderVersion) const
+{
+ const TSymbol *target;
+ for (ImmutableString name : names)
+ {
+ target = findBuiltIn(name, shaderVersion);
+ if (target != nullptr)
+ break;
+ }
+ return target;
+}
+
+bool TSymbolTable::declare(TSymbol *symbol)
+{
+ ASSERT(!mTable.empty());
+ ASSERT(symbol->symbolType() == SymbolType::UserDefined);
+ ASSERT(!symbol->isFunction());
+ return mTable.back()->insert(symbol);
+}
+
+bool TSymbolTable::declareInternal(TSymbol *symbol)
+{
+ ASSERT(!mTable.empty());
+ ASSERT(symbol->symbolType() == SymbolType::AngleInternal);
+ ASSERT(!symbol->isFunction());
+ return mTable.back()->insert(symbol);
+}
+
+void TSymbolTable::declareUserDefinedFunction(TFunction *function, bool insertUnmangledName)
+{
+ ASSERT(!mTable.empty());
+ if (insertUnmangledName)
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ mTable[0]->insertUnmangled(function);
+ }
+ mTable[0]->insert(function);
+}
+
+void TSymbolTable::setDefaultPrecision(TBasicType type, TPrecision prec)
+{
+ int indexOfLastElement = static_cast<int>(mPrecisionStack.size()) - 1;
+ // Uses map operator [], overwrites the current value
+ (*mPrecisionStack[indexOfLastElement])[type] = prec;
+}
+
+TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const
+{
+ if (!SupportsPrecision(type))
+ return EbpUndefined;
+
+ // unsigned integers use the same precision as signed
+ TBasicType baseType = (type == EbtUInt) ? EbtInt : type;
+
+ int level = static_cast<int>(mPrecisionStack.size()) - 1;
+ ASSERT(level >= 0); // Just to be safe. Should not happen.
+ // If we dont find anything we return this. Some types don't have predefined default precision.
+ TPrecision prec = EbpUndefined;
+ while (level >= 0)
+ {
+ PrecisionStackLevel::iterator it = mPrecisionStack[level]->find(baseType);
+ if (it != mPrecisionStack[level]->end())
+ {
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+}
+
+void TSymbolTable::clearCompilationResults()
+{
+ mGlobalInvariant = false;
+ mUniqueIdCounter = kLastBuiltInId + 1;
+ mVariableMetadata.clear();
+ mGlInVariableWithArraySize = nullptr;
+
+ // User-defined scopes should have already been cleared when the compilation finished.
+ ASSERT(mTable.empty());
+}
+
+int TSymbolTable::nextUniqueIdValue()
+{
+ ASSERT(mUniqueIdCounter < std::numeric_limits<int>::max());
+ return ++mUniqueIdCounter;
+}
+
+void TSymbolTable::initializeBuiltIns(sh::GLenum type,
+ ShShaderSpec spec,
+ const ShBuiltInResources &resources)
+{
+ mShaderType = type;
+ mResources = resources;
+
+ // We need just one precision stack level for predefined precisions.
+ mPrecisionStack.emplace_back(new PrecisionStackLevel);
+
+ if (IsDesktopGLSpec(spec))
+ {
+ setDefaultPrecision(EbtInt, EbpUndefined);
+ setDefaultPrecision(EbtFloat, EbpUndefined);
+ }
+ else
+ {
+ switch (type)
+ {
+ case GL_FRAGMENT_SHADER:
+ setDefaultPrecision(EbtInt, EbpMedium);
+ break;
+ case GL_VERTEX_SHADER:
+ case GL_COMPUTE_SHADER:
+ case GL_GEOMETRY_SHADER_EXT:
+ setDefaultPrecision(EbtInt, EbpHigh);
+ 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.
+ // New sampler types in ESSL3 don't have default precision. ESSL1 types do.
+ initSamplerDefaultPrecision(EbtSampler2D);
+ 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);
+
+ setDefaultPrecision(EbtAtomicCounter, EbpHigh);
+
+ initializeBuiltInVariables(type, spec, resources);
+ mUniqueIdCounter = kLastBuiltInId + 1;
+}
+
+void TSymbolTable::initSamplerDefaultPrecision(TBasicType samplerType)
+{
+ ASSERT(samplerType >= EbtGuardSamplerBegin && samplerType <= EbtGuardSamplerEnd);
+ setDefaultPrecision(samplerType, EbpLow);
+}
+
+TSymbolTable::VariableMetadata::VariableMetadata()
+ : staticRead(false), staticWrite(false), invariant(false)
+{}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable.h b/gfx/angle/checkout/src/compiler/translator/SymbolTable.h
new file mode 100644
index 0000000000..687ddccd6f
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable.h
@@ -0,0 +1,201 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_H_
+#define COMPILER_TRANSLATOR_SYMBOLTABLE_H_
+
+//
+// Symbol table for parsing. Has these design characteristics:
+//
+// * Same symbol table can be used to compile many shaders, to preserve
+// effort of creating and loading with the large numbers of built-in
+// symbols.
+//
+// * Name mangling will be used to give each function a unique name
+// so that symbol table lookups are never ambiguous. This allows
+// a simpler symbol table structure.
+//
+// * Pushing and popping of scope, so symbol table will really be a stack
+// of symbol tables. Searched from the top, with new inserts going into
+// the top.
+//
+// * Constants: Compile time constant symbols will keep their values
+// in the symbol table. The parser can substitute constants at parse
+// time, including doing constant folding and constant propagation.
+//
+// * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
+// are tracked in the intermediate representation, not the symbol table.
+//
+
+#include <memory>
+#include <set>
+
+#include "common/angleutils.h"
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/SymbolTable_autogen.h"
+
+namespace sh
+{
+
+// Define ESymbolLevel as int rather than an enum so that we can do arithmetic on it.
+typedef int ESymbolLevel;
+const int COMMON_BUILTINS = 0;
+const int ESSL1_BUILTINS = 1;
+const int ESSL3_BUILTINS = 2;
+const int ESSL3_1_BUILTINS = 3;
+// GLSL_BUILTINS are desktop GLSL builtins that don't exist in ESSL but are used to implement
+// features in ANGLE's GLSL backend. They're not visible to the parser.
+const int GLSL_BUILTINS = 4;
+const int LAST_BUILTIN_LEVEL = GLSL_BUILTINS;
+
+struct UnmangledBuiltIn
+{
+ constexpr UnmangledBuiltIn(TExtension extension) : extension(extension) {}
+
+ TExtension extension;
+};
+
+class TSymbolTable : angle::NonCopyable, TSymbolTableBase
+{
+ public:
+ TSymbolTable();
+ // To start using the symbol table after construction:
+ // * initializeBuiltIns() needs to be called.
+ // * push() needs to be called to push the global level.
+
+ ~TSymbolTable();
+
+ bool isEmpty() const;
+ bool atGlobalLevel() const;
+
+ void push();
+ void pop();
+
+ // Declare a non-function symbol at the current scope. Return true in case the declaration was
+ // successful, and false if the declaration failed due to redefinition.
+ bool declare(TSymbol *symbol);
+
+ // Only used to declare internal variables.
+ bool declareInternal(TSymbol *symbol);
+
+ // Functions are always declared at global scope.
+ void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
+
+ // These return the TFunction pointer to keep using to refer to this function.
+ const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName,
+ bool *hadPrototypeDeclarationOut) const;
+ const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function,
+ bool *wasDefinedOut) const;
+
+ // Return false if the gl_in array size has already been initialized with a mismatching value.
+ bool setGlInArraySize(unsigned int inputArraySize);
+ TVariable *getGlInVariableWithArraySize() const;
+
+ const TVariable *gl_FragData() const;
+ const TVariable *gl_SecondaryFragDataEXT() const;
+
+ void markStaticRead(const TVariable &variable);
+ void markStaticWrite(const TVariable &variable);
+
+ // Note: Should not call this for constant variables.
+ bool isStaticallyUsed(const TVariable &variable) const;
+
+ // find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString
+ // with a reference to a short-lived char * is fine to pass here.
+ const TSymbol *find(const ImmutableString &name, int shaderVersion) const;
+
+ const TSymbol *findUserDefined(const ImmutableString &name) const;
+
+ TFunction *findUserDefinedFunction(const ImmutableString &name) const;
+
+ const TSymbol *findGlobal(const ImmutableString &name) const;
+ const TSymbol *findGlobalWithConversion(const std::vector<ImmutableString> &names) const;
+
+ const TSymbol *findBuiltIn(const ImmutableString &name, int shaderVersion) const;
+ const TSymbol *findBuiltInWithConversion(const std::vector<ImmutableString> &names,
+ int shaderVersion) const;
+
+ void setDefaultPrecision(TBasicType type, TPrecision prec);
+
+ // Searches down the precisionStack for a precision qualifier
+ // for the specified TBasicType
+ TPrecision getDefaultPrecision(TBasicType type) const;
+
+ // This records invariant varyings declared through "invariant varying_name;".
+ void addInvariantVarying(const TVariable &variable);
+
+ // If this returns false, the varying could still be invariant if it is set as invariant during
+ // the varying variable declaration - this piece of information is stored in the variable's
+ // type, not here.
+ bool isVaryingInvariant(const TVariable &variable) const;
+
+ void setGlobalInvariant(bool invariant);
+
+ const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
+
+ // Gets the built-in accessible by a shader with the specified version, if any.
+ const UnmangledBuiltIn *getUnmangledBuiltInForShaderVersion(const ImmutableString &name,
+ int shaderVersion);
+
+ void initializeBuiltIns(sh::GLenum type,
+ ShShaderSpec spec,
+ const ShBuiltInResources &resources);
+ void clearCompilationResults();
+
+ private:
+ friend class TSymbolUniqueId;
+
+ struct VariableMetadata
+ {
+ VariableMetadata();
+ bool staticRead;
+ bool staticWrite;
+ bool invariant;
+ };
+
+ int nextUniqueIdValue();
+
+ class TSymbolTableLevel;
+
+ void initSamplerDefaultPrecision(TBasicType samplerType);
+
+ void initializeBuiltInVariables(sh::GLenum shaderType,
+ ShShaderSpec spec,
+ const ShBuiltInResources &resources);
+
+ VariableMetadata *getOrCreateVariableMetadata(const TVariable &variable);
+
+ std::vector<std::unique_ptr<TSymbolTableLevel>> mTable;
+
+ // There's one precision stack level for predefined precisions and then one level for each scope
+ // in table.
+ typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
+ std::vector<std::unique_ptr<PrecisionStackLevel>> mPrecisionStack;
+
+ bool mGlobalInvariant;
+
+ int mUniqueIdCounter;
+
+ static const int kLastBuiltInId;
+
+ sh::GLenum mShaderType;
+ ShBuiltInResources mResources;
+
+ // Indexed by unique id. Map instead of vector since the variables are fairly sparse.
+ std::map<int, VariableMetadata> mVariableMetadata;
+
+ // Store gl_in variable with its array size once the array size can be determined. The array
+ // size can also be checked against latter input primitive type declaration.
+ TVariable *mGlInVariableWithArraySize;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp
new file mode 100644
index 0000000000..d2307d5f53
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp
@@ -0,0 +1,20959 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_builtin_symbols.py using data from builtin_variables.json and
+// builtin_function_declarations.txt.
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SymbolTable_autogen.cpp:
+// Compile-time initialized built-ins.
+
+#include "compiler/translator/SymbolTable.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+
+namespace sh
+{
+
+// Since some of the BuiltInId declarations are used outside of constexpr expressions, we need to
+// have these definitions without an initializer. C++17 should eventually remove the need for this.
+constexpr const TSymbolUniqueId BuiltInId::radians_Float1;
+constexpr const TSymbolUniqueId BuiltInId::radians_Float2;
+constexpr const TSymbolUniqueId BuiltInId::radians_Float3;
+constexpr const TSymbolUniqueId BuiltInId::radians_Float4;
+constexpr const TSymbolUniqueId BuiltInId::degrees_Float1;
+constexpr const TSymbolUniqueId BuiltInId::degrees_Float2;
+constexpr const TSymbolUniqueId BuiltInId::degrees_Float3;
+constexpr const TSymbolUniqueId BuiltInId::degrees_Float4;
+constexpr const TSymbolUniqueId BuiltInId::sin_Float1;
+constexpr const TSymbolUniqueId BuiltInId::sin_Float2;
+constexpr const TSymbolUniqueId BuiltInId::sin_Float3;
+constexpr const TSymbolUniqueId BuiltInId::sin_Float4;
+constexpr const TSymbolUniqueId BuiltInId::cos_Float1;
+constexpr const TSymbolUniqueId BuiltInId::cos_Float2;
+constexpr const TSymbolUniqueId BuiltInId::cos_Float3;
+constexpr const TSymbolUniqueId BuiltInId::cos_Float4;
+constexpr const TSymbolUniqueId BuiltInId::tan_Float1;
+constexpr const TSymbolUniqueId BuiltInId::tan_Float2;
+constexpr const TSymbolUniqueId BuiltInId::tan_Float3;
+constexpr const TSymbolUniqueId BuiltInId::tan_Float4;
+constexpr const TSymbolUniqueId BuiltInId::asin_Float1;
+constexpr const TSymbolUniqueId BuiltInId::asin_Float2;
+constexpr const TSymbolUniqueId BuiltInId::asin_Float3;
+constexpr const TSymbolUniqueId BuiltInId::asin_Float4;
+constexpr const TSymbolUniqueId BuiltInId::acos_Float1;
+constexpr const TSymbolUniqueId BuiltInId::acos_Float2;
+constexpr const TSymbolUniqueId BuiltInId::acos_Float3;
+constexpr const TSymbolUniqueId BuiltInId::acos_Float4;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float1;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float2;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float3;
+constexpr const TSymbolUniqueId BuiltInId::atan_Float4;
+constexpr const TSymbolUniqueId BuiltInId::sinh_Float1;
+constexpr const TSymbolUniqueId BuiltInId::sinh_Float2;
+constexpr const TSymbolUniqueId BuiltInId::sinh_Float3;
+constexpr const TSymbolUniqueId BuiltInId::sinh_Float4;
+constexpr const TSymbolUniqueId BuiltInId::cosh_Float1;
+constexpr const TSymbolUniqueId BuiltInId::cosh_Float2;
+constexpr const TSymbolUniqueId BuiltInId::cosh_Float3;
+constexpr const TSymbolUniqueId BuiltInId::cosh_Float4;
+constexpr const TSymbolUniqueId BuiltInId::tanh_Float1;
+constexpr const TSymbolUniqueId BuiltInId::tanh_Float2;
+constexpr const TSymbolUniqueId BuiltInId::tanh_Float3;
+constexpr const TSymbolUniqueId BuiltInId::tanh_Float4;
+constexpr const TSymbolUniqueId BuiltInId::asinh_Float1;
+constexpr const TSymbolUniqueId BuiltInId::asinh_Float2;
+constexpr const TSymbolUniqueId BuiltInId::asinh_Float3;
+constexpr const TSymbolUniqueId BuiltInId::asinh_Float4;
+constexpr const TSymbolUniqueId BuiltInId::acosh_Float1;
+constexpr const TSymbolUniqueId BuiltInId::acosh_Float2;
+constexpr const TSymbolUniqueId BuiltInId::acosh_Float3;
+constexpr const TSymbolUniqueId BuiltInId::acosh_Float4;
+constexpr const TSymbolUniqueId BuiltInId::atanh_Float1;
+constexpr const TSymbolUniqueId BuiltInId::atanh_Float2;
+constexpr const TSymbolUniqueId BuiltInId::atanh_Float3;
+constexpr const TSymbolUniqueId BuiltInId::atanh_Float4;
+constexpr const TSymbolUniqueId BuiltInId::pow_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::pow_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::pow_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::pow_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::exp_Float1;
+constexpr const TSymbolUniqueId BuiltInId::exp_Float2;
+constexpr const TSymbolUniqueId BuiltInId::exp_Float3;
+constexpr const TSymbolUniqueId BuiltInId::exp_Float4;
+constexpr const TSymbolUniqueId BuiltInId::log_Float1;
+constexpr const TSymbolUniqueId BuiltInId::log_Float2;
+constexpr const TSymbolUniqueId BuiltInId::log_Float3;
+constexpr const TSymbolUniqueId BuiltInId::log_Float4;
+constexpr const TSymbolUniqueId BuiltInId::exp2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::exp2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::exp2_Float3;
+constexpr const TSymbolUniqueId BuiltInId::exp2_Float4;
+constexpr const TSymbolUniqueId BuiltInId::log2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::log2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::log2_Float3;
+constexpr const TSymbolUniqueId BuiltInId::log2_Float4;
+constexpr const TSymbolUniqueId BuiltInId::sqrt_Float1;
+constexpr const TSymbolUniqueId BuiltInId::sqrt_Float2;
+constexpr const TSymbolUniqueId BuiltInId::sqrt_Float3;
+constexpr const TSymbolUniqueId BuiltInId::sqrt_Float4;
+constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float1;
+constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float2;
+constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float3;
+constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float4;
+constexpr const TSymbolUniqueId BuiltInId::abs_Float1;
+constexpr const TSymbolUniqueId BuiltInId::abs_Float2;
+constexpr const TSymbolUniqueId BuiltInId::abs_Float3;
+constexpr const TSymbolUniqueId BuiltInId::abs_Float4;
+constexpr const TSymbolUniqueId BuiltInId::abs_Int1;
+constexpr const TSymbolUniqueId BuiltInId::abs_Int2;
+constexpr const TSymbolUniqueId BuiltInId::abs_Int3;
+constexpr const TSymbolUniqueId BuiltInId::abs_Int4;
+constexpr const TSymbolUniqueId BuiltInId::sign_Float1;
+constexpr const TSymbolUniqueId BuiltInId::sign_Float2;
+constexpr const TSymbolUniqueId BuiltInId::sign_Float3;
+constexpr const TSymbolUniqueId BuiltInId::sign_Float4;
+constexpr const TSymbolUniqueId BuiltInId::sign_Int1;
+constexpr const TSymbolUniqueId BuiltInId::sign_Int2;
+constexpr const TSymbolUniqueId BuiltInId::sign_Int3;
+constexpr const TSymbolUniqueId BuiltInId::sign_Int4;
+constexpr const TSymbolUniqueId BuiltInId::floor_Float1;
+constexpr const TSymbolUniqueId BuiltInId::floor_Float2;
+constexpr const TSymbolUniqueId BuiltInId::floor_Float3;
+constexpr const TSymbolUniqueId BuiltInId::floor_Float4;
+constexpr const TSymbolUniqueId BuiltInId::trunc_Float1;
+constexpr const TSymbolUniqueId BuiltInId::trunc_Float2;
+constexpr const TSymbolUniqueId BuiltInId::trunc_Float3;
+constexpr const TSymbolUniqueId BuiltInId::trunc_Float4;
+constexpr const TSymbolUniqueId BuiltInId::round_Float1;
+constexpr const TSymbolUniqueId BuiltInId::round_Float2;
+constexpr const TSymbolUniqueId BuiltInId::round_Float3;
+constexpr const TSymbolUniqueId BuiltInId::round_Float4;
+constexpr const TSymbolUniqueId BuiltInId::roundEven_Float1;
+constexpr const TSymbolUniqueId BuiltInId::roundEven_Float2;
+constexpr const TSymbolUniqueId BuiltInId::roundEven_Float3;
+constexpr const TSymbolUniqueId BuiltInId::roundEven_Float4;
+constexpr const TSymbolUniqueId BuiltInId::ceil_Float1;
+constexpr const TSymbolUniqueId BuiltInId::ceil_Float2;
+constexpr const TSymbolUniqueId BuiltInId::ceil_Float3;
+constexpr const TSymbolUniqueId BuiltInId::ceil_Float4;
+constexpr const TSymbolUniqueId BuiltInId::fract_Float1;
+constexpr const TSymbolUniqueId BuiltInId::fract_Float2;
+constexpr const TSymbolUniqueId BuiltInId::fract_Float3;
+constexpr const TSymbolUniqueId BuiltInId::fract_Float4;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::mod_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::min_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::min_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::min_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::min_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::min_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::min_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::min_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::min_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::min_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::min_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::min_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::min_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::min_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::min_Int4_Int1;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt2_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt3_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::min_UInt4_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::max_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::max_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::max_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::max_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::max_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::max_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::max_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::max_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::max_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::max_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::max_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::max_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::max_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::max_Int4_Int1;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt2_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt3_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::max_UInt4_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float1_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float2_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float3_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float4_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Float4_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int2_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int3_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int4_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int2_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int3_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::clamp_Int4_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt1_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt2_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt3_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt4_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt2_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt3_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::clamp_UInt4_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float1_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float2_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float3_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float4_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float4_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float1_Float1_Bool1;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float2_Float2_Bool2;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float3_Float3_Bool3;
+constexpr const TSymbolUniqueId BuiltInId::mix_Float4_Float4_Bool4;
+constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::step_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::step_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::step_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float4_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::modf_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::modf_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::modf_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::modf_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::isnan_Float1;
+constexpr const TSymbolUniqueId BuiltInId::isnan_Float2;
+constexpr const TSymbolUniqueId BuiltInId::isnan_Float3;
+constexpr const TSymbolUniqueId BuiltInId::isnan_Float4;
+constexpr const TSymbolUniqueId BuiltInId::isinf_Float1;
+constexpr const TSymbolUniqueId BuiltInId::isinf_Float2;
+constexpr const TSymbolUniqueId BuiltInId::isinf_Float3;
+constexpr const TSymbolUniqueId BuiltInId::isinf_Float4;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float1;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float2;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float3;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float4;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float1;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float2;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float3;
+constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float4;
+constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int1;
+constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int2;
+constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int3;
+constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int4;
+constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::frexp_Float1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::frexp_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::frexp_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::frexp_Float4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::ldexp_Float1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::ldexp_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::ldexp_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::ldexp_Float4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::packSnorm2x16_Float2;
+constexpr const TSymbolUniqueId BuiltInId::packUnorm2x16_Float2;
+constexpr const TSymbolUniqueId BuiltInId::packHalf2x16_Float2;
+constexpr const TSymbolUniqueId BuiltInId::unpackSnorm2x16_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::unpackUnorm2x16_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::unpackHalf2x16_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::packUnorm4x8_Float4;
+constexpr const TSymbolUniqueId BuiltInId::packSnorm4x8_Float4;
+constexpr const TSymbolUniqueId BuiltInId::unpackUnorm4x8_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::unpackSnorm4x8_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::length_Float1;
+constexpr const TSymbolUniqueId BuiltInId::length_Float2;
+constexpr const TSymbolUniqueId BuiltInId::length_Float3;
+constexpr const TSymbolUniqueId BuiltInId::length_Float4;
+constexpr const TSymbolUniqueId BuiltInId::distance_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::distance_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::distance_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::distance_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::dot_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::dot_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::dot_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::dot_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::cross_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::normalize_Float1;
+constexpr const TSymbolUniqueId BuiltInId::normalize_Float2;
+constexpr const TSymbolUniqueId BuiltInId::normalize_Float3;
+constexpr const TSymbolUniqueId BuiltInId::normalize_Float4;
+constexpr const TSymbolUniqueId BuiltInId::faceforward_Float1_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::faceforward_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::faceforward_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::faceforward_Float4_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::reflect_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::reflect_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::reflect_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::reflect_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::refract_Float1_Float1_Float1;
+constexpr const TSymbolUniqueId BuiltInId::refract_Float2_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::refract_Float3_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::refract_Float4_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float2x2_Float2x2;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float3x3_Float3x3;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float4x4_Float4x4;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float2x3_Float2x3;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float3x2_Float3x2;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float2x4_Float2x4;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float4x2_Float4x2;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float3x4_Float3x4;
+constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float4x3_Float4x3;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float3_Float2;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float2_Float3;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float4_Float2;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float2_Float4;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float4_Float3;
+constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float3_Float4;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float2x2;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float3x3;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float4x4;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float3x2;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float2x3;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float4x2;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float2x4;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float4x3;
+constexpr const TSymbolUniqueId BuiltInId::transpose_Float3x4;
+constexpr const TSymbolUniqueId BuiltInId::determinant_Float2x2;
+constexpr const TSymbolUniqueId BuiltInId::determinant_Float3x3;
+constexpr const TSymbolUniqueId BuiltInId::determinant_Float4x4;
+constexpr const TSymbolUniqueId BuiltInId::inverse_Float2x2;
+constexpr const TSymbolUniqueId BuiltInId::inverse_Float3x3;
+constexpr const TSymbolUniqueId BuiltInId::inverse_Float4x4;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::lessThan_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::greaterThan_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::equal_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::equal_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::equal_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::equal_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::equal_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::equal_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::equal_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::equal_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::equal_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::equal_Bool2_Bool2;
+constexpr const TSymbolUniqueId BuiltInId::equal_Bool3_Bool3;
+constexpr const TSymbolUniqueId BuiltInId::equal_Bool4_Bool4;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Float4_Float4;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Bool2_Bool2;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Bool3_Bool3;
+constexpr const TSymbolUniqueId BuiltInId::notEqual_Bool4_Bool4;
+constexpr const TSymbolUniqueId BuiltInId::any_Bool2;
+constexpr const TSymbolUniqueId BuiltInId::any_Bool3;
+constexpr const TSymbolUniqueId BuiltInId::any_Bool4;
+constexpr const TSymbolUniqueId BuiltInId::all_Bool2;
+constexpr const TSymbolUniqueId BuiltInId::all_Bool3;
+constexpr const TSymbolUniqueId BuiltInId::all_Bool4;
+constexpr const TSymbolUniqueId BuiltInId::notFunc_Bool2;
+constexpr const TSymbolUniqueId BuiltInId::notFunc_Bool3;
+constexpr const TSymbolUniqueId BuiltInId::notFunc_Bool4;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int2_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int3_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int4_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt2_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt3_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt4_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int1_Int1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int2_Int2_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int3_Int3_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int4_Int4_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt1_UInt1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt2_UInt2_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt3_UInt3_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt4_UInt4_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int2;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int3;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int4;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_Int1;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_Int2;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_Int3;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_Int4;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_Int1;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_Int2;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_Int3;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_Int4;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_Int1;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_Int2;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_Int3;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_Int4;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt1_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt2_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt3_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt4_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt1_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt2_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt3_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt4_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2;
+constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3;
+constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int1_Int1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int2_Int2_Int2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int3_Int3_Int3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int4_Int4_Int4_Int4;
+constexpr const TSymbolUniqueId BuiltInId::texture2D_Sampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureCube_SamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture2D_SamplerExternalOES1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProj_SamplerExternalOES1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProj_SamplerExternalOES1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::texture2DRect_Sampler2DRect1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture2DRectProj_Sampler2DRect1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture2DRectProj_Sampler2DRect1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DRect1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DRect1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DRect1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::texture2DGradEXT_Sampler2D1_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProjGradEXT_Sampler2D1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProjGradEXT_Sampler2D1_Float4_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureCubeGradEXT_SamplerCube1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture2D_Sampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureCube_SamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float1;
+constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float2;
+constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float3;
+constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float4;
+constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float1;
+constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float2;
+constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float3;
+constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float4;
+constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float1;
+constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float2;
+constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float3;
+constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float4;
+constexpr const TSymbolUniqueId BuiltInId::texture2DLodEXT_Sampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProjLodEXT_Sampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProjLodEXT_Sampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureCubeLodEXT_SamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture3D_Sampler3D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture3D_Sampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture3DProj_Sampler3D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::texture3DProj_Sampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture3DLod_Sampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture3DProjLod_Sampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DLod_Sampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProjLod_Sampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture2DProjLod_Sampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureCubeLod_SamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture_USampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler3D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISampler3D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_USampler3D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_USamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DArray1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2DArray1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_USampler2DArray1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler3D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler3D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler3D1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_ISampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_USampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_ISampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_USampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_SamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_ISamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_USamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler2DArray1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_ISampler2DArray1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_USampler2DArray1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DShadow1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCubeShadow1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DArrayShadow1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DShadow1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler2DShadow1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2D1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2D1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2D1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler3D1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler3D1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler3D1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerCube1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_ISamplerCube1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_USamplerCube1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DArray1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2DArray1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2DArray1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DShadow1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerCubeShadow1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DArrayShadow1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_ISampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_USampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_ISampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_USampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_ISampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_USampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler2DShadow1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2D1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2D1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2D1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler3D1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler3D1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler3D1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2DArray1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2DArray1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2DArray1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2D1_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISampler2D1_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_USampler2D1_Float2_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler3D1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISampler3D1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_USampler3D1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_SamplerCube1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISamplerCube1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_USamplerCube1_Float3_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2DShadow1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_SamplerCubeShadow1_Float4_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2DArray1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISampler2DArray1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_USampler2DArray1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2DArrayShadow1_Float4_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler2D1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_ISampler2D1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_USampler2D1_Float3_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler2D1_Float4_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_ISampler2D1_Float4_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_USampler2D1_Float4_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler3D1_Float4_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_ISampler3D1_Float4_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_USampler3D1_Float4_Float3_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler2DShadow1_Float4_Float2_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DMS1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2DMS1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2DMS1;
+constexpr const TSymbolUniqueId BuiltInId::textureSizeExt_Sampler2DMS1;
+constexpr const TSymbolUniqueId BuiltInId::textureSizeExt_ISampler2DMS1;
+constexpr const TSymbolUniqueId BuiltInId::textureSizeExt_USampler2DMS1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DMSArray1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2DMSArray1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2DMSArray1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2D1_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2D1_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2D1_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler3D1_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler3D1_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler3D1_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2DArray1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float4_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler3D1_Float4_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler2D1_Float2_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_ISampler2D1_Float2_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_USampler2D1_Float2_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler3D1_Float3_Float1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_ISampler3D1_Float3_Float1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_USampler3D1_Float3_Float1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler2DShadow1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler2DArray1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_ISampler2DArray1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_USampler2DArray1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler2D1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_ISampler2D1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_USampler2D1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler2D1_Float4_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_ISampler2D1_Float4_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_USampler2D1_Float4_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler3D1_Float4_Float1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_ISampler3D1_Float4_Float1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_USampler3D1_Float4_Float1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler2DShadow1_Float4_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_Sampler2D1_Int2_Int1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_ISampler2D1_Int2_Int1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_USampler2D1_Int2_Int1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_Sampler3D1_Int3_Int1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_ISampler3D1_Int3_Int1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_USampler3D1_Int3_Int1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_Sampler2DArray1_Int3_Int1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_ISampler2DArray1_Int3_Int1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_USampler2DArray1_Int3_Int1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_Sampler2D1_Float2_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_ISampler2D1_Float2_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_USampler2D1_Float2_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_Sampler3D1_Float3_Float3_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_ISampler3D1_Float3_Float3_Float3_Int3;
+constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_USampler3D1_Float3_Float3_Float3_Int3;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureGradOffset_Sampler2DShadow1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureGradOffset_Sampler2DArray1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureGradOffset_ISampler2DArray1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureGradOffset_USampler2DArray1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureGradOffset_Sampler2DArrayShadow1_Float4_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_Sampler2D1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_ISampler2D1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_USampler2D1_Float3_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_Sampler2D1_Float4_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_ISampler2D1_Float4_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_USampler2D1_Float4_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_Sampler3D1_Float4_Float3_Float3_Int3;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_ISampler3D1_Float4_Float3_Float3_Int3;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_USampler3D1_Float4_Float3_Float3_Int3;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureProjGradOffset_Sampler2DShadow1_Float4_Float2_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2D1_Float2_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2D1_Float2_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2D1_Float2_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler3D1_Float3_Int3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler3D1_Float3_Int3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler3D1_Float3_Int3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2DArray1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float3_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float4_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler3D1_Float4_Int3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternalOES1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerExternalOES1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_SamplerExternalOES1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4;
+constexpr const TSymbolUniqueId BuiltInId::rgb_2_yuv_Float3_YuvCscStandardEXT1;
+constexpr const TSymbolUniqueId BuiltInId::yuv_2_rgb_Float3_YuvCscStandardEXT1;
+constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerExternal2DY2YEXT1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_SamplerExternal2DY2YEXT1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_USampler2D1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_USampler3D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_USamplerCube1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DArray1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2DArray1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_USampler2DArray1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler3D1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DShadow1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCubeShadow1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DShadow1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternalOES1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4_Float1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2DMS1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2DMS1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2DMS1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchExt_Sampler2DMS1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchExt_ISampler2DMS1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetchExt_USampler2DMS1_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2DMSArray1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2DMSArray1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2DMSArray1_Int3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2D1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2D1_Float2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2D1_Float2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2D1_Float2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArray1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2DArray1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2DArray1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArray1_Float3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2DArray1_Float3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2DArray1_Float3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_ISamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_USamplerCube1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCube1_Float3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_ISamplerCube1_Float3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_USamplerCube1_Float3_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DShadow1_Float2;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DShadow1_Float2_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArrayShadow1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArrayShadow1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCubeShadow1_Float3;
+constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCubeShadow1_Float3_Float1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2_Int1;
+constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2DShadow1_Float2_Float1_Int2;
+constexpr const TSymbolUniqueId
+ BuiltInId::textureGatherOffset_Sampler2DArrayShadow1_Float3_Float1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::dFdx_Float1;
+constexpr const TSymbolUniqueId BuiltInId::dFdx_Float2;
+constexpr const TSymbolUniqueId BuiltInId::dFdx_Float3;
+constexpr const TSymbolUniqueId BuiltInId::dFdx_Float4;
+constexpr const TSymbolUniqueId BuiltInId::dFdy_Float1;
+constexpr const TSymbolUniqueId BuiltInId::dFdy_Float2;
+constexpr const TSymbolUniqueId BuiltInId::dFdy_Float3;
+constexpr const TSymbolUniqueId BuiltInId::dFdy_Float4;
+constexpr const TSymbolUniqueId BuiltInId::fwidth_Float1;
+constexpr const TSymbolUniqueId BuiltInId::fwidth_Float2;
+constexpr const TSymbolUniqueId BuiltInId::fwidth_Float3;
+constexpr const TSymbolUniqueId BuiltInId::fwidth_Float4;
+constexpr const TSymbolUniqueId BuiltInId::atomicCounter_AtomicCounter1;
+constexpr const TSymbolUniqueId BuiltInId::atomicCounterIncrement_AtomicCounter1;
+constexpr const TSymbolUniqueId BuiltInId::atomicCounterDecrement_AtomicCounter1;
+constexpr const TSymbolUniqueId BuiltInId::atomicAdd_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicAdd_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicMin_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicMin_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicMax_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicMax_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicAnd_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicAnd_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicOr_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicOr_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicXor_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicXor_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicExchange_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicExchange_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::atomicCompSwap_UInt1_UInt1_UInt1;
+constexpr const TSymbolUniqueId BuiltInId::atomicCompSwap_Int1_Int1_Int1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_Image2D1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_IImage2D1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_UImage2D1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_Image3D1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_IImage3D1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_UImage3D1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_Image2DArray1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_IImage2DArray1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_UImage2DArray1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_ImageCube1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_IImageCube1;
+constexpr const TSymbolUniqueId BuiltInId::imageSize_UImageCube1;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_Image2D1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImage2D1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImage2D1_Int2;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_Image3D1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImage3D1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImage3D1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_Image2DArray1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImage2DArray1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImage2DArray1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_ImageCube1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImageCube1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImageCube1_Int3;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_Image2D1_Int2_Float4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_IImage2D1_Int2_Int4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_UImage2D1_Int2_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_Image3D1_Int3_Float4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_IImage3D1_Int3_Int4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_UImage3D1_Int3_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_Image2DArray1_Int3_Float4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_IImage2DArray1_Int3_Int4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_UImage2DArray1_Int3_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_ImageCube1_Int3_Float4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_IImageCube1_Int3_Int4;
+constexpr const TSymbolUniqueId BuiltInId::imageStore_UImageCube1_Int3_UInt4;
+constexpr const TSymbolUniqueId BuiltInId::memoryBarrier;
+constexpr const TSymbolUniqueId BuiltInId::memoryBarrierAtomicCounter;
+constexpr const TSymbolUniqueId BuiltInId::memoryBarrierBuffer;
+constexpr const TSymbolUniqueId BuiltInId::memoryBarrierImage;
+constexpr const TSymbolUniqueId BuiltInId::barrier;
+constexpr const TSymbolUniqueId BuiltInId::memoryBarrierShared;
+constexpr const TSymbolUniqueId BuiltInId::groupMemoryBarrier;
+constexpr const TSymbolUniqueId BuiltInId::EmitVertex;
+constexpr const TSymbolUniqueId BuiltInId::EndPrimitive;
+constexpr const TSymbolUniqueId BuiltInId::gl_DepthRangeParameters;
+constexpr const TSymbolUniqueId BuiltInId::gl_DepthRange;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexAttribs;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexUniformVectors;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexTextureImageUnits;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedTextureImageUnits;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxTextureImageUnits;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentUniformVectors;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVaryingVectors;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxDrawBuffers;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxDualSourceDrawBuffersEXT;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexOutputVectors;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentInputVectors;
+constexpr const TSymbolUniqueId BuiltInId::gl_MinProgramTexelOffset;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxProgramTexelOffset;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxImageUnits;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexImageUniforms;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentImageUniforms;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeImageUniforms;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedImageUniforms;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedShaderOutputResources;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeWorkGroupCount;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeWorkGroupSize;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeUniformComponents;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeTextureImageUnits;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeAtomicCounters;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeAtomicCounterBuffers;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexAtomicCounters;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentAtomicCounters;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedAtomicCounters;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxAtomicCounterBindings;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexAtomicCounterBuffers;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentAtomicCounterBuffers;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedAtomicCounterBuffers;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxAtomicCounterBufferSize;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryInputComponents;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryOutputComponents;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryImageUniforms;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryTextureImageUnits;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryOutputVertices;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryTotalOutputComponents;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryUniformComponents;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryAtomicCounters;
+constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryAtomicCounterBuffers;
+constexpr const TSymbolUniqueId BuiltInId::gl_FragCoord;
+constexpr const TSymbolUniqueId BuiltInId::gl_FrontFacing;
+constexpr const TSymbolUniqueId BuiltInId::gl_PointCoord;
+constexpr const TSymbolUniqueId BuiltInId::gl_FragColor;
+constexpr const TSymbolUniqueId BuiltInId::gl_FragData;
+constexpr const TSymbolUniqueId BuiltInId::gl_FragDepth;
+constexpr const TSymbolUniqueId BuiltInId::gl_SecondaryFragColorEXT;
+constexpr const TSymbolUniqueId BuiltInId::gl_SecondaryFragDataEXT;
+constexpr const TSymbolUniqueId BuiltInId::gl_FragDepthEXT;
+constexpr const TSymbolUniqueId BuiltInId::gl_LastFragData;
+constexpr const TSymbolUniqueId BuiltInId::gl_LastFragColor;
+constexpr const TSymbolUniqueId BuiltInId::gl_LastFragDataNV;
+constexpr const TSymbolUniqueId BuiltInId::gl_LastFragColorARM;
+constexpr const TSymbolUniqueId BuiltInId::gl_PrimitiveID;
+constexpr const TSymbolUniqueId BuiltInId::gl_Layer;
+constexpr const TSymbolUniqueId BuiltInId::gl_Position;
+constexpr const TSymbolUniqueId BuiltInId::gl_PointSize;
+constexpr const TSymbolUniqueId BuiltInId::gl_InstanceID;
+constexpr const TSymbolUniqueId BuiltInId::gl_VertexID;
+constexpr const TSymbolUniqueId BuiltInId::gl_ViewportIndex;
+constexpr const TSymbolUniqueId BuiltInId::gl_LayerVS;
+constexpr const TSymbolUniqueId BuiltInId::gl_DrawID;
+constexpr const TSymbolUniqueId BuiltInId::gl_DrawIDESSL1;
+constexpr const TSymbolUniqueId BuiltInId::gl_BaseVertex;
+constexpr const TSymbolUniqueId BuiltInId::gl_BaseInstance;
+constexpr const TSymbolUniqueId BuiltInId::gl_NumWorkGroups;
+constexpr const TSymbolUniqueId BuiltInId::gl_WorkGroupSize;
+constexpr const TSymbolUniqueId BuiltInId::gl_WorkGroupID;
+constexpr const TSymbolUniqueId BuiltInId::gl_LocalInvocationID;
+constexpr const TSymbolUniqueId BuiltInId::gl_GlobalInvocationID;
+constexpr const TSymbolUniqueId BuiltInId::gl_LocalInvocationIndex;
+constexpr const TSymbolUniqueId BuiltInId::gl_PrimitiveIDIn;
+constexpr const TSymbolUniqueId BuiltInId::gl_InvocationID;
+constexpr const TSymbolUniqueId BuiltInId::gl_PrimitiveIDGS;
+constexpr const TSymbolUniqueId BuiltInId::gl_LayerGS;
+constexpr const TSymbolUniqueId BuiltInId::gl_PerVertex;
+constexpr const TSymbolUniqueId BuiltInId::gl_in;
+constexpr const TSymbolUniqueId BuiltInId::gl_PerVertexOutBlock;
+constexpr const TSymbolUniqueId BuiltInId::gl_PositionGS;
+constexpr const TSymbolUniqueId BuiltInId::gl_ViewID_OVR;
+constexpr const TSymbolUniqueId BuiltInId::gl_ViewID_OVRESSL1;
+
+const int TSymbolTable::kLastBuiltInId = 1033;
+
+namespace BuiltInName
+{
+
+constexpr const ImmutableString _empty("");
+constexpr const ImmutableString EmitVertex("EmitVertex");
+constexpr const ImmutableString EndPrimitive("EndPrimitive");
+constexpr const ImmutableString abs("abs");
+constexpr const ImmutableString acos("acos");
+constexpr const ImmutableString acosh("acosh");
+constexpr const ImmutableString all("all");
+constexpr const ImmutableString any("any");
+constexpr const ImmutableString asin("asin");
+constexpr const ImmutableString asinh("asinh");
+constexpr const ImmutableString atan("atan");
+constexpr const ImmutableString atanh("atanh");
+constexpr const ImmutableString atomicAdd("atomicAdd");
+constexpr const ImmutableString atomicAnd("atomicAnd");
+constexpr const ImmutableString atomicCompSwap("atomicCompSwap");
+constexpr const ImmutableString atomicCompSwap_0D0D0D("atomicCompSwap(0D0D0D");
+constexpr const ImmutableString atomicCounter("atomicCounter");
+constexpr const ImmutableString atomicCounterDecrement("atomicCounterDecrement");
+constexpr const ImmutableString atomicCounterIncrement("atomicCounterIncrement");
+constexpr const ImmutableString atomicExchange("atomicExchange");
+constexpr const ImmutableString atomicMax("atomicMax");
+constexpr const ImmutableString atomicMin("atomicMin");
+constexpr const ImmutableString atomicOr("atomicOr");
+constexpr const ImmutableString atomicXor("atomicXor");
+constexpr const ImmutableString barrier("barrier");
+constexpr const ImmutableString bitCount("bitCount");
+constexpr const ImmutableString bitfieldExtract("bitfieldExtract");
+constexpr const ImmutableString bitfieldExtract_0D0C0C("bitfieldExtract(0D0C0C");
+constexpr const ImmutableString bitfieldExtract_1C0C0C("bitfieldExtract(1C0C0C");
+constexpr const ImmutableString bitfieldExtract_3C0C0C("bitfieldExtract(3C0C0C");
+constexpr const ImmutableString bitfieldInsert("bitfieldInsert");
+constexpr const ImmutableString bitfieldInsert_0C0C0C0C("bitfieldInsert(0C0C0C0C");
+constexpr const ImmutableString bitfieldInsert_0D0D0C0C("bitfieldInsert(0D0D0C0C");
+constexpr const ImmutableString bitfieldInsert_1C1C0C0C("bitfieldInsert(1C1C0C0C");
+constexpr const ImmutableString bitfieldInsert_1D1D0C0C("bitfieldInsert(1D1D0C0C");
+constexpr const ImmutableString bitfieldInsert_2C2C0C0C("bitfieldInsert(2C2C0C0C");
+constexpr const ImmutableString bitfieldInsert_2D2D0C0C("bitfieldInsert(2D2D0C0C");
+constexpr const ImmutableString bitfieldInsert_3C3C0C0C("bitfieldInsert(3C3C0C0C");
+constexpr const ImmutableString bitfieldInsert_3D3D0C0C("bitfieldInsert(3D3D0C0C");
+constexpr const ImmutableString bitfieldReverse("bitfieldReverse");
+constexpr const ImmutableString ceil("ceil");
+constexpr const ImmutableString clamp("clamp");
+constexpr const ImmutableString clamp_0D0D0D("clamp(0D0D0D");
+constexpr const ImmutableString clamp_1B0B0B("clamp(1B0B0B");
+constexpr const ImmutableString clamp_1B1B1B("clamp(1B1B1B");
+constexpr const ImmutableString clamp_1C0C0C("clamp(1C0C0C");
+constexpr const ImmutableString clamp_1C1C1C("clamp(1C1C1C");
+constexpr const ImmutableString clamp_1D1D1D("clamp(1D1D1D");
+constexpr const ImmutableString clamp_2C2C2C("clamp(2C2C2C");
+constexpr const ImmutableString clamp_3B0B0B("clamp(3B0B0B");
+constexpr const ImmutableString clamp_3C0C0C("clamp(3C0C0C");
+constexpr const ImmutableString clamp_3D0D0D("clamp(3D0D0D");
+constexpr const ImmutableString cos("cos");
+constexpr const ImmutableString cosh("cosh");
+constexpr const ImmutableString cross("cross");
+constexpr const ImmutableString dFdx("dFdx");
+constexpr const ImmutableString dFdxExt("dFdx");
+constexpr const ImmutableString dFdy("dFdy");
+constexpr const ImmutableString dFdyExt("dFdy");
+constexpr const ImmutableString degrees("degrees");
+constexpr const ImmutableString determinant("determinant");
+constexpr const ImmutableString diff("diff");
+constexpr const ImmutableString distance("distance");
+constexpr const ImmutableString dot("dot");
+constexpr const ImmutableString equal("equal");
+constexpr const ImmutableString exp("exp");
+constexpr const ImmutableString exp2("exp2");
+constexpr const ImmutableString faceforward("faceforward");
+constexpr const ImmutableString faceforward_1B1B1B("faceforward(1B1B1B");
+constexpr const ImmutableString faceforward_2B2B2B("faceforward(2B2B2B");
+constexpr const ImmutableString faceforward_3B3B3B("faceforward(3B3B3B");
+constexpr const ImmutableString far("far");
+constexpr const ImmutableString findLSB("findLSB");
+constexpr const ImmutableString findMSB("findMSB");
+constexpr const ImmutableString floatBitsToInt("floatBitsToInt");
+constexpr const ImmutableString floatBitsToUint("floatBitsToUint");
+constexpr const ImmutableString floor("floor");
+constexpr const ImmutableString fract("fract");
+constexpr const ImmutableString frexp("frexp");
+constexpr const ImmutableString frexp_3B3C("frexp(3B3C");
+constexpr const ImmutableString fwidth("fwidth");
+constexpr const ImmutableString fwidthExt("fwidth");
+constexpr const ImmutableString gl_BaseInstance("gl_BaseInstance");
+constexpr const ImmutableString gl_BaseVertex("gl_BaseVertex");
+constexpr const ImmutableString gl_DepthRange("gl_DepthRange");
+constexpr const ImmutableString gl_DepthRangeParameters("gl_DepthRangeParameters");
+constexpr const ImmutableString gl_DrawID("gl_DrawID");
+constexpr const ImmutableString gl_FragColor("gl_FragColor");
+constexpr const ImmutableString gl_FragCoord("gl_FragCoord");
+constexpr const ImmutableString gl_FragData("gl_FragData");
+constexpr const ImmutableString gl_FragDepth("gl_FragDepth");
+constexpr const ImmutableString gl_FragDepthEXT("gl_FragDepthEXT");
+constexpr const ImmutableString gl_FrontFacing("gl_FrontFacing");
+constexpr const ImmutableString gl_GlobalInvocationID("gl_GlobalInvocationID");
+constexpr const ImmutableString gl_InstanceID("gl_InstanceID");
+constexpr const ImmutableString gl_InvocationID("gl_InvocationID");
+constexpr const ImmutableString gl_LastFragColor("gl_LastFragColor");
+constexpr const ImmutableString gl_LastFragColorARM("gl_LastFragColorARM");
+constexpr const ImmutableString gl_LastFragData("gl_LastFragData");
+constexpr const ImmutableString gl_Layer("gl_Layer");
+constexpr const ImmutableString gl_LocalInvocationID("gl_LocalInvocationID");
+constexpr const ImmutableString gl_LocalInvocationIndex("gl_LocalInvocationIndex");
+constexpr const ImmutableString gl_MaxAtomicCounterBindings("gl_MaxAtomicCounterBindings");
+constexpr const ImmutableString gl_MaxAtomicCounterBufferSize("gl_MaxAtomicCounterBufferSize");
+constexpr const ImmutableString gl_MaxCombinedAtomicCounterBuffers(
+ "gl_MaxCombinedAtomicCounterBuffers");
+constexpr const ImmutableString gl_MaxCombinedAtomicCounters("gl_MaxCombinedAtomicCounters");
+constexpr const ImmutableString gl_MaxCombinedImageUniforms("gl_MaxCombinedImageUniforms");
+constexpr const ImmutableString gl_MaxCombinedShaderOutputResources(
+ "gl_MaxCombinedShaderOutputResources");
+constexpr const ImmutableString gl_MaxCombinedTextureImageUnits("gl_MaxCombinedTextureImageUnits");
+constexpr const ImmutableString gl_MaxComputeAtomicCounterBuffers(
+ "gl_MaxComputeAtomicCounterBuffers");
+constexpr const ImmutableString gl_MaxComputeAtomicCounters("gl_MaxComputeAtomicCounters");
+constexpr const ImmutableString gl_MaxComputeImageUniforms("gl_MaxComputeImageUniforms");
+constexpr const ImmutableString gl_MaxComputeTextureImageUnits("gl_MaxComputeTextureImageUnits");
+constexpr const ImmutableString gl_MaxComputeUniformComponents("gl_MaxComputeUniformComponents");
+constexpr const ImmutableString gl_MaxComputeWorkGroupCount("gl_MaxComputeWorkGroupCount");
+constexpr const ImmutableString gl_MaxComputeWorkGroupSize("gl_MaxComputeWorkGroupSize");
+constexpr const ImmutableString gl_MaxDrawBuffers("gl_MaxDrawBuffers");
+constexpr const ImmutableString gl_MaxDualSourceDrawBuffersEXT("gl_MaxDualSourceDrawBuffersEXT");
+constexpr const ImmutableString gl_MaxFragmentAtomicCounterBuffers(
+ "gl_MaxFragmentAtomicCounterBuffers");
+constexpr const ImmutableString gl_MaxFragmentAtomicCounters("gl_MaxFragmentAtomicCounters");
+constexpr const ImmutableString gl_MaxFragmentImageUniforms("gl_MaxFragmentImageUniforms");
+constexpr const ImmutableString gl_MaxFragmentInputVectors("gl_MaxFragmentInputVectors");
+constexpr const ImmutableString gl_MaxFragmentUniformVectors("gl_MaxFragmentUniformVectors");
+constexpr const ImmutableString gl_MaxGeometryAtomicCounterBuffers(
+ "gl_MaxGeometryAtomicCounterBuffers");
+constexpr const ImmutableString gl_MaxGeometryAtomicCounters("gl_MaxGeometryAtomicCounters");
+constexpr const ImmutableString gl_MaxGeometryImageUniforms("gl_MaxGeometryImageUniforms");
+constexpr const ImmutableString gl_MaxGeometryInputComponents("gl_MaxGeometryInputComponents");
+constexpr const ImmutableString gl_MaxGeometryOutputComponents("gl_MaxGeometryOutputComponents");
+constexpr const ImmutableString gl_MaxGeometryOutputVertices("gl_MaxGeometryOutputVertices");
+constexpr const ImmutableString gl_MaxGeometryTextureImageUnits("gl_MaxGeometryTextureImageUnits");
+constexpr const ImmutableString gl_MaxGeometryTotalOutputComponents(
+ "gl_MaxGeometryTotalOutputComponents");
+constexpr const ImmutableString gl_MaxGeometryUniformComponents("gl_MaxGeometryUniformComponents");
+constexpr const ImmutableString gl_MaxImageUnits("gl_MaxImageUnits");
+constexpr const ImmutableString gl_MaxProgramTexelOffset("gl_MaxProgramTexelOffset");
+constexpr const ImmutableString gl_MaxTextureImageUnits("gl_MaxTextureImageUnits");
+constexpr const ImmutableString gl_MaxVaryingVectors("gl_MaxVaryingVectors");
+constexpr const ImmutableString gl_MaxVertexAtomicCounterBuffers(
+ "gl_MaxVertexAtomicCounterBuffers");
+constexpr const ImmutableString gl_MaxVertexAtomicCounters("gl_MaxVertexAtomicCounters");
+constexpr const ImmutableString gl_MaxVertexAttribs("gl_MaxVertexAttribs");
+constexpr const ImmutableString gl_MaxVertexImageUniforms("gl_MaxVertexImageUniforms");
+constexpr const ImmutableString gl_MaxVertexOutputVectors("gl_MaxVertexOutputVectors");
+constexpr const ImmutableString gl_MaxVertexTextureImageUnits("gl_MaxVertexTextureImageUnits");
+constexpr const ImmutableString gl_MaxVertexUniformVectors("gl_MaxVertexUniformVectors");
+constexpr const ImmutableString gl_MinProgramTexelOffset("gl_MinProgramTexelOffset");
+constexpr const ImmutableString gl_NumWorkGroups("gl_NumWorkGroups");
+constexpr const ImmutableString gl_PerVertex("gl_PerVertex");
+constexpr const ImmutableString gl_PointCoord("gl_PointCoord");
+constexpr const ImmutableString gl_PointSize("gl_PointSize");
+constexpr const ImmutableString gl_Position("gl_Position");
+constexpr const ImmutableString gl_PrimitiveID("gl_PrimitiveID");
+constexpr const ImmutableString gl_PrimitiveIDIn("gl_PrimitiveIDIn");
+constexpr const ImmutableString gl_SecondaryFragColorEXT("gl_SecondaryFragColorEXT");
+constexpr const ImmutableString gl_SecondaryFragDataEXT("gl_SecondaryFragDataEXT");
+constexpr const ImmutableString gl_VertexID("gl_VertexID");
+constexpr const ImmutableString gl_ViewID_OVR("gl_ViewID_OVR");
+constexpr const ImmutableString gl_ViewportIndex("gl_ViewportIndex");
+constexpr const ImmutableString gl_WorkGroupID("gl_WorkGroupID");
+constexpr const ImmutableString gl_WorkGroupSize("gl_WorkGroupSize");
+constexpr const ImmutableString gl_in("gl_in");
+constexpr const ImmutableString greaterThan("greaterThan");
+constexpr const ImmutableString greaterThanEqual("greaterThanEqual");
+constexpr const ImmutableString groupMemoryBarrier("groupMemoryBarrier");
+constexpr const ImmutableString imageLoad("imageLoad");
+constexpr const ImmutableString imageSize("imageSize");
+constexpr const ImmutableString imageStore("imageStore");
+constexpr const ImmutableString imageStore_0h1C3D("imageStore(0h1C3D");
+constexpr const ImmutableString imageStore_0j2C3C("imageStore(0j2C3C");
+constexpr const ImmutableString imageStore_0l2C3B("imageStore(0l2C3B");
+constexpr const ImmutableString imageStore_0n2C3D("imageStore(0n2C3D");
+constexpr const ImmutableString imageStore_0p2C3C("imageStore(0p2C3C");
+constexpr const ImmutableString imulExtended("imulExtended");
+constexpr const ImmutableString imulExtended_0C0C0C0C("imulExtended(0C0C0C0C");
+constexpr const ImmutableString imulExtended_1C1C1C1C("imulExtended(1C1C1C1C");
+constexpr const ImmutableString imulExtended_2C2C2C2C("imulExtended(2C2C2C2C");
+constexpr const ImmutableString imulExtended_3C3C3C3C("imulExtended(3C3C3C3C");
+constexpr const ImmutableString intBitsToFloat("intBitsToFloat");
+constexpr const ImmutableString inverse("inverse");
+constexpr const ImmutableString inversesqrt("inversesqrt");
+constexpr const ImmutableString isinf("isinf");
+constexpr const ImmutableString isnan("isnan");
+constexpr const ImmutableString ldexp("ldexp");
+constexpr const ImmutableString length("length");
+constexpr const ImmutableString lessThan("lessThan");
+constexpr const ImmutableString lessThanEqual("lessThanEqual");
+constexpr const ImmutableString log("log");
+constexpr const ImmutableString log2("log2");
+constexpr const ImmutableString matrixCompMult("matrixCompMult");
+constexpr const ImmutableString max("max");
+constexpr const ImmutableString memoryBarrier("memoryBarrier");
+constexpr const ImmutableString memoryBarrierAtomicCounter("memoryBarrierAtomicCounter");
+constexpr const ImmutableString memoryBarrierBuffer("memoryBarrierBuffer");
+constexpr const ImmutableString memoryBarrierImage("memoryBarrierImage");
+constexpr const ImmutableString memoryBarrierShared("memoryBarrierShared");
+constexpr const ImmutableString min("min");
+constexpr const ImmutableString mix("mix");
+constexpr const ImmutableString mix_0B0B0E("mix(0B0B0E");
+constexpr const ImmutableString mix_1B1B1B("mix(1B1B1B");
+constexpr const ImmutableString mix_1B1B1E("mix(1B1B1E");
+constexpr const ImmutableString mix_3B3B0B("mix(3B3B0B");
+constexpr const ImmutableString mix_3B3B3B("mix(3B3B3B");
+constexpr const ImmutableString mod("mod");
+constexpr const ImmutableString modf("modf");
+constexpr const ImmutableString near("near");
+constexpr const ImmutableString normalize("normalize");
+constexpr const ImmutableString notEqual("notEqual");
+constexpr const ImmutableString notFunc("not");
+constexpr const ImmutableString outerProduct("outerProduct");
+constexpr const ImmutableString packHalf2x16("packHalf2x16");
+constexpr const ImmutableString packSnorm2x16("packSnorm2x16");
+constexpr const ImmutableString packSnorm4x8("packSnorm4x8");
+constexpr const ImmutableString packUnorm2x16("packUnorm2x16");
+constexpr const ImmutableString packUnorm4x8("packUnorm4x8");
+constexpr const ImmutableString pow("pow");
+constexpr const ImmutableString radians("radians");
+constexpr const ImmutableString reflect("reflect");
+constexpr const ImmutableString refract("refract");
+constexpr const ImmutableString refract_3B3B0B("refract(3B3B0B");
+constexpr const ImmutableString rgb_2_yuv("rgb_2_yuv");
+constexpr const ImmutableString round("round");
+constexpr const ImmutableString roundEven("roundEven");
+constexpr const ImmutableString sign("sign");
+constexpr const ImmutableString sin("sin");
+constexpr const ImmutableString sinh("sinh");
+constexpr const ImmutableString smoothstep("smoothstep");
+constexpr const ImmutableString smoothstep_0B0B3B("smoothstep(0B0B3B");
+constexpr const ImmutableString smoothstep_1B1B1B("smoothstep(1B1B1B");
+constexpr const ImmutableString smoothstep_3B3B3B("smoothstep(3B3B3B");
+constexpr const ImmutableString sqrt("sqrt");
+constexpr const ImmutableString step("step");
+constexpr const ImmutableString tan("tan");
+constexpr const ImmutableString tanh("tanh");
+constexpr const ImmutableString texelFetch("texelFetch");
+constexpr const ImmutableString texelFetchExt("texelFetch");
+constexpr const ImmutableString texelFetchExt_0O1C0C("texelFetch(0O1C0C");
+constexpr const ImmutableString texelFetchOffset("texelFetchOffset");
+constexpr const ImmutableString texelFetchOffset_0H1C0C1C("texelFetchOffset(0H1C0C1C");
+constexpr const ImmutableString texelFetchOffset_0I2C0C2C("texelFetchOffset(0I2C0C2C");
+constexpr const ImmutableString texelFetchOffset_0K2C0C1C("texelFetchOffset(0K2C0C1C");
+constexpr const ImmutableString texelFetchOffset_0Q1C0C1C("texelFetchOffset(0Q1C0C1C");
+constexpr const ImmutableString texelFetchOffset_0R2C0C2C("texelFetchOffset(0R2C0C2C");
+constexpr const ImmutableString texelFetchOffset_0T2C0C1C("texelFetchOffset(0T2C0C1C");
+constexpr const ImmutableString texelFetchOffset_0W1C0C1C("texelFetchOffset(0W1C0C1C");
+constexpr const ImmutableString texelFetchOffset_0X2C0C2C("texelFetchOffset(0X2C0C2C");
+constexpr const ImmutableString texelFetchOffset_0Z2C0C1C("texelFetchOffset(0Z2C0C1C");
+constexpr const ImmutableString texelFetch_0H1C0C("texelFetch(0H1C0C");
+constexpr const ImmutableString texelFetch_0I2C0C("texelFetch(0I2C0C");
+constexpr const ImmutableString texelFetch_0K2C0C("texelFetch(0K2C0C");
+constexpr const ImmutableString texelFetch_0L1C0C("texelFetch(0L1C0C");
+constexpr const ImmutableString texelFetch_0O1C0C("texelFetch(0O1C0C");
+constexpr const ImmutableString texelFetch_0P2C0C("texelFetch(0P2C0C");
+constexpr const ImmutableString texelFetch_0Q1C0C("texelFetch(0Q1C0C");
+constexpr const ImmutableString texelFetch_0T2C0C("texelFetch(0T2C0C");
+constexpr const ImmutableString texelFetch_0V2C0C("texelFetch(0V2C0C");
+constexpr const ImmutableString texelFetch_0X2C0C("texelFetch(0X2C0C");
+constexpr const ImmutableString texelFetch_0Z2C0C("texelFetch(0Z2C0C");
+constexpr const ImmutableString texture("texture");
+constexpr const ImmutableString texture2D("texture2D");
+constexpr const ImmutableString texture2DGradEXT("texture2DGradEXT");
+constexpr const ImmutableString texture2DGradEXT_0H1B1B1B("texture2DGradEXT(0H1B1B1B");
+constexpr const ImmutableString texture2DLod("texture2DLod");
+constexpr const ImmutableString texture2DLodEXT("texture2DLodEXT");
+constexpr const ImmutableString texture2DLodEXT_0H1B0B("texture2DLodEXT(0H1B0B");
+constexpr const ImmutableString texture2DLod_0H1B0B("texture2DLod(0H1B0B");
+constexpr const ImmutableString texture2DProj("texture2DProj");
+constexpr const ImmutableString texture2DProjGradEXT("texture2DProjGradEXT");
+constexpr const ImmutableString texture2DProjGradEXT_0H2B1B1B("texture2DProjGradEXT(0H2B1B1B");
+constexpr const ImmutableString texture2DProjGradEXT_0H3B1B1B("texture2DProjGradEXT(0H3B1B1B");
+constexpr const ImmutableString texture2DProjLod("texture2DProjLod");
+constexpr const ImmutableString texture2DProjLodEXT("texture2DProjLodEXT");
+constexpr const ImmutableString texture2DProjLodEXT_0H2B0B("texture2DProjLodEXT(0H2B0B");
+constexpr const ImmutableString texture2DProjLod_0H2B0B("texture2DProjLod(0H2B0B");
+constexpr const ImmutableString texture2DProj_0H2B0B("texture2DProj(0H2B0B");
+constexpr const ImmutableString texture2DRect("texture2DRect");
+constexpr const ImmutableString texture2DRectProj("texture2DRectProj");
+constexpr const ImmutableString texture3D("texture3D");
+constexpr const ImmutableString texture3DLod("texture3DLod");
+constexpr const ImmutableString texture3DProj("texture3DProj");
+constexpr const ImmutableString texture3DProjLod("texture3DProjLod");
+constexpr const ImmutableString texture3DProj_0I3B0B("texture3DProj(0I3B0B");
+constexpr const ImmutableString texture3D_0I2B0B("texture3D(0I2B0B");
+constexpr const ImmutableString textureCube("textureCube");
+constexpr const ImmutableString textureCubeGradEXT("textureCubeGradEXT");
+constexpr const ImmutableString textureCubeGradEXT_0J2B2B2B("textureCubeGradEXT(0J2B2B2B");
+constexpr const ImmutableString textureCubeLod("textureCubeLod");
+constexpr const ImmutableString textureCubeLodEXT("textureCubeLodEXT");
+constexpr const ImmutableString textureGather("textureGather");
+constexpr const ImmutableString textureGatherOffset("textureGatherOffset");
+constexpr const ImmutableString textureGatherOffset_0H1B1C0C("textureGatherOffset(0H1B1C0C");
+constexpr const ImmutableString textureGatherOffset_0K2B1C0C("textureGatherOffset(0K2B1C0C");
+constexpr const ImmutableString textureGatherOffset_0Q1B1C0C("textureGatherOffset(0Q1B1C0C");
+constexpr const ImmutableString textureGatherOffset_0T2B1C("textureGatherOffset(0T2B1C");
+constexpr const ImmutableString textureGatherOffset_0T2B1C0C("textureGatherOffset(0T2B1C0C");
+constexpr const ImmutableString textureGatherOffset_0W1B1C("textureGatherOffset(0W1B1C");
+constexpr const ImmutableString textureGatherOffset_0W1B1C0C("textureGatherOffset(0W1B1C0C");
+constexpr const ImmutableString textureGatherOffset_0Z2B1C0C("textureGatherOffset(0Z2B1C0C");
+constexpr const ImmutableString textureGatherOffset_0c1B0B1C("textureGatherOffset(0c1B0B1C");
+constexpr const ImmutableString textureGatherOffset_0e2B0B1C("textureGatherOffset(0e2B0B1C");
+constexpr const ImmutableString textureGather_0J2B0C("textureGather(0J2B0C");
+constexpr const ImmutableString textureGather_0S2B0C("textureGather(0S2B0C");
+constexpr const ImmutableString textureGather_0T2B0C("textureGather(0T2B0C");
+constexpr const ImmutableString textureGather_0Z2B0C("textureGather(0Z2B0C");
+constexpr const ImmutableString textureGrad("textureGrad");
+constexpr const ImmutableString textureGradOffset("textureGradOffset");
+constexpr const ImmutableString textureGradOffset_0H1B1B1B1C("textureGradOffset(0H1B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0I2B2B2B2C("textureGradOffset(0I2B2B2B2C");
+constexpr const ImmutableString textureGradOffset_0K2B1B1B1C("textureGradOffset(0K2B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0Q1B1B1B1C("textureGradOffset(0Q1B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0R2B2B2B2C("textureGradOffset(0R2B2B2B2C");
+constexpr const ImmutableString textureGradOffset_0T2B1B1B1C("textureGradOffset(0T2B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0W1B1B1B1C("textureGradOffset(0W1B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0X2B2B2B2C("textureGradOffset(0X2B2B2B2C");
+constexpr const ImmutableString textureGradOffset_0Z2B1B1B1C("textureGradOffset(0Z2B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0c2B1B1B1C("textureGradOffset(0c2B1B1B1C");
+constexpr const ImmutableString textureGradOffset_0e3B1B1B1C("textureGradOffset(0e3B1B1B1C");
+constexpr const ImmutableString textureGrad_0H1B1B1B("textureGrad(0H1B1B1B");
+constexpr const ImmutableString textureGrad_0I2B2B2B("textureGrad(0I2B2B2B");
+constexpr const ImmutableString textureGrad_0J2B2B2B("textureGrad(0J2B2B2B");
+constexpr const ImmutableString textureGrad_0K2B1B1B("textureGrad(0K2B1B1B");
+constexpr const ImmutableString textureGrad_0Q1B1B1B("textureGrad(0Q1B1B1B");
+constexpr const ImmutableString textureGrad_0R2B2B2B("textureGrad(0R2B2B2B");
+constexpr const ImmutableString textureGrad_0S2B2B2B("textureGrad(0S2B2B2B");
+constexpr const ImmutableString textureGrad_0T2B1B1B("textureGrad(0T2B1B1B");
+constexpr const ImmutableString textureGrad_0W1B1B1B("textureGrad(0W1B1B1B");
+constexpr const ImmutableString textureGrad_0X2B2B2B("textureGrad(0X2B2B2B");
+constexpr const ImmutableString textureGrad_0Y2B2B2B("textureGrad(0Y2B2B2B");
+constexpr const ImmutableString textureGrad_0Z2B1B1B("textureGrad(0Z2B1B1B");
+constexpr const ImmutableString textureGrad_0c2B1B1B("textureGrad(0c2B1B1B");
+constexpr const ImmutableString textureGrad_0d3B2B2B("textureGrad(0d3B2B2B");
+constexpr const ImmutableString textureGrad_0e3B1B1B("textureGrad(0e3B1B1B");
+constexpr const ImmutableString textureLod("textureLod");
+constexpr const ImmutableString textureLodOffset("textureLodOffset");
+constexpr const ImmutableString textureLodOffset_0H1B0B1C("textureLodOffset(0H1B0B1C");
+constexpr const ImmutableString textureLodOffset_0I2B0B2C("textureLodOffset(0I2B0B2C");
+constexpr const ImmutableString textureLodOffset_0K2B0B1C("textureLodOffset(0K2B0B1C");
+constexpr const ImmutableString textureLodOffset_0Q1B0B1C("textureLodOffset(0Q1B0B1C");
+constexpr const ImmutableString textureLodOffset_0R2B0B2C("textureLodOffset(0R2B0B2C");
+constexpr const ImmutableString textureLodOffset_0T2B0B1C("textureLodOffset(0T2B0B1C");
+constexpr const ImmutableString textureLodOffset_0W1B0B1C("textureLodOffset(0W1B0B1C");
+constexpr const ImmutableString textureLodOffset_0X2B0B2C("textureLodOffset(0X2B0B2C");
+constexpr const ImmutableString textureLodOffset_0Z2B0B1C("textureLodOffset(0Z2B0B1C");
+constexpr const ImmutableString textureLodOffset_0c2B0B1C("textureLodOffset(0c2B0B1C");
+constexpr const ImmutableString textureLod_0J2B0B("textureLod(0J2B0B");
+constexpr const ImmutableString textureLod_0Q1B0B("textureLod(0Q1B0B");
+constexpr const ImmutableString textureLod_0S2B0B("textureLod(0S2B0B");
+constexpr const ImmutableString textureLod_0W1B0B("textureLod(0W1B0B");
+constexpr const ImmutableString textureLod_0Y2B0B("textureLod(0Y2B0B");
+constexpr const ImmutableString textureLod_0Z2B0B("textureLod(0Z2B0B");
+constexpr const ImmutableString textureOffset("textureOffset");
+constexpr const ImmutableString textureOffset_0H1B1C0B("textureOffset(0H1B1C0B");
+constexpr const ImmutableString textureOffset_0I2B2C0B("textureOffset(0I2B2C0B");
+constexpr const ImmutableString textureOffset_0K2B1C0B("textureOffset(0K2B1C0B");
+constexpr const ImmutableString textureOffset_0Q1B1C0B("textureOffset(0Q1B1C0B");
+constexpr const ImmutableString textureOffset_0R2B2C0B("textureOffset(0R2B2C0B");
+constexpr const ImmutableString textureOffset_0T2B1C0B("textureOffset(0T2B1C0B");
+constexpr const ImmutableString textureOffset_0W1B1C0B("textureOffset(0W1B1C0B");
+constexpr const ImmutableString textureOffset_0X2B2C("textureOffset(0X2B2C");
+constexpr const ImmutableString textureOffset_0X2B2C0B("textureOffset(0X2B2C0B");
+constexpr const ImmutableString textureOffset_0Z2B1C0B("textureOffset(0Z2B1C0B");
+constexpr const ImmutableString textureOffset_0c2B1C0B("textureOffset(0c2B1C0B");
+constexpr const ImmutableString textureProj("textureProj");
+constexpr const ImmutableString textureProjGrad("textureProjGrad");
+constexpr const ImmutableString textureProjGradOffset("textureProjGradOffset");
+constexpr const ImmutableString textureProjGradOffset_0H2B1B1B1C(
+ "textureProjGradOffset(0H2B1B1B1C");
+constexpr const ImmutableString textureProjGradOffset_0H3B1B1B1C(
+ "textureProjGradOffset(0H3B1B1B1C");
+constexpr const ImmutableString textureProjGradOffset_0I3B2B2B2C(
+ "textureProjGradOffset(0I3B2B2B2C");
+constexpr const ImmutableString textureProjGradOffset_0Q2B1B1B1C(
+ "textureProjGradOffset(0Q2B1B1B1C");
+constexpr const ImmutableString textureProjGradOffset_0Q3B1B1B1C(
+ "textureProjGradOffset(0Q3B1B1B1C");
+constexpr const ImmutableString textureProjGradOffset_0R3B2B2B2C(
+ "textureProjGradOffset(0R3B2B2B2C");
+constexpr const ImmutableString textureProjGradOffset_0W2B1B1B1C(
+ "textureProjGradOffset(0W2B1B1B1C");
+constexpr const ImmutableString textureProjGradOffset_0W3B1B1B1C(
+ "textureProjGradOffset(0W3B1B1B1C");
+constexpr const ImmutableString textureProjGradOffset_0X3B2B2B2C(
+ "textureProjGradOffset(0X3B2B2B2C");
+constexpr const ImmutableString textureProjGradOffset_0c3B1B1B1C(
+ "textureProjGradOffset(0c3B1B1B1C");
+constexpr const ImmutableString textureProjGrad_0H2B1B1B("textureProjGrad(0H2B1B1B");
+constexpr const ImmutableString textureProjGrad_0H3B1B1B("textureProjGrad(0H3B1B1B");
+constexpr const ImmutableString textureProjGrad_0I3B2B2B("textureProjGrad(0I3B2B2B");
+constexpr const ImmutableString textureProjGrad_0Q2B1B1B("textureProjGrad(0Q2B1B1B");
+constexpr const ImmutableString textureProjGrad_0Q3B1B1B("textureProjGrad(0Q3B1B1B");
+constexpr const ImmutableString textureProjGrad_0R3B2B2B("textureProjGrad(0R3B2B2B");
+constexpr const ImmutableString textureProjGrad_0W2B1B1B("textureProjGrad(0W2B1B1B");
+constexpr const ImmutableString textureProjGrad_0W3B1B1B("textureProjGrad(0W3B1B1B");
+constexpr const ImmutableString textureProjGrad_0X3B2B2B("textureProjGrad(0X3B2B2B");
+constexpr const ImmutableString textureProjGrad_0c3B1B1B("textureProjGrad(0c3B1B1B");
+constexpr const ImmutableString textureProjLod("textureProjLod");
+constexpr const ImmutableString textureProjLodOffset("textureProjLodOffset");
+constexpr const ImmutableString textureProjLodOffset_0H2B0B1C("textureProjLodOffset(0H2B0B1C");
+constexpr const ImmutableString textureProjLodOffset_0H3B0B1C("textureProjLodOffset(0H3B0B1C");
+constexpr const ImmutableString textureProjLodOffset_0I3B0B2C("textureProjLodOffset(0I3B0B2C");
+constexpr const ImmutableString textureProjLodOffset_0Q2B0B1C("textureProjLodOffset(0Q2B0B1C");
+constexpr const ImmutableString textureProjLodOffset_0Q3B0B1C("textureProjLodOffset(0Q3B0B1C");
+constexpr const ImmutableString textureProjLodOffset_0R3B0B2C("textureProjLodOffset(0R3B0B2C");
+constexpr const ImmutableString textureProjLodOffset_0W2B0B1C("textureProjLodOffset(0W2B0B1C");
+constexpr const ImmutableString textureProjLodOffset_0W3B0B1C("textureProjLodOffset(0W3B0B1C");
+constexpr const ImmutableString textureProjLodOffset_0X3B0B2C("textureProjLodOffset(0X3B0B2C");
+constexpr const ImmutableString textureProjLodOffset_0c3B0B1C("textureProjLodOffset(0c3B0B1C");
+constexpr const ImmutableString textureProjLod_0H3B0B("textureProjLod(0H3B0B");
+constexpr const ImmutableString textureProjLod_0I3B0B("textureProjLod(0I3B0B");
+constexpr const ImmutableString textureProjLod_0Q2B0B("textureProjLod(0Q2B0B");
+constexpr const ImmutableString textureProjLod_0Q3B0B("textureProjLod(0Q3B0B");
+constexpr const ImmutableString textureProjOffset("textureProjOffset");
+constexpr const ImmutableString textureProjOffset_0H2B1C("textureProjOffset(0H2B1C");
+constexpr const ImmutableString textureProjOffset_0H2B1C0B("textureProjOffset(0H2B1C0B");
+constexpr const ImmutableString textureProjOffset_0H3B1C("textureProjOffset(0H3B1C");
+constexpr const ImmutableString textureProjOffset_0H3B1C0B("textureProjOffset(0H3B1C0B");
+constexpr const ImmutableString textureProjOffset_0I3B2C0B("textureProjOffset(0I3B2C0B");
+constexpr const ImmutableString textureProjOffset_0Q2B1C("textureProjOffset(0Q2B1C");
+constexpr const ImmutableString textureProjOffset_0Q2B1C0B("textureProjOffset(0Q2B1C0B");
+constexpr const ImmutableString textureProjOffset_0Q3B1C("textureProjOffset(0Q3B1C");
+constexpr const ImmutableString textureProjOffset_0Q3B1C0B("textureProjOffset(0Q3B1C0B");
+constexpr const ImmutableString textureProjOffset_0R3B2C0B("textureProjOffset(0R3B2C0B");
+constexpr const ImmutableString textureProjOffset_0W2B1C0B("textureProjOffset(0W2B1C0B");
+constexpr const ImmutableString textureProjOffset_0W3B1C("textureProjOffset(0W3B1C");
+constexpr const ImmutableString textureProjOffset_0W3B1C0B("textureProjOffset(0W3B1C0B");
+constexpr const ImmutableString textureProjOffset_0X3B2C("textureProjOffset(0X3B2C");
+constexpr const ImmutableString textureProjOffset_0X3B2C0B("textureProjOffset(0X3B2C0B");
+constexpr const ImmutableString textureProjOffset_0c3B1C0B("textureProjOffset(0c3B1C0B");
+constexpr const ImmutableString textureProj_0Q2B0B("textureProj(0Q2B0B");
+constexpr const ImmutableString textureProj_0R3B0B("textureProj(0R3B0B");
+constexpr const ImmutableString textureProj_0X3B0B("textureProj(0X3B0B");
+constexpr const ImmutableString textureSize("textureSize");
+constexpr const ImmutableString textureSizeExt("textureSize");
+constexpr const ImmutableString texture_0Q1B0B("texture(0Q1B0B");
+constexpr const ImmutableString texture_0c2B0B("texture(0c2B0B");
+constexpr const ImmutableString texture_0d3B0B("texture(0d3B0B");
+constexpr const ImmutableString transpose("transpose");
+constexpr const ImmutableString trunc("trunc");
+constexpr const ImmutableString uaddCarry("uaddCarry");
+constexpr const ImmutableString uaddCarry_2D2D2D("uaddCarry(2D2D2D");
+constexpr const ImmutableString uaddCarry_3D3D3D("uaddCarry(3D3D3D");
+constexpr const ImmutableString uintBitsToFloat("uintBitsToFloat");
+constexpr const ImmutableString umulExtended("umulExtended");
+constexpr const ImmutableString umulExtended_0D0D0D0D("umulExtended(0D0D0D0D");
+constexpr const ImmutableString umulExtended_1D1D1D1D("umulExtended(1D1D1D1D");
+constexpr const ImmutableString umulExtended_2D2D2D2D("umulExtended(2D2D2D2D");
+constexpr const ImmutableString umulExtended_3D3D3D3D("umulExtended(3D3D3D3D");
+constexpr const ImmutableString unpackHalf2x16("unpackHalf2x16");
+constexpr const ImmutableString unpackSnorm2x16("unpackSnorm2x16");
+constexpr const ImmutableString unpackSnorm4x8("unpackSnorm4x8");
+constexpr const ImmutableString unpackUnorm2x16("unpackUnorm2x16");
+constexpr const ImmutableString unpackUnorm4x8("unpackUnorm4x8");
+constexpr const ImmutableString usubBorrow("usubBorrow");
+constexpr const ImmutableString usubBorrow_0D0D0D("usubBorrow(0D0D0D");
+constexpr const ImmutableString usubBorrow_1D1D1D("usubBorrow(1D1D1D");
+constexpr const ImmutableString usubBorrow_3D3D3D("usubBorrow(3D3D3D");
+constexpr const ImmutableString yuv_2_rgb("yuv_2_rgb");
+
+} // namespace BuiltInName
+
+// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend
+// this from TVariable. Now symbol constructors taking an id have to be public even though they're
+// not supposed to be accessible from outside of here. http://anglebug.com/2390
+namespace BuiltInVariable
+{
+
+constexpr const TVariable kVar_gl_BaseInstance(
+ BuiltInId::gl_BaseInstance,
+ BuiltInName::gl_BaseInstance,
+ SymbolType::BuiltIn,
+ TExtension::ANGLE_base_vertex_base_instance,
+ StaticType::Get<EbtInt, EbpHigh, EvqBaseInstance, 1, 1>());
+constexpr const TVariable kVar_gl_BaseVertex(
+ BuiltInId::gl_BaseVertex,
+ BuiltInName::gl_BaseVertex,
+ SymbolType::BuiltIn,
+ TExtension::ANGLE_base_vertex_base_instance,
+ StaticType::Get<EbtInt, EbpHigh, EvqBaseVertex, 1, 1>());
+constexpr const TVariable kVar_gl_DrawID(BuiltInId::gl_DrawID,
+ BuiltInName::gl_DrawID,
+ SymbolType::BuiltIn,
+ TExtension::ANGLE_multi_draw,
+ StaticType::Get<EbtInt, EbpHigh, EvqDrawID, 1, 1>());
+constexpr const TVariable kVar_gl_DrawIDESSL1(BuiltInId::gl_DrawIDESSL1,
+ BuiltInName::gl_DrawID,
+ SymbolType::BuiltIn,
+ TExtension::ANGLE_multi_draw,
+ StaticType::Get<EbtInt, EbpHigh, EvqDrawID, 1, 1>());
+constexpr const TVariable kVar_gl_FragColor(
+ BuiltInId::gl_FragColor,
+ BuiltInName::gl_FragColor,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpMedium, EvqFragColor, 4, 1>());
+constexpr const TVariable kVar_gl_FragCoord(
+ BuiltInId::gl_FragCoord,
+ BuiltInName::gl_FragCoord,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpMedium, EvqFragCoord, 4, 1>());
+constexpr const TVariable kVar_gl_FragDepth(
+ BuiltInId::gl_FragDepth,
+ BuiltInName::gl_FragDepth,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpHigh, EvqFragDepth, 1, 1>());
+constexpr const TVariable kVar_gl_FrontFacing(
+ BuiltInId::gl_FrontFacing,
+ BuiltInName::gl_FrontFacing,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtBool, EbpUndefined, EvqFrontFacing, 1, 1>());
+constexpr const TVariable kVar_gl_GlobalInvocationID(
+ BuiltInId::gl_GlobalInvocationID,
+ BuiltInName::gl_GlobalInvocationID,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobalInvocationID, 3, 1>());
+constexpr const TVariable kVar_gl_InstanceID(
+ BuiltInId::gl_InstanceID,
+ BuiltInName::gl_InstanceID,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpHigh, EvqInstanceID, 1, 1>());
+constexpr const TVariable kVar_gl_InvocationID(
+ BuiltInId::gl_InvocationID,
+ BuiltInName::gl_InvocationID,
+ SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpHigh, EvqInvocationID, 1, 1>());
+constexpr const TVariable kVar_gl_LastFragColor(
+ BuiltInId::gl_LastFragColor,
+ BuiltInName::gl_LastFragColor,
+ SymbolType::BuiltIn,
+ TExtension::NV_shader_framebuffer_fetch,
+ StaticType::Get<EbtFloat, EbpMedium, EvqLastFragColor, 4, 1>());
+constexpr const TVariable kVar_gl_LastFragColorARM(
+ BuiltInId::gl_LastFragColorARM,
+ BuiltInName::gl_LastFragColorARM,
+ SymbolType::BuiltIn,
+ TExtension::ARM_shader_framebuffer_fetch,
+ StaticType::Get<EbtFloat, EbpMedium, EvqLastFragColor, 4, 1>());
+constexpr const TVariable kVar_gl_Layer(BuiltInId::gl_Layer,
+ BuiltInName::gl_Layer,
+ SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpHigh, EvqLayer, 1, 1>());
+constexpr const TVariable kVar_gl_LayerGS(BuiltInId::gl_LayerGS,
+ BuiltInName::gl_Layer,
+ SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpHigh, EvqLayer, 1, 1>());
+constexpr const TVariable kVar_gl_LayerVS(BuiltInId::gl_LayerVS,
+ BuiltInName::gl_Layer,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpHigh, EvqLayer, 1, 1>());
+constexpr const TVariable kVar_gl_LocalInvocationID(
+ BuiltInId::gl_LocalInvocationID,
+ BuiltInName::gl_LocalInvocationID,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqLocalInvocationID, 3, 1>());
+constexpr const TVariable kVar_gl_LocalInvocationIndex(
+ BuiltInId::gl_LocalInvocationIndex,
+ BuiltInName::gl_LocalInvocationIndex,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqLocalInvocationIndex, 1, 1>());
+constexpr const TVariable kVar_gl_NumWorkGroups(
+ BuiltInId::gl_NumWorkGroups,
+ BuiltInName::gl_NumWorkGroups,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqNumWorkGroups, 3, 1>());
+constexpr const TVariable kVar_gl_PointCoord(
+ BuiltInId::gl_PointCoord,
+ BuiltInName::gl_PointCoord,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpMedium, EvqPointCoord, 2, 1>());
+constexpr const TVariable kVar_gl_PointSize(
+ BuiltInId::gl_PointSize,
+ BuiltInName::gl_PointSize,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpMedium, EvqPointSize, 1, 1>());
+constexpr const TVariable kVar_gl_Position(BuiltInId::gl_Position,
+ BuiltInName::gl_Position,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpHigh, EvqPosition, 4, 1>());
+constexpr const TVariable kVar_gl_PrimitiveID(
+ BuiltInId::gl_PrimitiveID,
+ BuiltInName::gl_PrimitiveID,
+ SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpHigh, EvqPrimitiveID, 1, 1>());
+constexpr const TVariable kVar_gl_PrimitiveIDGS(
+ BuiltInId::gl_PrimitiveIDGS,
+ BuiltInName::gl_PrimitiveID,
+ SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpHigh, EvqPrimitiveID, 1, 1>());
+constexpr const TVariable kVar_gl_PrimitiveIDIn(
+ BuiltInId::gl_PrimitiveIDIn,
+ BuiltInName::gl_PrimitiveIDIn,
+ SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpHigh, EvqPrimitiveIDIn, 1, 1>());
+constexpr const TVariable kVar_gl_SecondaryFragColorEXT(
+ BuiltInId::gl_SecondaryFragColorEXT,
+ BuiltInName::gl_SecondaryFragColorEXT,
+ SymbolType::BuiltIn,
+ TExtension::EXT_blend_func_extended,
+ StaticType::Get<EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4, 1>());
+constexpr const TVariable kVar_gl_VertexID(BuiltInId::gl_VertexID,
+ BuiltInName::gl_VertexID,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpHigh, EvqVertexID, 1, 1>());
+constexpr const TVariable kVar_gl_ViewID_OVR(
+ BuiltInId::gl_ViewID_OVR,
+ BuiltInName::gl_ViewID_OVR,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpHigh, EvqViewIDOVR, 1, 1>());
+constexpr const TVariable kVar_gl_ViewID_OVRESSL1(
+ BuiltInId::gl_ViewID_OVRESSL1,
+ BuiltInName::gl_ViewID_OVR,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpHigh, EvqViewIDOVR, 1, 1>());
+constexpr const TVariable kVar_gl_ViewportIndex(
+ BuiltInId::gl_ViewportIndex,
+ BuiltInName::gl_ViewportIndex,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpHigh, EvqViewportIndex, 1, 1>());
+constexpr const TVariable kVar_gl_WorkGroupID(
+ BuiltInId::gl_WorkGroupID,
+ BuiltInName::gl_WorkGroupID,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqWorkGroupID, 3, 1>());
+constexpr const TVariable kVar_gl_WorkGroupSize(
+ BuiltInId::gl_WorkGroupSize,
+ BuiltInName::gl_WorkGroupSize,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqWorkGroupSize, 3, 1>());
+constexpr const TVariable kVar_pt0B(BuiltInId::pt0B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0C(BuiltInId::pt0C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0D(BuiltInId::pt0D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0E(BuiltInId::pt0E,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0F(
+ BuiltInId::pt0F,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtAtomicCounter, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0G(
+ BuiltInId::pt0G,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtYuvCscStandardEXT, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0H(BuiltInId::pt0H,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0I(BuiltInId::pt0I,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler3D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0J(
+ BuiltInId::pt0J,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSamplerCube, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0K(
+ BuiltInId::pt0K,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2DArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0L(
+ BuiltInId::pt0L,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSamplerExternalOES, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0M(
+ BuiltInId::pt0M,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSamplerExternal2DY2YEXT, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0N(
+ BuiltInId::pt0N,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2DRect, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0O(
+ BuiltInId::pt0O,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2DMS, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0P(
+ BuiltInId::pt0P,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2DMSArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0Q(
+ BuiltInId::pt0Q,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtISampler2D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0R(
+ BuiltInId::pt0R,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtISampler3D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0S(
+ BuiltInId::pt0S,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtISamplerCube, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0T(
+ BuiltInId::pt0T,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtISampler2DArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0U(
+ BuiltInId::pt0U,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtISampler2DMS, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0V(
+ BuiltInId::pt0V,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtISampler2DMSArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0W(
+ BuiltInId::pt0W,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUSampler2D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0X(
+ BuiltInId::pt0X,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUSampler3D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0Y(
+ BuiltInId::pt0Y,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUSamplerCube, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0Z(
+ BuiltInId::pt0Z,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUSampler2DArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0a(
+ BuiltInId::pt0a,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUSampler2DMS, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0b(
+ BuiltInId::pt0b,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUSampler2DMSArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0c(
+ BuiltInId::pt0c,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2DShadow, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0d(
+ BuiltInId::pt0d,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSamplerCubeShadow, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0e(
+ BuiltInId::pt0e,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtSampler2DArrayShadow, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0f(BuiltInId::pt0f,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtImage2D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0g(BuiltInId::pt0g,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtIImage2D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0h(BuiltInId::pt0h,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUImage2D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0i(BuiltInId::pt0i,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtImage3D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0j(BuiltInId::pt0j,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtIImage3D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0k(BuiltInId::pt0k,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUImage3D, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0l(
+ BuiltInId::pt0l,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtImage2DArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0m(
+ BuiltInId::pt0m,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtIImage2DArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0n(
+ BuiltInId::pt0n,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUImage2DArray, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0o(BuiltInId::pt0o,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtImageCube, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0p(
+ BuiltInId::pt0p,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtIImageCube, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt0q(
+ BuiltInId::pt0q,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUImageCube, EbpUndefined, EvqGlobal, 1, 1>());
+constexpr const TVariable kVar_pt1B(BuiltInId::pt1B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>());
+constexpr const TVariable kVar_pt1C(BuiltInId::pt1C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>());
+constexpr const TVariable kVar_pt1D(BuiltInId::pt1D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>());
+constexpr const TVariable kVar_pt1E(BuiltInId::pt1E,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>());
+constexpr const TVariable kVar_pt2B(BuiltInId::pt2B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>());
+constexpr const TVariable kVar_pt2C(BuiltInId::pt2C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>());
+constexpr const TVariable kVar_pt2D(BuiltInId::pt2D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>());
+constexpr const TVariable kVar_pt2E(BuiltInId::pt2E,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>());
+constexpr const TVariable kVar_pt3B(BuiltInId::pt3B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>());
+constexpr const TVariable kVar_pt3C(BuiltInId::pt3C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>());
+constexpr const TVariable kVar_pt3D(BuiltInId::pt3D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>());
+constexpr const TVariable kVar_pt3E(BuiltInId::pt3E,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>());
+constexpr const TVariable kVar_pt5B(BuiltInId::pt5B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>());
+constexpr const TVariable kVar_pt6B(BuiltInId::pt6B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>());
+constexpr const TVariable kVar_pt7B(BuiltInId::pt7B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>());
+constexpr const TVariable kVar_pt9B(BuiltInId::pt9B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>());
+constexpr const TVariable kVar_ptAB(BuiltInId::ptAB,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>());
+constexpr const TVariable kVar_ptBB(BuiltInId::ptBB,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>());
+constexpr const TVariable kVar_ptDB(BuiltInId::ptDB,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>());
+constexpr const TVariable kVar_ptEB(BuiltInId::ptEB,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>());
+constexpr const TVariable kVar_ptFB(BuiltInId::ptFB,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>());
+constexpr const TVariable kVar_pt_io_0C(BuiltInId::pt_io_0C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqInOut, 1, 1>());
+constexpr const TVariable kVar_pt_io_0D(BuiltInId::pt_io_0D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqInOut, 1, 1>());
+constexpr const TVariable kVar_pt_o_0B(BuiltInId::pt_o_0B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 1, 1>());
+constexpr const TVariable kVar_pt_o_0C(BuiltInId::pt_o_0C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqOut, 1, 1>());
+constexpr const TVariable kVar_pt_o_0D(BuiltInId::pt_o_0D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 1, 1>());
+constexpr const TVariable kVar_pt_o_1B(BuiltInId::pt_o_1B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 2, 1>());
+constexpr const TVariable kVar_pt_o_1C(BuiltInId::pt_o_1C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqOut, 2, 1>());
+constexpr const TVariable kVar_pt_o_1D(BuiltInId::pt_o_1D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 2, 1>());
+constexpr const TVariable kVar_pt_o_2B(BuiltInId::pt_o_2B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 3, 1>());
+constexpr const TVariable kVar_pt_o_2C(BuiltInId::pt_o_2C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqOut, 3, 1>());
+constexpr const TVariable kVar_pt_o_2D(BuiltInId::pt_o_2D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 3, 1>());
+constexpr const TVariable kVar_pt_o_3B(BuiltInId::pt_o_3B,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 4, 1>());
+constexpr const TVariable kVar_pt_o_3C(BuiltInId::pt_o_3C,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpUndefined, EvqOut, 4, 1>());
+constexpr const TVariable kVar_pt_o_3D(BuiltInId::pt_o_3D,
+ BuiltInName::_empty,
+ SymbolType::BuiltIn,
+ TExtension::UNDEFINED,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 4, 1>());
+
+const TVariable *gl_BaseInstance()
+{
+ return &kVar_gl_BaseInstance;
+}
+
+const TVariable *gl_BaseVertex()
+{
+ return &kVar_gl_BaseVertex;
+}
+
+const TVariable *gl_DrawID()
+{
+ return &kVar_gl_DrawID;
+}
+
+const TVariable *gl_DrawIDESSL1()
+{
+ return &kVar_gl_DrawIDESSL1;
+}
+
+const TVariable *gl_FragColor()
+{
+ return &kVar_gl_FragColor;
+}
+
+const TVariable *gl_FragCoord()
+{
+ return &kVar_gl_FragCoord;
+}
+
+const TVariable *gl_FragDepth()
+{
+ return &kVar_gl_FragDepth;
+}
+
+const TVariable *gl_FrontFacing()
+{
+ return &kVar_gl_FrontFacing;
+}
+
+const TVariable *gl_GlobalInvocationID()
+{
+ return &kVar_gl_GlobalInvocationID;
+}
+
+const TVariable *gl_InstanceID()
+{
+ return &kVar_gl_InstanceID;
+}
+
+const TVariable *gl_InvocationID()
+{
+ return &kVar_gl_InvocationID;
+}
+
+const TVariable *gl_LastFragColor()
+{
+ return &kVar_gl_LastFragColor;
+}
+
+const TVariable *gl_LastFragColorARM()
+{
+ return &kVar_gl_LastFragColorARM;
+}
+
+const TVariable *gl_Layer()
+{
+ return &kVar_gl_Layer;
+}
+
+const TVariable *gl_LayerGS()
+{
+ return &kVar_gl_LayerGS;
+}
+
+const TVariable *gl_LayerVS()
+{
+ return &kVar_gl_LayerVS;
+}
+
+const TVariable *gl_LocalInvocationID()
+{
+ return &kVar_gl_LocalInvocationID;
+}
+
+const TVariable *gl_LocalInvocationIndex()
+{
+ return &kVar_gl_LocalInvocationIndex;
+}
+
+const TVariable *gl_NumWorkGroups()
+{
+ return &kVar_gl_NumWorkGroups;
+}
+
+const TVariable *gl_PointCoord()
+{
+ return &kVar_gl_PointCoord;
+}
+
+const TVariable *gl_PointSize()
+{
+ return &kVar_gl_PointSize;
+}
+
+const TVariable *gl_Position()
+{
+ return &kVar_gl_Position;
+}
+
+const TVariable *gl_PrimitiveID()
+{
+ return &kVar_gl_PrimitiveID;
+}
+
+const TVariable *gl_PrimitiveIDGS()
+{
+ return &kVar_gl_PrimitiveIDGS;
+}
+
+const TVariable *gl_PrimitiveIDIn()
+{
+ return &kVar_gl_PrimitiveIDIn;
+}
+
+const TVariable *gl_SecondaryFragColorEXT()
+{
+ return &kVar_gl_SecondaryFragColorEXT;
+}
+
+const TVariable *gl_VertexID()
+{
+ return &kVar_gl_VertexID;
+}
+
+const TVariable *gl_ViewID_OVR()
+{
+ return &kVar_gl_ViewID_OVR;
+}
+
+const TVariable *gl_ViewID_OVRESSL1()
+{
+ return &kVar_gl_ViewID_OVRESSL1;
+}
+
+const TVariable *gl_ViewportIndex()
+{
+ return &kVar_gl_ViewportIndex;
+}
+
+const TVariable *gl_WorkGroupID()
+{
+ return &kVar_gl_WorkGroupID;
+}
+
+const TVariable *gl_WorkGroupSize()
+{
+ return &kVar_gl_WorkGroupSize;
+}
+
+} // namespace BuiltInVariable
+
+namespace BuiltInParameters
+{
+
+constexpr const TVariable **empty = nullptr;
+constexpr const TVariable *p0B0B0B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0B0B0E[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt0E};
+constexpr const TVariable *p0B0B1B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1B};
+constexpr const TVariable *p0B0B2B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0B0B3B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0B0C[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0B1B[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt1B};
+constexpr const TVariable *p0B2B[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0B3B[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0B_o_0B[2] = {&BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt_o_0B};
+constexpr const TVariable *p0B_o_0C[2] = {&BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt_o_0C};
+constexpr const TVariable *p0C0C0C0C[4] = {&BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0C0C_o_0C_o_0C[4] = {
+ &BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt_o_0C,
+ &BuiltInVariable::kVar_pt_o_0C};
+constexpr const TVariable *p0D0C0C[3] = {&BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0D0D0C0C[4] = {&BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0D0D0D[3] = {&BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D,
+ &BuiltInVariable::kVar_pt0D};
+constexpr const TVariable *p0D0D_o_0D_o_0D[4] = {
+ &BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt_o_0D,
+ &BuiltInVariable::kVar_pt_o_0D};
+constexpr const TVariable *p0F[1] = {&BuiltInVariable::kVar_pt0F};
+constexpr const TVariable *p0H0C[2] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0H1B0B1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H1B0C[3] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0H1B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H1B1C0B[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0H1B1C0C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0H1C0C1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H2B0B1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H2B1C0B[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0H3B0B1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H3B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0H3B1C0B[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0I0C[2] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0I2B0B2C[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0I2B2B2B2C[5] = {
+ &BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0I2B2C0B[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0I2C0C2C[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0I3B0B2C[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0I3B2B2B2C[5] = {
+ &BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0I3B2C0B[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0J0C[2] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0J2B0B[3] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0J2B0C[3] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0J2B2B2B[4] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0K0C[2] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0K2B0B1C[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0K2B0C[3] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0K2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0K2B1C0B[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0K2B1C0C[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0K2C0C1C[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0L0C[2] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0L1B0B[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0L1C0C[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0L2B0B[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0L3B0B[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0M0C[2] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0M1B0B[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0M1C0C[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0M2B0B[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0M3B0B[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0N1B[2] = {&BuiltInVariable::kVar_pt0N, &BuiltInVariable::kVar_pt1B};
+constexpr const TVariable *p0N2B[2] = {&BuiltInVariable::kVar_pt0N, &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0N3B[2] = {&BuiltInVariable::kVar_pt0N, &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0O1C0C[3] = {&BuiltInVariable::kVar_pt0O, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0P2C0C[3] = {&BuiltInVariable::kVar_pt0P, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Q0C[2] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Q1B0B1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q1B0C[3] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Q1B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q1B1C0B[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0Q1B1C0C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Q1C0C1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q2B0B1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q2B1C0B[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0Q3B0B1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q3B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Q3B1C0B[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0R0C[2] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0R2B0B2C[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0R2B2B2B2C[5] = {
+ &BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0R2B2C0B[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0R2C0C2C[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0R3B0B2C[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0R3B2B2B2C[5] = {
+ &BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0R3B2C0B[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0S0C[2] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0S2B0B[3] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0S2B0C[3] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0S2B2B2B[4] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0T0C[2] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0T2B0B1C[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0T2B0C[3] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0T2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0T2B1C0B[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0T2B1C0C[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0T2C0C1C[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0U1C0C[3] = {&BuiltInVariable::kVar_pt0U, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0V2C0C[3] = {&BuiltInVariable::kVar_pt0V, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0W0C[2] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0W1B0B1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W1B0C[3] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0W1B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W1B1C0B[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0W1B1C0C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0W1C0C1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W2B0B1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W2B1C0B[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0W3B0B1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W3B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0W3B1C0B[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0X0C[2] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0X2B0B2C[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0X2B2B2B2C[5] = {
+ &BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0X2B2C0B[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0X2C0C2C[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0X3B0B2C[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0X3B2B2B2C[5] = {
+ &BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p0X3B2C0B[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0Y0C[2] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Y2B0B[3] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0Y2B0C[3] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Y2B2B2B[4] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0Z0C[2] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Z2B0B1C[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Z2B0C[3] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Z2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0Z2B1C0B[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0Z2B1C0C[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0Z2C0C1C[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0a1C0C[3] = {&BuiltInVariable::kVar_pt0a, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0b2C0C[3] = {&BuiltInVariable::kVar_pt0b, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0c0C[2] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0c1B0B1C[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0c2B0B1C[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0c2B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0c2B1C0B[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0c3B0B1C[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0c3B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0c3B1C0B[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0d0C[2] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0d2B0B[3] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0d3B0B[3] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p0d3B2B2B[4] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p0e0C[2] = {&BuiltInVariable::kVar_pt0e, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p0e2B0B1C[4] = {&BuiltInVariable::kVar_pt0e, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0e3B1B1B1C[5] = {
+ &BuiltInVariable::kVar_pt0e, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p0f1C3B[3] = {&BuiltInVariable::kVar_pt0f, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0g1C3C[3] = {&BuiltInVariable::kVar_pt0g, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt3C};
+constexpr const TVariable *p0h1C3D[3] = {&BuiltInVariable::kVar_pt0h, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt3D};
+constexpr const TVariable *p0i2C3B[3] = {&BuiltInVariable::kVar_pt0i, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0j2C3C[3] = {&BuiltInVariable::kVar_pt0j, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3C};
+constexpr const TVariable *p0k2C3D[3] = {&BuiltInVariable::kVar_pt0k, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3D};
+constexpr const TVariable *p0l2C3B[3] = {&BuiltInVariable::kVar_pt0l, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0m2C3C[3] = {&BuiltInVariable::kVar_pt0m, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3C};
+constexpr const TVariable *p0n2C3D[3] = {&BuiltInVariable::kVar_pt0n, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3D};
+constexpr const TVariable *p0o2C3B[3] = {&BuiltInVariable::kVar_pt0o, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p0p2C3C[3] = {&BuiltInVariable::kVar_pt0p, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3C};
+constexpr const TVariable *p0q2C3D[3] = {&BuiltInVariable::kVar_pt0q, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt3D};
+constexpr const TVariable *p1B0B0B[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p1B1B0B[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p1B1B1B[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1B};
+constexpr const TVariable *p1B1B1E[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt1E};
+constexpr const TVariable *p1B1C[2] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p1B2B[2] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p1B3B[2] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p1B_o_1B[2] = {&BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt_o_1B};
+constexpr const TVariable *p1B_o_1C[2] = {&BuiltInVariable::kVar_pt1B,
+ &BuiltInVariable::kVar_pt_o_1C};
+constexpr const TVariable *p1C0C0C[3] = {&BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p1C1C0C0C[4] = {&BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p1C1C1C[3] = {&BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt1C,
+ &BuiltInVariable::kVar_pt1C};
+constexpr const TVariable *p1C1C_o_1C_o_1C[4] = {
+ &BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt_o_1C,
+ &BuiltInVariable::kVar_pt_o_1C};
+constexpr const TVariable *p1D0C0C[3] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p1D0D0D[3] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt0D,
+ &BuiltInVariable::kVar_pt0D};
+constexpr const TVariable *p1D1D0C0C[4] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt1D,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p1D1D1D[3] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt1D,
+ &BuiltInVariable::kVar_pt1D};
+constexpr const TVariable *p1D1D_o_1D_o_1D[4] = {
+ &BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt_o_1D,
+ &BuiltInVariable::kVar_pt_o_1D};
+constexpr const TVariable *p1E1E[2] = {&BuiltInVariable::kVar_pt1E, &BuiltInVariable::kVar_pt1E};
+constexpr const TVariable *p2B0B0B[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p2B0G[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt0G};
+constexpr const TVariable *p2B1B[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B};
+constexpr const TVariable *p2B2B0B[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p2B2B2B[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p2B2B2E[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt2E};
+constexpr const TVariable *p2B2C[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p2B3B[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p2B_o_2B[2] = {&BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt_o_2B};
+constexpr const TVariable *p2B_o_2C[2] = {&BuiltInVariable::kVar_pt2B,
+ &BuiltInVariable::kVar_pt_o_2C};
+constexpr const TVariable *p2C0C0C[3] = {&BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p2C2C0C0C[4] = {&BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p2C2C2C[3] = {&BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt2C,
+ &BuiltInVariable::kVar_pt2C};
+constexpr const TVariable *p2C2C_o_2C_o_2C[4] = {
+ &BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt_o_2C,
+ &BuiltInVariable::kVar_pt_o_2C};
+constexpr const TVariable *p2D0C0C[3] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p2D0D0D[3] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt0D,
+ &BuiltInVariable::kVar_pt0D};
+constexpr const TVariable *p2D2D0C0C[4] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt2D,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p2D2D2D[3] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt2D,
+ &BuiltInVariable::kVar_pt2D};
+constexpr const TVariable *p2D2D_o_2D_o_2D[4] = {
+ &BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt_o_2D,
+ &BuiltInVariable::kVar_pt_o_2D};
+constexpr const TVariable *p2E2E[2] = {&BuiltInVariable::kVar_pt2E, &BuiltInVariable::kVar_pt2E};
+constexpr const TVariable *p3B0B0B[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt0B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p3B1B[2] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B};
+constexpr const TVariable *p3B2B[2] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B};
+constexpr const TVariable *p3B3B0B[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt0B};
+constexpr const TVariable *p3B3B3B[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt3B};
+constexpr const TVariable *p3B3B3E[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt3E};
+constexpr const TVariable *p3B3C[2] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3C};
+constexpr const TVariable *p3B_o_3B[2] = {&BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt_o_3B};
+constexpr const TVariable *p3B_o_3C[2] = {&BuiltInVariable::kVar_pt3B,
+ &BuiltInVariable::kVar_pt_o_3C};
+constexpr const TVariable *p3C0C0C[3] = {&BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p3C3C0C0C[4] = {&BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt3C,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p3C3C3C[3] = {&BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt3C,
+ &BuiltInVariable::kVar_pt3C};
+constexpr const TVariable *p3C3C_o_3C_o_3C[4] = {
+ &BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt_o_3C,
+ &BuiltInVariable::kVar_pt_o_3C};
+constexpr const TVariable *p3D0C0C[3] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p3D0D0D[3] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt0D,
+ &BuiltInVariable::kVar_pt0D};
+constexpr const TVariable *p3D3D0C0C[4] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt3D,
+ &BuiltInVariable::kVar_pt0C,
+ &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p3D3D3D[3] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt3D,
+ &BuiltInVariable::kVar_pt3D};
+constexpr const TVariable *p3D3D_o_3D_o_3D[4] = {
+ &BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt_o_3D,
+ &BuiltInVariable::kVar_pt_o_3D};
+constexpr const TVariable *p3E3E[2] = {&BuiltInVariable::kVar_pt3E, &BuiltInVariable::kVar_pt3E};
+constexpr const TVariable *p5B5B[2] = {&BuiltInVariable::kVar_pt5B, &BuiltInVariable::kVar_pt5B};
+constexpr const TVariable *p6B6B[2] = {&BuiltInVariable::kVar_pt6B, &BuiltInVariable::kVar_pt6B};
+constexpr const TVariable *p7B7B[2] = {&BuiltInVariable::kVar_pt7B, &BuiltInVariable::kVar_pt7B};
+constexpr const TVariable *p9B9B[2] = {&BuiltInVariable::kVar_pt9B, &BuiltInVariable::kVar_pt9B};
+constexpr const TVariable *pABAB[2] = {&BuiltInVariable::kVar_ptAB, &BuiltInVariable::kVar_ptAB};
+constexpr const TVariable *pBBBB[2] = {&BuiltInVariable::kVar_ptBB, &BuiltInVariable::kVar_ptBB};
+constexpr const TVariable *pDBDB[2] = {&BuiltInVariable::kVar_ptDB, &BuiltInVariable::kVar_ptDB};
+constexpr const TVariable *pEBEB[2] = {&BuiltInVariable::kVar_ptEB, &BuiltInVariable::kVar_ptEB};
+constexpr const TVariable *pFBFB[2] = {&BuiltInVariable::kVar_ptFB, &BuiltInVariable::kVar_ptFB};
+constexpr const TVariable *p_io_0C0C0C[3] = {
+ &BuiltInVariable::kVar_pt_io_0C, &BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt0C};
+constexpr const TVariable *p_io_0D0D0D[3] = {
+ &BuiltInVariable::kVar_pt_io_0D, &BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D};
+
+} // namespace BuiltInParameters
+
+namespace UnmangledBuiltIns
+{
+
+constexpr const UnmangledBuiltIn ARB_texture_rectangle(TExtension::ARB_texture_rectangle);
+constexpr const UnmangledBuiltIn EXT_YUV_target(TExtension::EXT_YUV_target);
+constexpr const UnmangledBuiltIn EXT_geometry_shader(TExtension::EXT_geometry_shader);
+constexpr const UnmangledBuiltIn EXT_shader_texture_lod(TExtension::EXT_shader_texture_lod);
+constexpr const UnmangledBuiltIn OES_standard_derivatives(TExtension::OES_standard_derivatives);
+constexpr const UnmangledBuiltIn OES_texture_3D(TExtension::OES_texture_3D);
+constexpr const UnmangledBuiltIn UNDEFINED(TExtension::UNDEFINED);
+
+} // namespace UnmangledBuiltIns
+
+// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend
+// this from TFunction. Now symbol constructors taking an id have to be public even though they're
+// not supposed to be accessible from outside of here. http://anglebug.com/2390
+namespace BuiltInFunction
+{
+
+constexpr const TFunction kFunction_radians_0B(
+ BuiltInId::radians_Float1,
+ BuiltInName::radians,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpRadians,
+ true);
+constexpr const TFunction kFunction_radians_1B(
+ BuiltInId::radians_Float2,
+ BuiltInName::radians,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpRadians,
+ true);
+constexpr const TFunction kFunction_radians_2B(
+ BuiltInId::radians_Float3,
+ BuiltInName::radians,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpRadians,
+ true);
+constexpr const TFunction kFunction_radians_3B(
+ BuiltInId::radians_Float4,
+ BuiltInName::radians,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpRadians,
+ true);
+constexpr const TFunction kFunction_degrees_0B(
+ BuiltInId::degrees_Float1,
+ BuiltInName::degrees,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDegrees,
+ true);
+constexpr const TFunction kFunction_degrees_1B(
+ BuiltInId::degrees_Float2,
+ BuiltInName::degrees,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpDegrees,
+ true);
+constexpr const TFunction kFunction_degrees_2B(
+ BuiltInId::degrees_Float3,
+ BuiltInName::degrees,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpDegrees,
+ true);
+constexpr const TFunction kFunction_degrees_3B(
+ BuiltInId::degrees_Float4,
+ BuiltInName::degrees,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpDegrees,
+ true);
+constexpr const TFunction kFunction_sin_0B(
+ BuiltInId::sin_Float1,
+ BuiltInName::sin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpSin,
+ true);
+constexpr const TFunction kFunction_sin_1B(
+ BuiltInId::sin_Float2,
+ BuiltInName::sin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSin,
+ true);
+constexpr const TFunction kFunction_sin_2B(
+ BuiltInId::sin_Float3,
+ BuiltInName::sin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSin,
+ true);
+constexpr const TFunction kFunction_sin_3B(
+ BuiltInId::sin_Float4,
+ BuiltInName::sin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSin,
+ true);
+constexpr const TFunction kFunction_cos_0B(
+ BuiltInId::cos_Float1,
+ BuiltInName::cos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCos,
+ true);
+constexpr const TFunction kFunction_cos_1B(
+ BuiltInId::cos_Float2,
+ BuiltInName::cos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCos,
+ true);
+constexpr const TFunction kFunction_cos_2B(
+ BuiltInId::cos_Float3,
+ BuiltInName::cos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCos,
+ true);
+constexpr const TFunction kFunction_cos_3B(
+ BuiltInId::cos_Float4,
+ BuiltInName::cos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCos,
+ true);
+constexpr const TFunction kFunction_tan_0B(
+ BuiltInId::tan_Float1,
+ BuiltInName::tan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpTan,
+ true);
+constexpr const TFunction kFunction_tan_1B(
+ BuiltInId::tan_Float2,
+ BuiltInName::tan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpTan,
+ true);
+constexpr const TFunction kFunction_tan_2B(
+ BuiltInId::tan_Float3,
+ BuiltInName::tan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpTan,
+ true);
+constexpr const TFunction kFunction_tan_3B(
+ BuiltInId::tan_Float4,
+ BuiltInName::tan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpTan,
+ true);
+constexpr const TFunction kFunction_asin_0B(
+ BuiltInId::asin_Float1,
+ BuiltInName::asin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAsin,
+ true);
+constexpr const TFunction kFunction_asin_1B(
+ BuiltInId::asin_Float2,
+ BuiltInName::asin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAsin,
+ true);
+constexpr const TFunction kFunction_asin_2B(
+ BuiltInId::asin_Float3,
+ BuiltInName::asin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAsin,
+ true);
+constexpr const TFunction kFunction_asin_3B(
+ BuiltInId::asin_Float4,
+ BuiltInName::asin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAsin,
+ true);
+constexpr const TFunction kFunction_acos_0B(
+ BuiltInId::acos_Float1,
+ BuiltInName::acos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAcos,
+ true);
+constexpr const TFunction kFunction_acos_1B(
+ BuiltInId::acos_Float2,
+ BuiltInName::acos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAcos,
+ true);
+constexpr const TFunction kFunction_acos_2B(
+ BuiltInId::acos_Float3,
+ BuiltInName::acos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAcos,
+ true);
+constexpr const TFunction kFunction_acos_3B(
+ BuiltInId::acos_Float4,
+ BuiltInName::acos,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAcos,
+ true);
+constexpr const TFunction kFunction_atan_0B0B(
+ BuiltInId::atan_Float1_Float1,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_1B1B(
+ BuiltInId::atan_Float2_Float2,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_2B2B(
+ BuiltInId::atan_Float3_Float3,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_3B3B(
+ BuiltInId::atan_Float4_Float4,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_0B(
+ BuiltInId::atan_Float1,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_1B(
+ BuiltInId::atan_Float2,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_2B(
+ BuiltInId::atan_Float3,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_atan_3B(
+ BuiltInId::atan_Float4,
+ BuiltInName::atan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAtan,
+ true);
+constexpr const TFunction kFunction_sinh_0B(
+ BuiltInId::sinh_Float1,
+ BuiltInName::sinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpSinh,
+ true);
+constexpr const TFunction kFunction_sinh_1B(
+ BuiltInId::sinh_Float2,
+ BuiltInName::sinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSinh,
+ true);
+constexpr const TFunction kFunction_sinh_2B(
+ BuiltInId::sinh_Float3,
+ BuiltInName::sinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSinh,
+ true);
+constexpr const TFunction kFunction_sinh_3B(
+ BuiltInId::sinh_Float4,
+ BuiltInName::sinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSinh,
+ true);
+constexpr const TFunction kFunction_cosh_0B(
+ BuiltInId::cosh_Float1,
+ BuiltInName::cosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCosh,
+ true);
+constexpr const TFunction kFunction_cosh_1B(
+ BuiltInId::cosh_Float2,
+ BuiltInName::cosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCosh,
+ true);
+constexpr const TFunction kFunction_cosh_2B(
+ BuiltInId::cosh_Float3,
+ BuiltInName::cosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCosh,
+ true);
+constexpr const TFunction kFunction_cosh_3B(
+ BuiltInId::cosh_Float4,
+ BuiltInName::cosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCosh,
+ true);
+constexpr const TFunction kFunction_tanh_0B(
+ BuiltInId::tanh_Float1,
+ BuiltInName::tanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpTanh,
+ true);
+constexpr const TFunction kFunction_tanh_1B(
+ BuiltInId::tanh_Float2,
+ BuiltInName::tanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpTanh,
+ true);
+constexpr const TFunction kFunction_tanh_2B(
+ BuiltInId::tanh_Float3,
+ BuiltInName::tanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpTanh,
+ true);
+constexpr const TFunction kFunction_tanh_3B(
+ BuiltInId::tanh_Float4,
+ BuiltInName::tanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpTanh,
+ true);
+constexpr const TFunction kFunction_asinh_0B(
+ BuiltInId::asinh_Float1,
+ BuiltInName::asinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAsinh,
+ true);
+constexpr const TFunction kFunction_asinh_1B(
+ BuiltInId::asinh_Float2,
+ BuiltInName::asinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAsinh,
+ true);
+constexpr const TFunction kFunction_asinh_2B(
+ BuiltInId::asinh_Float3,
+ BuiltInName::asinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAsinh,
+ true);
+constexpr const TFunction kFunction_asinh_3B(
+ BuiltInId::asinh_Float4,
+ BuiltInName::asinh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAsinh,
+ true);
+constexpr const TFunction kFunction_acosh_0B(
+ BuiltInId::acosh_Float1,
+ BuiltInName::acosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAcosh,
+ true);
+constexpr const TFunction kFunction_acosh_1B(
+ BuiltInId::acosh_Float2,
+ BuiltInName::acosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAcosh,
+ true);
+constexpr const TFunction kFunction_acosh_2B(
+ BuiltInId::acosh_Float3,
+ BuiltInName::acosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAcosh,
+ true);
+constexpr const TFunction kFunction_acosh_3B(
+ BuiltInId::acosh_Float4,
+ BuiltInName::acosh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAcosh,
+ true);
+constexpr const TFunction kFunction_atanh_0B(
+ BuiltInId::atanh_Float1,
+ BuiltInName::atanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtanh,
+ true);
+constexpr const TFunction kFunction_atanh_1B(
+ BuiltInId::atanh_Float2,
+ BuiltInName::atanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAtanh,
+ true);
+constexpr const TFunction kFunction_atanh_2B(
+ BuiltInId::atanh_Float3,
+ BuiltInName::atanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAtanh,
+ true);
+constexpr const TFunction kFunction_atanh_3B(
+ BuiltInId::atanh_Float4,
+ BuiltInName::atanh,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAtanh,
+ true);
+constexpr const TFunction kFunction_pow_0B0B(
+ BuiltInId::pow_Float1_Float1,
+ BuiltInName::pow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpPow,
+ true);
+constexpr const TFunction kFunction_pow_1B1B(
+ BuiltInId::pow_Float2_Float2,
+ BuiltInName::pow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpPow,
+ true);
+constexpr const TFunction kFunction_pow_2B2B(
+ BuiltInId::pow_Float3_Float3,
+ BuiltInName::pow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpPow,
+ true);
+constexpr const TFunction kFunction_pow_3B3B(
+ BuiltInId::pow_Float4_Float4,
+ BuiltInName::pow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpPow,
+ true);
+constexpr const TFunction kFunction_exp_0B(
+ BuiltInId::exp_Float1,
+ BuiltInName::exp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpExp,
+ true);
+constexpr const TFunction kFunction_exp_1B(
+ BuiltInId::exp_Float2,
+ BuiltInName::exp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpExp,
+ true);
+constexpr const TFunction kFunction_exp_2B(
+ BuiltInId::exp_Float3,
+ BuiltInName::exp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpExp,
+ true);
+constexpr const TFunction kFunction_exp_3B(
+ BuiltInId::exp_Float4,
+ BuiltInName::exp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpExp,
+ true);
+constexpr const TFunction kFunction_log_0B(
+ BuiltInId::log_Float1,
+ BuiltInName::log,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLog,
+ true);
+constexpr const TFunction kFunction_log_1B(
+ BuiltInId::log_Float2,
+ BuiltInName::log,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLog,
+ true);
+constexpr const TFunction kFunction_log_2B(
+ BuiltInId::log_Float3,
+ BuiltInName::log,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLog,
+ true);
+constexpr const TFunction kFunction_log_3B(
+ BuiltInId::log_Float4,
+ BuiltInName::log,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLog,
+ true);
+constexpr const TFunction kFunction_exp2_0B(
+ BuiltInId::exp2_Float1,
+ BuiltInName::exp2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpExp2,
+ true);
+constexpr const TFunction kFunction_exp2_1B(
+ BuiltInId::exp2_Float2,
+ BuiltInName::exp2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpExp2,
+ true);
+constexpr const TFunction kFunction_exp2_2B(
+ BuiltInId::exp2_Float3,
+ BuiltInName::exp2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpExp2,
+ true);
+constexpr const TFunction kFunction_exp2_3B(
+ BuiltInId::exp2_Float4,
+ BuiltInName::exp2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpExp2,
+ true);
+constexpr const TFunction kFunction_log2_0B(
+ BuiltInId::log2_Float1,
+ BuiltInName::log2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLog2,
+ true);
+constexpr const TFunction kFunction_log2_1B(
+ BuiltInId::log2_Float2,
+ BuiltInName::log2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLog2,
+ true);
+constexpr const TFunction kFunction_log2_2B(
+ BuiltInId::log2_Float3,
+ BuiltInName::log2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLog2,
+ true);
+constexpr const TFunction kFunction_log2_3B(
+ BuiltInId::log2_Float4,
+ BuiltInName::log2,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLog2,
+ true);
+constexpr const TFunction kFunction_sqrt_0B(
+ BuiltInId::sqrt_Float1,
+ BuiltInName::sqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpSqrt,
+ true);
+constexpr const TFunction kFunction_sqrt_1B(
+ BuiltInId::sqrt_Float2,
+ BuiltInName::sqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSqrt,
+ true);
+constexpr const TFunction kFunction_sqrt_2B(
+ BuiltInId::sqrt_Float3,
+ BuiltInName::sqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSqrt,
+ true);
+constexpr const TFunction kFunction_sqrt_3B(
+ BuiltInId::sqrt_Float4,
+ BuiltInName::sqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSqrt,
+ true);
+constexpr const TFunction kFunction_inversesqrt_0B(
+ BuiltInId::inversesqrt_Float1,
+ BuiltInName::inversesqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpInversesqrt,
+ true);
+constexpr const TFunction kFunction_inversesqrt_1B(
+ BuiltInId::inversesqrt_Float2,
+ BuiltInName::inversesqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpInversesqrt,
+ true);
+constexpr const TFunction kFunction_inversesqrt_2B(
+ BuiltInId::inversesqrt_Float3,
+ BuiltInName::inversesqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpInversesqrt,
+ true);
+constexpr const TFunction kFunction_inversesqrt_3B(
+ BuiltInId::inversesqrt_Float4,
+ BuiltInName::inversesqrt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpInversesqrt,
+ true);
+constexpr const TFunction kFunction_abs_0B(
+ BuiltInId::abs_Float1,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_1B(
+ BuiltInId::abs_Float2,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_2B(
+ BuiltInId::abs_Float3,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_3B(
+ BuiltInId::abs_Float4,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_0C(BuiltInId::abs_Int1,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_1C(BuiltInId::abs_Int2,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_2C(BuiltInId::abs_Int3,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_abs_3C(BuiltInId::abs_Int4,
+ BuiltInName::abs,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpAbs,
+ true);
+constexpr const TFunction kFunction_sign_0B(
+ BuiltInId::sign_Float1,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_1B(
+ BuiltInId::sign_Float2,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_2B(
+ BuiltInId::sign_Float3,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_3B(
+ BuiltInId::sign_Float4,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_0C(
+ BuiltInId::sign_Int1,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_1C(
+ BuiltInId::sign_Int2,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_2C(
+ BuiltInId::sign_Int3,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_sign_3C(
+ BuiltInId::sign_Int4,
+ BuiltInName::sign,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSign,
+ true);
+constexpr const TFunction kFunction_floor_0B(
+ BuiltInId::floor_Float1,
+ BuiltInName::floor,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFloor,
+ true);
+constexpr const TFunction kFunction_floor_1B(
+ BuiltInId::floor_Float2,
+ BuiltInName::floor,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFloor,
+ true);
+constexpr const TFunction kFunction_floor_2B(
+ BuiltInId::floor_Float3,
+ BuiltInName::floor,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFloor,
+ true);
+constexpr const TFunction kFunction_floor_3B(
+ BuiltInId::floor_Float4,
+ BuiltInName::floor,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFloor,
+ true);
+constexpr const TFunction kFunction_trunc_0B(
+ BuiltInId::trunc_Float1,
+ BuiltInName::trunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpTrunc,
+ true);
+constexpr const TFunction kFunction_trunc_1B(
+ BuiltInId::trunc_Float2,
+ BuiltInName::trunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpTrunc,
+ true);
+constexpr const TFunction kFunction_trunc_2B(
+ BuiltInId::trunc_Float3,
+ BuiltInName::trunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpTrunc,
+ true);
+constexpr const TFunction kFunction_trunc_3B(
+ BuiltInId::trunc_Float4,
+ BuiltInName::trunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpTrunc,
+ true);
+constexpr const TFunction kFunction_round_0B(
+ BuiltInId::round_Float1,
+ BuiltInName::round,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpRound,
+ true);
+constexpr const TFunction kFunction_round_1B(
+ BuiltInId::round_Float2,
+ BuiltInName::round,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpRound,
+ true);
+constexpr const TFunction kFunction_round_2B(
+ BuiltInId::round_Float3,
+ BuiltInName::round,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpRound,
+ true);
+constexpr const TFunction kFunction_round_3B(
+ BuiltInId::round_Float4,
+ BuiltInName::round,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpRound,
+ true);
+constexpr const TFunction kFunction_roundEven_0B(
+ BuiltInId::roundEven_Float1,
+ BuiltInName::roundEven,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpRoundEven,
+ true);
+constexpr const TFunction kFunction_roundEven_1B(
+ BuiltInId::roundEven_Float2,
+ BuiltInName::roundEven,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpRoundEven,
+ true);
+constexpr const TFunction kFunction_roundEven_2B(
+ BuiltInId::roundEven_Float3,
+ BuiltInName::roundEven,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpRoundEven,
+ true);
+constexpr const TFunction kFunction_roundEven_3B(
+ BuiltInId::roundEven_Float4,
+ BuiltInName::roundEven,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpRoundEven,
+ true);
+constexpr const TFunction kFunction_ceil_0B(
+ BuiltInId::ceil_Float1,
+ BuiltInName::ceil,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCeil,
+ true);
+constexpr const TFunction kFunction_ceil_1B(
+ BuiltInId::ceil_Float2,
+ BuiltInName::ceil,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCeil,
+ true);
+constexpr const TFunction kFunction_ceil_2B(
+ BuiltInId::ceil_Float3,
+ BuiltInName::ceil,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCeil,
+ true);
+constexpr const TFunction kFunction_ceil_3B(
+ BuiltInId::ceil_Float4,
+ BuiltInName::ceil,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCeil,
+ true);
+constexpr const TFunction kFunction_fract_0B(
+ BuiltInId::fract_Float1,
+ BuiltInName::fract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFract,
+ true);
+constexpr const TFunction kFunction_fract_1B(
+ BuiltInId::fract_Float2,
+ BuiltInName::fract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFract,
+ true);
+constexpr const TFunction kFunction_fract_2B(
+ BuiltInId::fract_Float3,
+ BuiltInName::fract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFract,
+ true);
+constexpr const TFunction kFunction_fract_3B(
+ BuiltInId::fract_Float4,
+ BuiltInName::fract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFract,
+ true);
+constexpr const TFunction kFunction_mod_0B0B(
+ BuiltInId::mod_Float1_Float1,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_mod_1B0B(
+ BuiltInId::mod_Float2_Float1,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_mod_2B0B(
+ BuiltInId::mod_Float3_Float1,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_mod_3B0B(
+ BuiltInId::mod_Float4_Float1,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_mod_1B1B(
+ BuiltInId::mod_Float2_Float2,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_mod_2B2B(
+ BuiltInId::mod_Float3_Float3,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_mod_3B3B(
+ BuiltInId::mod_Float4_Float4,
+ BuiltInName::mod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMod,
+ true);
+constexpr const TFunction kFunction_min_0B0B(
+ BuiltInId::min_Float1_Float1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_1B0B(
+ BuiltInId::min_Float2_Float1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_2B0B(
+ BuiltInId::min_Float3_Float1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_3B0B(
+ BuiltInId::min_Float4_Float1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_1B1B(
+ BuiltInId::min_Float2_Float2,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_2B2B(
+ BuiltInId::min_Float3_Float3,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_3B3B(
+ BuiltInId::min_Float4_Float4,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_0C0C(
+ BuiltInId::min_Int1_Int1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_1C1C(
+ BuiltInId::min_Int2_Int2,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_2C2C(
+ BuiltInId::min_Int3_Int3,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_3C3C(
+ BuiltInId::min_Int4_Int4,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_1C0C(
+ BuiltInId::min_Int2_Int1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_2C0C(
+ BuiltInId::min_Int3_Int1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_3C0C(
+ BuiltInId::min_Int4_Int1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_0D0D(
+ BuiltInId::min_UInt1_UInt1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_1D1D(
+ BuiltInId::min_UInt2_UInt2,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_2D2D(
+ BuiltInId::min_UInt3_UInt3,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_3D3D(
+ BuiltInId::min_UInt4_UInt4,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_1D0D(
+ BuiltInId::min_UInt2_UInt1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_2D0D(
+ BuiltInId::min_UInt3_UInt1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_min_3D0D(
+ BuiltInId::min_UInt4_UInt1,
+ BuiltInName::min,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMin,
+ true);
+constexpr const TFunction kFunction_max_0B0B(
+ BuiltInId::max_Float1_Float1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_1B0B(
+ BuiltInId::max_Float2_Float1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_2B0B(
+ BuiltInId::max_Float3_Float1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_3B0B(
+ BuiltInId::max_Float4_Float1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_1B1B(
+ BuiltInId::max_Float2_Float2,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_2B2B(
+ BuiltInId::max_Float3_Float3,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_3B3B(
+ BuiltInId::max_Float4_Float4,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_0C0C(
+ BuiltInId::max_Int1_Int1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_1C1C(
+ BuiltInId::max_Int2_Int2,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_2C2C(
+ BuiltInId::max_Int3_Int3,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_3C3C(
+ BuiltInId::max_Int4_Int4,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_1C0C(
+ BuiltInId::max_Int2_Int1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_2C0C(
+ BuiltInId::max_Int3_Int1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_3C0C(
+ BuiltInId::max_Int4_Int1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_0D0D(
+ BuiltInId::max_UInt1_UInt1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_1D1D(
+ BuiltInId::max_UInt2_UInt2,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_2D2D(
+ BuiltInId::max_UInt3_UInt3,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_3D3D(
+ BuiltInId::max_UInt4_UInt4,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_1D0D(
+ BuiltInId::max_UInt2_UInt1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_2D0D(
+ BuiltInId::max_UInt3_UInt1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_max_3D0D(
+ BuiltInId::max_UInt4_UInt1,
+ BuiltInName::max,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMax,
+ true);
+constexpr const TFunction kFunction_clamp_0B0B0B(
+ BuiltInId::clamp_Float1_Float1_Float1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_1B0B0B(
+ BuiltInId::clamp_Float2_Float1_Float1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_2B0B0B(
+ BuiltInId::clamp_Float3_Float1_Float1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_3B0B0B(
+ BuiltInId::clamp_Float4_Float1_Float1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_1B1B1B(
+ BuiltInId::clamp_Float2_Float2_Float2,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B1B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_2B2B2B(
+ BuiltInId::clamp_Float3_Float3_Float3,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B2B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_3B3B3B(
+ BuiltInId::clamp_Float4_Float4_Float4,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B3B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_0C0C0C(
+ BuiltInId::clamp_Int1_Int1_Int1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_1C0C0C(
+ BuiltInId::clamp_Int2_Int1_Int1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_2C0C0C(
+ BuiltInId::clamp_Int3_Int1_Int1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_3C0C0C(
+ BuiltInId::clamp_Int4_Int1_Int1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_1C1C1C(
+ BuiltInId::clamp_Int2_Int2_Int2,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_2C2C2C(
+ BuiltInId::clamp_Int3_Int3_Int3,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C2C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_3C3C3C(
+ BuiltInId::clamp_Int4_Int4_Int4,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_0D0D0D(
+ BuiltInId::clamp_UInt1_UInt1_UInt1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_1D0D0D(
+ BuiltInId::clamp_UInt2_UInt1_UInt1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0D0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_2D0D0D(
+ BuiltInId::clamp_UInt3_UInt1_UInt1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D0D0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_3D0D0D(
+ BuiltInId::clamp_UInt4_UInt1_UInt1,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0D0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_1D1D1D(
+ BuiltInId::clamp_UInt2_UInt2_UInt2,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D1D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_2D2D2D(
+ BuiltInId::clamp_UInt3_UInt3_UInt3,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D2D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_clamp_3D3D3D(
+ BuiltInId::clamp_UInt4_UInt4_UInt4,
+ BuiltInName::clamp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D3D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpClamp,
+ true);
+constexpr const TFunction kFunction_mix_0B0B0B(
+ BuiltInId::mix_Float1_Float1_Float1,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_1B1B0B(
+ BuiltInId::mix_Float2_Float2_Float1,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_2B2B0B(
+ BuiltInId::mix_Float3_Float3_Float1,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_3B3B0B(
+ BuiltInId::mix_Float4_Float4_Float1,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_1B1B1B(
+ BuiltInId::mix_Float2_Float2_Float2,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B1B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_2B2B2B(
+ BuiltInId::mix_Float3_Float3_Float3,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B2B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_3B3B3B(
+ BuiltInId::mix_Float4_Float4_Float4,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B3B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_0B0B0E(
+ BuiltInId::mix_Float1_Float1_Bool1,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B0E,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_1B1B1E(
+ BuiltInId::mix_Float2_Float2_Bool2,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B1E,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_2B2B2E(
+ BuiltInId::mix_Float3_Float3_Bool3,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B2E,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_mix_3B3B3E(
+ BuiltInId::mix_Float4_Float4_Bool4,
+ BuiltInName::mix,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B3E,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpMix,
+ true);
+constexpr const TFunction kFunction_step_0B0B(
+ BuiltInId::step_Float1_Float1,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_step_1B1B(
+ BuiltInId::step_Float2_Float2,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_step_2B2B(
+ BuiltInId::step_Float3_Float3,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_step_3B3B(
+ BuiltInId::step_Float4_Float4,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_step_0B1B(
+ BuiltInId::step_Float1_Float2,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_step_0B2B(
+ BuiltInId::step_Float1_Float3,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_step_0B3B(
+ BuiltInId::step_Float1_Float4,
+ BuiltInName::step,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpStep,
+ true);
+constexpr const TFunction kFunction_smoothstep_0B0B0B(
+ BuiltInId::smoothstep_Float1_Float1_Float1,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_smoothstep_1B1B1B(
+ BuiltInId::smoothstep_Float2_Float2_Float2,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B1B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_smoothstep_2B2B2B(
+ BuiltInId::smoothstep_Float3_Float3_Float3,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B2B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_smoothstep_3B3B3B(
+ BuiltInId::smoothstep_Float4_Float4_Float4,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B3B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_smoothstep_0B0B1B(
+ BuiltInId::smoothstep_Float1_Float1_Float2,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_smoothstep_0B0B2B(
+ BuiltInId::smoothstep_Float1_Float1_Float3,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B2B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_smoothstep_0B0B3B(
+ BuiltInId::smoothstep_Float1_Float1_Float4,
+ BuiltInName::smoothstep,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B3B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpSmoothstep,
+ true);
+constexpr const TFunction kFunction_modf_0B0B(
+ BuiltInId::modf_Float1_Float1,
+ BuiltInName::modf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B_o_0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpModf,
+ false);
+constexpr const TFunction kFunction_modf_1B1B(
+ BuiltInId::modf_Float2_Float2,
+ BuiltInName::modf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B_o_1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpModf,
+ false);
+constexpr const TFunction kFunction_modf_2B2B(
+ BuiltInId::modf_Float3_Float3,
+ BuiltInName::modf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpModf,
+ false);
+constexpr const TFunction kFunction_modf_3B3B(
+ BuiltInId::modf_Float4_Float4,
+ BuiltInName::modf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B_o_3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpModf,
+ false);
+constexpr const TFunction kFunction_isnan_0B(
+ BuiltInId::isnan_Float1,
+ BuiltInName::isnan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpIsnan,
+ true);
+constexpr const TFunction kFunction_isnan_1B(
+ BuiltInId::isnan_Float2,
+ BuiltInName::isnan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpIsnan,
+ true);
+constexpr const TFunction kFunction_isnan_2B(
+ BuiltInId::isnan_Float3,
+ BuiltInName::isnan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpIsnan,
+ true);
+constexpr const TFunction kFunction_isnan_3B(
+ BuiltInId::isnan_Float4,
+ BuiltInName::isnan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpIsnan,
+ true);
+constexpr const TFunction kFunction_isinf_0B(
+ BuiltInId::isinf_Float1,
+ BuiltInName::isinf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpIsinf,
+ true);
+constexpr const TFunction kFunction_isinf_1B(
+ BuiltInId::isinf_Float2,
+ BuiltInName::isinf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpIsinf,
+ true);
+constexpr const TFunction kFunction_isinf_2B(
+ BuiltInId::isinf_Float3,
+ BuiltInName::isinf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpIsinf,
+ true);
+constexpr const TFunction kFunction_isinf_3B(
+ BuiltInId::isinf_Float4,
+ BuiltInName::isinf,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpIsinf,
+ true);
+constexpr const TFunction kFunction_floatBitsToInt_0B(
+ BuiltInId::floatBitsToInt_Float1,
+ BuiltInName::floatBitsToInt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFloatBitsToInt,
+ true);
+constexpr const TFunction kFunction_floatBitsToInt_1B(
+ BuiltInId::floatBitsToInt_Float2,
+ BuiltInName::floatBitsToInt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFloatBitsToInt,
+ true);
+constexpr const TFunction kFunction_floatBitsToInt_2B(
+ BuiltInId::floatBitsToInt_Float3,
+ BuiltInName::floatBitsToInt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFloatBitsToInt,
+ true);
+constexpr const TFunction kFunction_floatBitsToInt_3B(
+ BuiltInId::floatBitsToInt_Float4,
+ BuiltInName::floatBitsToInt,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFloatBitsToInt,
+ true);
+constexpr const TFunction kFunction_floatBitsToUint_0B(
+ BuiltInId::floatBitsToUint_Float1,
+ BuiltInName::floatBitsToUint,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFloatBitsToUint,
+ true);
+constexpr const TFunction kFunction_floatBitsToUint_1B(
+ BuiltInId::floatBitsToUint_Float2,
+ BuiltInName::floatBitsToUint,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFloatBitsToUint,
+ true);
+constexpr const TFunction kFunction_floatBitsToUint_2B(
+ BuiltInId::floatBitsToUint_Float3,
+ BuiltInName::floatBitsToUint,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFloatBitsToUint,
+ true);
+constexpr const TFunction kFunction_floatBitsToUint_3B(
+ BuiltInId::floatBitsToUint_Float4,
+ BuiltInName::floatBitsToUint,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFloatBitsToUint,
+ true);
+constexpr const TFunction kFunction_intBitsToFloat_0C(
+ BuiltInId::intBitsToFloat_Int1,
+ BuiltInName::intBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpIntBitsToFloat,
+ true);
+constexpr const TFunction kFunction_intBitsToFloat_1C(
+ BuiltInId::intBitsToFloat_Int2,
+ BuiltInName::intBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpIntBitsToFloat,
+ true);
+constexpr const TFunction kFunction_intBitsToFloat_2C(
+ BuiltInId::intBitsToFloat_Int3,
+ BuiltInName::intBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpIntBitsToFloat,
+ true);
+constexpr const TFunction kFunction_intBitsToFloat_3C(
+ BuiltInId::intBitsToFloat_Int4,
+ BuiltInName::intBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpIntBitsToFloat,
+ true);
+constexpr const TFunction kFunction_uintBitsToFloat_0D(
+ BuiltInId::uintBitsToFloat_UInt1,
+ BuiltInName::uintBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUintBitsToFloat,
+ true);
+constexpr const TFunction kFunction_uintBitsToFloat_1D(
+ BuiltInId::uintBitsToFloat_UInt2,
+ BuiltInName::uintBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpUintBitsToFloat,
+ true);
+constexpr const TFunction kFunction_uintBitsToFloat_2D(
+ BuiltInId::uintBitsToFloat_UInt3,
+ BuiltInName::uintBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpUintBitsToFloat,
+ true);
+constexpr const TFunction kFunction_uintBitsToFloat_3D(
+ BuiltInId::uintBitsToFloat_UInt4,
+ BuiltInName::uintBitsToFloat,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpUintBitsToFloat,
+ true);
+constexpr const TFunction kFunction_frexp_0B0C(
+ BuiltInId::frexp_Float1_Int1,
+ BuiltInName::frexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B_o_0C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFrexp,
+ false);
+constexpr const TFunction kFunction_frexp_1B1C(
+ BuiltInId::frexp_Float2_Int2,
+ BuiltInName::frexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B_o_1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFrexp,
+ false);
+constexpr const TFunction kFunction_frexp_2B2C(
+ BuiltInId::frexp_Float3_Int3,
+ BuiltInName::frexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFrexp,
+ false);
+constexpr const TFunction kFunction_frexp_3B3C(
+ BuiltInId::frexp_Float4_Int4,
+ BuiltInName::frexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B_o_3C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFrexp,
+ false);
+constexpr const TFunction kFunction_ldexp_0B0C(
+ BuiltInId::ldexp_Float1_Int1,
+ BuiltInName::ldexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLdexp,
+ true);
+constexpr const TFunction kFunction_ldexp_1B1C(
+ BuiltInId::ldexp_Float2_Int2,
+ BuiltInName::ldexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLdexp,
+ true);
+constexpr const TFunction kFunction_ldexp_2B2C(
+ BuiltInId::ldexp_Float3_Int3,
+ BuiltInName::ldexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLdexp,
+ true);
+constexpr const TFunction kFunction_ldexp_3B3C(
+ BuiltInId::ldexp_Float4_Int4,
+ BuiltInName::ldexp,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLdexp,
+ true);
+constexpr const TFunction kFunction_packSnorm2x16_1B(
+ BuiltInId::packSnorm2x16_Float2,
+ BuiltInName::packSnorm2x16,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpPackSnorm2x16,
+ true);
+constexpr const TFunction kFunction_packUnorm2x16_1B(
+ BuiltInId::packUnorm2x16_Float2,
+ BuiltInName::packUnorm2x16,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpPackUnorm2x16,
+ true);
+constexpr const TFunction kFunction_packHalf2x16_1B(
+ BuiltInId::packHalf2x16_Float2,
+ BuiltInName::packHalf2x16,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpPackHalf2x16,
+ true);
+constexpr const TFunction kFunction_unpackSnorm2x16_0D(
+ BuiltInId::unpackSnorm2x16_UInt1,
+ BuiltInName::unpackSnorm2x16,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpUnpackSnorm2x16,
+ true);
+constexpr const TFunction kFunction_unpackUnorm2x16_0D(
+ BuiltInId::unpackUnorm2x16_UInt1,
+ BuiltInName::unpackUnorm2x16,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpUnpackUnorm2x16,
+ true);
+constexpr const TFunction kFunction_unpackHalf2x16_0D(
+ BuiltInId::unpackHalf2x16_UInt1,
+ BuiltInName::unpackHalf2x16,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpUnpackHalf2x16,
+ true);
+constexpr const TFunction kFunction_packUnorm4x8_3B(
+ BuiltInId::packUnorm4x8_Float4,
+ BuiltInName::packUnorm4x8,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpPackUnorm4x8,
+ true);
+constexpr const TFunction kFunction_packSnorm4x8_3B(
+ BuiltInId::packSnorm4x8_Float4,
+ BuiltInName::packSnorm4x8,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpPackSnorm4x8,
+ true);
+constexpr const TFunction kFunction_unpackUnorm4x8_0D(
+ BuiltInId::unpackUnorm4x8_UInt1,
+ BuiltInName::unpackUnorm4x8,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpUnpackUnorm4x8,
+ true);
+constexpr const TFunction kFunction_unpackSnorm4x8_0D(
+ BuiltInId::unpackSnorm4x8_UInt1,
+ BuiltInName::unpackSnorm4x8,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpUnpackSnorm4x8,
+ true);
+constexpr const TFunction kFunction_length_0B(
+ BuiltInId::length_Float1,
+ BuiltInName::length,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLength,
+ true);
+constexpr const TFunction kFunction_length_1B(
+ BuiltInId::length_Float2,
+ BuiltInName::length,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLength,
+ true);
+constexpr const TFunction kFunction_length_2B(
+ BuiltInId::length_Float3,
+ BuiltInName::length,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLength,
+ true);
+constexpr const TFunction kFunction_length_3B(
+ BuiltInId::length_Float4,
+ BuiltInName::length,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpLength,
+ true);
+constexpr const TFunction kFunction_distance_0B0B(
+ BuiltInId::distance_Float1_Float1,
+ BuiltInName::distance,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDistance,
+ true);
+constexpr const TFunction kFunction_distance_1B1B(
+ BuiltInId::distance_Float2_Float2,
+ BuiltInName::distance,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDistance,
+ true);
+constexpr const TFunction kFunction_distance_2B2B(
+ BuiltInId::distance_Float3_Float3,
+ BuiltInName::distance,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDistance,
+ true);
+constexpr const TFunction kFunction_distance_3B3B(
+ BuiltInId::distance_Float4_Float4,
+ BuiltInName::distance,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDistance,
+ true);
+constexpr const TFunction kFunction_dot_0B0B(
+ BuiltInId::dot_Float1_Float1,
+ BuiltInName::dot,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDot,
+ true);
+constexpr const TFunction kFunction_dot_1B1B(
+ BuiltInId::dot_Float2_Float2,
+ BuiltInName::dot,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDot,
+ true);
+constexpr const TFunction kFunction_dot_2B2B(
+ BuiltInId::dot_Float3_Float3,
+ BuiltInName::dot,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDot,
+ true);
+constexpr const TFunction kFunction_dot_3B3B(
+ BuiltInId::dot_Float4_Float4,
+ BuiltInName::dot,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDot,
+ true);
+constexpr const TFunction kFunction_cross_2B2B(
+ BuiltInId::cross_Float3_Float3,
+ BuiltInName::cross,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCross,
+ true);
+constexpr const TFunction kFunction_normalize_0B(
+ BuiltInId::normalize_Float1,
+ BuiltInName::normalize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpNormalize,
+ true);
+constexpr const TFunction kFunction_normalize_1B(
+ BuiltInId::normalize_Float2,
+ BuiltInName::normalize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpNormalize,
+ true);
+constexpr const TFunction kFunction_normalize_2B(
+ BuiltInId::normalize_Float3,
+ BuiltInName::normalize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpNormalize,
+ true);
+constexpr const TFunction kFunction_normalize_3B(
+ BuiltInId::normalize_Float4,
+ BuiltInName::normalize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpNormalize,
+ true);
+constexpr const TFunction kFunction_faceforward_0B0B0B(
+ BuiltInId::faceforward_Float1_Float1_Float1,
+ BuiltInName::faceforward,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFaceforward,
+ true);
+constexpr const TFunction kFunction_faceforward_1B1B1B(
+ BuiltInId::faceforward_Float2_Float2_Float2,
+ BuiltInName::faceforward,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B1B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFaceforward,
+ true);
+constexpr const TFunction kFunction_faceforward_2B2B2B(
+ BuiltInId::faceforward_Float3_Float3_Float3,
+ BuiltInName::faceforward,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B2B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFaceforward,
+ true);
+constexpr const TFunction kFunction_faceforward_3B3B3B(
+ BuiltInId::faceforward_Float4_Float4_Float4,
+ BuiltInName::faceforward,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B3B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFaceforward,
+ true);
+constexpr const TFunction kFunction_reflect_0B0B(
+ BuiltInId::reflect_Float1_Float1,
+ BuiltInName::reflect,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpReflect,
+ true);
+constexpr const TFunction kFunction_reflect_1B1B(
+ BuiltInId::reflect_Float2_Float2,
+ BuiltInName::reflect,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpReflect,
+ true);
+constexpr const TFunction kFunction_reflect_2B2B(
+ BuiltInId::reflect_Float3_Float3,
+ BuiltInName::reflect,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpReflect,
+ true);
+constexpr const TFunction kFunction_reflect_3B3B(
+ BuiltInId::reflect_Float4_Float4,
+ BuiltInName::reflect,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpReflect,
+ true);
+constexpr const TFunction kFunction_refract_0B0B0B(
+ BuiltInId::refract_Float1_Float1_Float1,
+ BuiltInName::refract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpRefract,
+ true);
+constexpr const TFunction kFunction_refract_1B1B0B(
+ BuiltInId::refract_Float2_Float2_Float1,
+ BuiltInName::refract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpRefract,
+ true);
+constexpr const TFunction kFunction_refract_2B2B0B(
+ BuiltInId::refract_Float3_Float3_Float1,
+ BuiltInName::refract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpRefract,
+ true);
+constexpr const TFunction kFunction_refract_3B3B0B(
+ BuiltInId::refract_Float4_Float4_Float1,
+ BuiltInName::refract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpRefract,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_5B5B(
+ BuiltInId::matrixCompMult_Float2x2_Float2x2,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p5B5B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_ABAB(
+ BuiltInId::matrixCompMult_Float3x3_Float3x3,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pABAB,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_FBFB(
+ BuiltInId::matrixCompMult_Float4x4_Float4x4,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pFBFB,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_9B9B(
+ BuiltInId::matrixCompMult_Float2x3_Float2x3,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p9B9B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_6B6B(
+ BuiltInId::matrixCompMult_Float3x2_Float3x2,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p6B6B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_DBDB(
+ BuiltInId::matrixCompMult_Float2x4_Float2x4,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pDBDB,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_7B7B(
+ BuiltInId::matrixCompMult_Float4x2_Float4x2,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p7B7B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_EBEB(
+ BuiltInId::matrixCompMult_Float3x4_Float3x4,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pEBEB,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_matrixCompMult_BBBB(
+ BuiltInId::matrixCompMult_Float4x3_Float4x3,
+ BuiltInName::matrixCompMult,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pBBBB,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>(),
+ EOpMulMatrixComponentWise,
+ true);
+constexpr const TFunction kFunction_outerProduct_1B1B(
+ BuiltInId::outerProduct_Float2_Float2,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_2B2B(
+ BuiltInId::outerProduct_Float3_Float3,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_3B3B(
+ BuiltInId::outerProduct_Float4_Float4,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_2B1B(
+ BuiltInId::outerProduct_Float3_Float2,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_1B2B(
+ BuiltInId::outerProduct_Float2_Float3,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_3B1B(
+ BuiltInId::outerProduct_Float4_Float2,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_1B3B(
+ BuiltInId::outerProduct_Float2_Float4,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_3B2B(
+ BuiltInId::outerProduct_Float4_Float3,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_outerProduct_2B3B(
+ BuiltInId::outerProduct_Float3_Float4,
+ BuiltInName::outerProduct,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>(),
+ EOpOuterProduct,
+ true);
+constexpr const TFunction kFunction_transpose_5B(
+ BuiltInId::transpose_Float2x2,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p5B5B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_AB(
+ BuiltInId::transpose_Float3x3,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pABAB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_FB(
+ BuiltInId::transpose_Float4x4,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pFBFB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_6B(
+ BuiltInId::transpose_Float3x2,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p6B6B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_9B(
+ BuiltInId::transpose_Float2x3,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p9B9B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_7B(
+ BuiltInId::transpose_Float4x2,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p7B7B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_DB(
+ BuiltInId::transpose_Float2x4,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pDBDB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_BB(
+ BuiltInId::transpose_Float4x3,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pBBBB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_transpose_EB(
+ BuiltInId::transpose_Float3x4,
+ BuiltInName::transpose,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pEBEB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>(),
+ EOpTranspose,
+ true);
+constexpr const TFunction kFunction_determinant_5B(
+ BuiltInId::determinant_Float2x2,
+ BuiltInName::determinant,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p5B5B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDeterminant,
+ true);
+constexpr const TFunction kFunction_determinant_AB(
+ BuiltInId::determinant_Float3x3,
+ BuiltInName::determinant,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pABAB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDeterminant,
+ true);
+constexpr const TFunction kFunction_determinant_FB(
+ BuiltInId::determinant_Float4x4,
+ BuiltInName::determinant,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pFBFB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDeterminant,
+ true);
+constexpr const TFunction kFunction_inverse_5B(
+ BuiltInId::inverse_Float2x2,
+ BuiltInName::inverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p5B5B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(),
+ EOpInverse,
+ true);
+constexpr const TFunction kFunction_inverse_AB(
+ BuiltInId::inverse_Float3x3,
+ BuiltInName::inverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pABAB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(),
+ EOpInverse,
+ true);
+constexpr const TFunction kFunction_inverse_FB(
+ BuiltInId::inverse_Float4x4,
+ BuiltInName::inverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::pFBFB,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(),
+ EOpInverse,
+ true);
+constexpr const TFunction kFunction_lessThan_1B1B(
+ BuiltInId::lessThan_Float2_Float2,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_2B2B(
+ BuiltInId::lessThan_Float3_Float3,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_3B3B(
+ BuiltInId::lessThan_Float4_Float4,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_1C1C(
+ BuiltInId::lessThan_Int2_Int2,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_2C2C(
+ BuiltInId::lessThan_Int3_Int3,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_3C3C(
+ BuiltInId::lessThan_Int4_Int4,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_1D1D(
+ BuiltInId::lessThan_UInt2_UInt2,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_2D2D(
+ BuiltInId::lessThan_UInt3_UInt3,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThan_3D3D(
+ BuiltInId::lessThan_UInt4_UInt4,
+ BuiltInName::lessThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLessThanComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_1B1B(
+ BuiltInId::lessThanEqual_Float2_Float2,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_2B2B(
+ BuiltInId::lessThanEqual_Float3_Float3,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_3B3B(
+ BuiltInId::lessThanEqual_Float4_Float4,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_1C1C(
+ BuiltInId::lessThanEqual_Int2_Int2,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_2C2C(
+ BuiltInId::lessThanEqual_Int3_Int3,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_3C3C(
+ BuiltInId::lessThanEqual_Int4_Int4,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_1D1D(
+ BuiltInId::lessThanEqual_UInt2_UInt2,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_2D2D(
+ BuiltInId::lessThanEqual_UInt3_UInt3,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_lessThanEqual_3D3D(
+ BuiltInId::lessThanEqual_UInt4_UInt4,
+ BuiltInName::lessThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLessThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_1B1B(
+ BuiltInId::greaterThan_Float2_Float2,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_2B2B(
+ BuiltInId::greaterThan_Float3_Float3,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_3B3B(
+ BuiltInId::greaterThan_Float4_Float4,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_1C1C(
+ BuiltInId::greaterThan_Int2_Int2,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_2C2C(
+ BuiltInId::greaterThan_Int3_Int3,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_3C3C(
+ BuiltInId::greaterThan_Int4_Int4,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_1D1D(
+ BuiltInId::greaterThan_UInt2_UInt2,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_2D2D(
+ BuiltInId::greaterThan_UInt3_UInt3,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThan_3D3D(
+ BuiltInId::greaterThan_UInt4_UInt4,
+ BuiltInName::greaterThan,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpGreaterThanComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_1B1B(
+ BuiltInId::greaterThanEqual_Float2_Float2,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_2B2B(
+ BuiltInId::greaterThanEqual_Float3_Float3,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_3B3B(
+ BuiltInId::greaterThanEqual_Float4_Float4,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_1C1C(
+ BuiltInId::greaterThanEqual_Int2_Int2,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_2C2C(
+ BuiltInId::greaterThanEqual_Int3_Int3,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_3C3C(
+ BuiltInId::greaterThanEqual_Int4_Int4,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_1D1D(
+ BuiltInId::greaterThanEqual_UInt2_UInt2,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_2D2D(
+ BuiltInId::greaterThanEqual_UInt3_UInt3,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_greaterThanEqual_3D3D(
+ BuiltInId::greaterThanEqual_UInt4_UInt4,
+ BuiltInName::greaterThanEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpGreaterThanEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_1B1B(
+ BuiltInId::equal_Float2_Float2,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_2B2B(
+ BuiltInId::equal_Float3_Float3,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_3B3B(
+ BuiltInId::equal_Float4_Float4,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_1C1C(
+ BuiltInId::equal_Int2_Int2,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_2C2C(
+ BuiltInId::equal_Int3_Int3,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_3C3C(
+ BuiltInId::equal_Int4_Int4,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_1D1D(
+ BuiltInId::equal_UInt2_UInt2,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_2D2D(
+ BuiltInId::equal_UInt3_UInt3,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_3D3D(
+ BuiltInId::equal_UInt4_UInt4,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_1E1E(
+ BuiltInId::equal_Bool2_Bool2,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1E1E,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_2E2E(
+ BuiltInId::equal_Bool3_Bool3,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2E2E,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_equal_3E3E(
+ BuiltInId::equal_Bool4_Bool4,
+ BuiltInName::equal,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3E3E,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_1B1B(
+ BuiltInId::notEqual_Float2_Float2,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_2B2B(
+ BuiltInId::notEqual_Float3_Float3,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B2B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_3B3B(
+ BuiltInId::notEqual_Float4_Float4,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B3B0B,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_1C1C(
+ BuiltInId::notEqual_Int2_Int2,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_2C2C(
+ BuiltInId::notEqual_Int3_Int3,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_3C3C(
+ BuiltInId::notEqual_Int4_Int4,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C3C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_1D1D(
+ BuiltInId::notEqual_UInt2_UInt2,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_2D2D(
+ BuiltInId::notEqual_UInt3_UInt3,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_3D3D(
+ BuiltInId::notEqual_UInt4_UInt4,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_1E1E(
+ BuiltInId::notEqual_Bool2_Bool2,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1E1E,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_2E2E(
+ BuiltInId::notEqual_Bool3_Bool3,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2E2E,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_notEqual_3E3E(
+ BuiltInId::notEqual_Bool4_Bool4,
+ BuiltInName::notEqual,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3E3E,
+ 2,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpNotEqualComponentWise,
+ true);
+constexpr const TFunction kFunction_any_1E(
+ BuiltInId::any_Bool2,
+ BuiltInName::any,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1E1E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAny,
+ true);
+constexpr const TFunction kFunction_any_2E(
+ BuiltInId::any_Bool3,
+ BuiltInName::any,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2E2E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAny,
+ true);
+constexpr const TFunction kFunction_any_3E(
+ BuiltInId::any_Bool4,
+ BuiltInName::any,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3E3E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAny,
+ true);
+constexpr const TFunction kFunction_all_1E(
+ BuiltInId::all_Bool2,
+ BuiltInName::all,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1E1E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAll,
+ true);
+constexpr const TFunction kFunction_all_2E(
+ BuiltInId::all_Bool3,
+ BuiltInName::all,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2E2E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAll,
+ true);
+constexpr const TFunction kFunction_all_3E(
+ BuiltInId::all_Bool4,
+ BuiltInName::all,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3E3E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAll,
+ true);
+constexpr const TFunction kFunction_notFunc_1E(
+ BuiltInId::notFunc_Bool2,
+ BuiltInName::notFunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1E1E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpLogicalNotComponentWise,
+ true);
+constexpr const TFunction kFunction_notFunc_2E(
+ BuiltInId::notFunc_Bool3,
+ BuiltInName::notFunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2E2E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpLogicalNotComponentWise,
+ true);
+constexpr const TFunction kFunction_notFunc_3E(
+ BuiltInId::notFunc_Bool4,
+ BuiltInName::notFunc,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3E3E,
+ 1,
+ StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpLogicalNotComponentWise,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_0C0C0C(
+ BuiltInId::bitfieldExtract_Int1_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_1C0C0C(
+ BuiltInId::bitfieldExtract_Int2_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_2C0C0C(
+ BuiltInId::bitfieldExtract_Int3_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_3C0C0C(
+ BuiltInId::bitfieldExtract_Int4_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_0D0C0C(
+ BuiltInId::bitfieldExtract_UInt1_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_1D0C0C(
+ BuiltInId::bitfieldExtract_UInt2_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_2D0C0C(
+ BuiltInId::bitfieldExtract_UInt3_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D0C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldExtract_3D0C0C(
+ BuiltInId::bitfieldExtract_UInt4_Int1_Int1,
+ BuiltInName::bitfieldExtract,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitfieldExtract,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_0C0C0C0C(
+ BuiltInId::bitfieldInsert_Int1_Int1_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C0C0C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_1C1C0C0C(
+ BuiltInId::bitfieldInsert_Int2_Int2_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C0C0C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_2C2C0C0C(
+ BuiltInId::bitfieldInsert_Int3_Int3_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_3C3C0C0C(
+ BuiltInId::bitfieldInsert_Int4_Int4_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C0C0C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_0D0D0C0C(
+ BuiltInId::bitfieldInsert_UInt1_UInt1_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D0C0C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_1D1D0C0C(
+ BuiltInId::bitfieldInsert_UInt2_UInt2_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D0C0C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_2D2D0C0C(
+ BuiltInId::bitfieldInsert_UInt3_UInt3_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldInsert_3D3D0C0C(
+ BuiltInId::bitfieldInsert_UInt4_UInt4_Int1_Int1,
+ BuiltInName::bitfieldInsert,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D0C0C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitfieldInsert,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_0C(
+ BuiltInId::bitfieldReverse_Int1,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_1C(
+ BuiltInId::bitfieldReverse_Int2,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_2C(
+ BuiltInId::bitfieldReverse_Int3,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_3C(
+ BuiltInId::bitfieldReverse_Int4,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_0D(
+ BuiltInId::bitfieldReverse_UInt1,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_1D(
+ BuiltInId::bitfieldReverse_UInt2,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0C0C,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_2D(
+ BuiltInId::bitfieldReverse_UInt3,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitfieldReverse_3D(
+ BuiltInId::bitfieldReverse_UInt4,
+ BuiltInName::bitfieldReverse,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0C0C,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitfieldReverse,
+ true);
+constexpr const TFunction kFunction_bitCount_0C(
+ BuiltInId::bitCount_Int1,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_1C(
+ BuiltInId::bitCount_Int2,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_2C(
+ BuiltInId::bitCount_Int3,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_3C(
+ BuiltInId::bitCount_Int4,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_0D(
+ BuiltInId::bitCount_UInt1,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_1D(
+ BuiltInId::bitCount_UInt2,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_2D(
+ BuiltInId::bitCount_UInt3,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_bitCount_3D(
+ BuiltInId::bitCount_UInt4,
+ BuiltInName::bitCount,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpBitCount,
+ true);
+constexpr const TFunction kFunction_findLSB_0C(
+ BuiltInId::findLSB_Int1,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_1C(
+ BuiltInId::findLSB_Int2,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_2C(
+ BuiltInId::findLSB_Int3,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_3C(
+ BuiltInId::findLSB_Int4,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_0D(
+ BuiltInId::findLSB_UInt1,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_1D(
+ BuiltInId::findLSB_UInt2,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_2D(
+ BuiltInId::findLSB_UInt3,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findLSB_3D(
+ BuiltInId::findLSB_UInt4,
+ BuiltInName::findLSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFindLSB,
+ true);
+constexpr const TFunction kFunction_findMSB_0C(
+ BuiltInId::findMSB_Int1,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_1C(
+ BuiltInId::findMSB_Int2,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_2C(
+ BuiltInId::findMSB_Int3,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_3C(
+ BuiltInId::findMSB_Int4,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_0D(
+ BuiltInId::findMSB_UInt1,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_1D(
+ BuiltInId::findMSB_UInt2,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_2D(
+ BuiltInId::findMSB_UInt3,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_findMSB_3D(
+ BuiltInId::findMSB_UInt4,
+ BuiltInName::findMSB,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D0C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFindMSB,
+ true);
+constexpr const TFunction kFunction_uaddCarry_0D0D0D(
+ BuiltInId::uaddCarry_UInt1_UInt1_UInt1,
+ BuiltInName::uaddCarry,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D_o_0D_o_0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUaddCarry,
+ false);
+constexpr const TFunction kFunction_uaddCarry_1D1D1D(
+ BuiltInId::uaddCarry_UInt2_UInt2_UInt2,
+ BuiltInName::uaddCarry,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D_o_1D_o_1D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpUaddCarry,
+ false);
+constexpr const TFunction kFunction_uaddCarry_2D2D2D(
+ BuiltInId::uaddCarry_UInt3_UInt3_UInt3,
+ BuiltInName::uaddCarry,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D_o_2D_o_2D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpUaddCarry,
+ false);
+constexpr const TFunction kFunction_uaddCarry_3D3D3D(
+ BuiltInId::uaddCarry_UInt4_UInt4_UInt4,
+ BuiltInName::uaddCarry,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D_o_3D_o_3D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpUaddCarry,
+ false);
+constexpr const TFunction kFunction_usubBorrow_0D0D0D(
+ BuiltInId::usubBorrow_UInt1_UInt1_UInt1,
+ BuiltInName::usubBorrow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D_o_0D_o_0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUsubBorrow,
+ false);
+constexpr const TFunction kFunction_usubBorrow_1D1D1D(
+ BuiltInId::usubBorrow_UInt2_UInt2_UInt2,
+ BuiltInName::usubBorrow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D_o_1D_o_1D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpUsubBorrow,
+ false);
+constexpr const TFunction kFunction_usubBorrow_2D2D2D(
+ BuiltInId::usubBorrow_UInt3_UInt3_UInt3,
+ BuiltInName::usubBorrow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D_o_2D_o_2D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpUsubBorrow,
+ false);
+constexpr const TFunction kFunction_usubBorrow_3D3D3D(
+ BuiltInId::usubBorrow_UInt4_UInt4_UInt4,
+ BuiltInName::usubBorrow,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D_o_3D_o_3D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpUsubBorrow,
+ false);
+constexpr const TFunction kFunction_umulExtended_0D0D0D0D(
+ BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
+ BuiltInName::umulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0D0D_o_0D_o_0D,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUmulExtended,
+ false);
+constexpr const TFunction kFunction_umulExtended_1D1D1D1D(
+ BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2,
+ BuiltInName::umulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1D1D_o_1D_o_1D,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUmulExtended,
+ false);
+constexpr const TFunction kFunction_umulExtended_2D2D2D2D(
+ BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3,
+ BuiltInName::umulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2D2D_o_2D_o_2D,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUmulExtended,
+ false);
+constexpr const TFunction kFunction_umulExtended_3D3D3D3D(
+ BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4,
+ BuiltInName::umulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3D3D_o_3D_o_3D,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpUmulExtended,
+ false);
+constexpr const TFunction kFunction_imulExtended_0C0C0C0C(
+ BuiltInId::imulExtended_Int1_Int1_Int1_Int1,
+ BuiltInName::imulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0C0C_o_0C_o_0C,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpImulExtended,
+ false);
+constexpr const TFunction kFunction_imulExtended_1C1C1C1C(
+ BuiltInId::imulExtended_Int2_Int2_Int2_Int2,
+ BuiltInName::imulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1C1C_o_1C_o_1C,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpImulExtended,
+ false);
+constexpr const TFunction kFunction_imulExtended_2C2C2C2C(
+ BuiltInId::imulExtended_Int3_Int3_Int3_Int3,
+ BuiltInName::imulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2C2C_o_2C_o_2C,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpImulExtended,
+ false);
+constexpr const TFunction kFunction_imulExtended_3C3C3C3C(
+ BuiltInId::imulExtended_Int4_Int4_Int4_Int4,
+ BuiltInName::imulExtended,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3C3C_o_3C_o_3C,
+ 4,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpImulExtended,
+ false);
+constexpr const TFunction kFunction_texture2D_0H1B(
+ BuiltInId::texture2D_Sampler2D1_Float2,
+ BuiltInName::texture2D,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1B1B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProj_0H2B(
+ BuiltInId::texture2DProj_Sampler2D1_Float3,
+ BuiltInName::texture2DProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProj_0H3B(
+ BuiltInId::texture2DProj_Sampler2D1_Float4,
+ BuiltInName::texture2DProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureCube_0J2B(
+ BuiltInId::textureCube_SamplerCube1_Float3,
+ BuiltInName::textureCube,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B2B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2D_0L1B(
+ BuiltInId::texture2D_SamplerExternalOES1_Float2,
+ BuiltInName::texture2D,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0L1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProj_0L2B(
+ BuiltInId::texture2DProj_SamplerExternalOES1_Float3,
+ BuiltInName::texture2DProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0L2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProj_0L3B(
+ BuiltInId::texture2DProj_SamplerExternalOES1_Float4,
+ BuiltInName::texture2DProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0L3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DRect_0N1B(
+ BuiltInId::texture2DRect_Sampler2DRect1_Float2,
+ BuiltInName::texture2DRect,
+ TExtension::ARB_texture_rectangle,
+ BuiltInParameters::p0N1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DRectProj_0N2B(
+ BuiltInId::texture2DRectProj_Sampler2DRect1_Float3,
+ BuiltInName::texture2DRectProj,
+ TExtension::ARB_texture_rectangle,
+ BuiltInParameters::p0N2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DRectProj_0N3B(
+ BuiltInId::texture2DRectProj_Sampler2DRect1_Float4,
+ BuiltInName::texture2DRectProj,
+ TExtension::ARB_texture_rectangle,
+ BuiltInParameters::p0N3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0N1B(
+ BuiltInId::texture_Sampler2DRect1_Float2,
+ BuiltInName::texture,
+ TExtension::ARB_texture_rectangle,
+ BuiltInParameters::p0N1B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0N2B(
+ BuiltInId::textureProj_Sampler2DRect1_Float3,
+ BuiltInName::textureProj,
+ TExtension::ARB_texture_rectangle,
+ BuiltInParameters::p0N2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0N3B(
+ BuiltInId::textureProj_Sampler2DRect1_Float4,
+ BuiltInName::textureProj,
+ TExtension::ARB_texture_rectangle,
+ BuiltInParameters::p0N3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DGradEXT_0H1B1B1B(
+ BuiltInId::texture2DGradEXT_Sampler2D1_Float2_Float2_Float2,
+ BuiltInName::texture2DGradEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0H1B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProjGradEXT_0H2B1B1B(
+ BuiltInId::texture2DProjGradEXT_Sampler2D1_Float3_Float2_Float2,
+ BuiltInName::texture2DProjGradEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0H2B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProjGradEXT_0H3B1B1B(
+ BuiltInId::texture2DProjGradEXT_Sampler2D1_Float4_Float2_Float2,
+ BuiltInName::texture2DProjGradEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0H3B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureCubeGradEXT_0J2B2B2B(
+ BuiltInId::textureCubeGradEXT_SamplerCube1_Float3_Float3_Float3,
+ BuiltInName::textureCubeGradEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0J2B2B2B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2D_0H1B0B(
+ BuiltInId::texture2D_Sampler2D1_Float2_Float1,
+ BuiltInName::texture2D,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProj_0H2B0B(
+ BuiltInId::texture2DProj_Sampler2D1_Float3_Float1,
+ BuiltInName::texture2DProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProj_0H3B0B(
+ BuiltInId::texture2DProj_Sampler2D1_Float4_Float1,
+ BuiltInName::texture2DProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureCube_0J2B0B(
+ BuiltInId::textureCube_SamplerCube1_Float3_Float1,
+ BuiltInName::textureCube,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_dFdxExt_0B(
+ BuiltInId::dFdxExt_Float1,
+ BuiltInName::dFdxExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdxExt_1B(
+ BuiltInId::dFdxExt_Float2,
+ BuiltInName::dFdxExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdxExt_2B(
+ BuiltInId::dFdxExt_Float3,
+ BuiltInName::dFdxExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdxExt_3B(
+ BuiltInId::dFdxExt_Float4,
+ BuiltInName::dFdxExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdyExt_0B(
+ BuiltInId::dFdyExt_Float1,
+ BuiltInName::dFdyExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_dFdyExt_1B(
+ BuiltInId::dFdyExt_Float2,
+ BuiltInName::dFdyExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_dFdyExt_2B(
+ BuiltInId::dFdyExt_Float3,
+ BuiltInName::dFdyExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_dFdyExt_3B(
+ BuiltInId::dFdyExt_Float4,
+ BuiltInName::dFdyExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_fwidthExt_0B(
+ BuiltInId::fwidthExt_Float1,
+ BuiltInName::fwidthExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_fwidthExt_1B(
+ BuiltInId::fwidthExt_Float2,
+ BuiltInName::fwidthExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_fwidthExt_2B(
+ BuiltInId::fwidthExt_Float3,
+ BuiltInName::fwidthExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_fwidthExt_3B(
+ BuiltInId::fwidthExt_Float4,
+ BuiltInName::fwidthExt,
+ TExtension::OES_standard_derivatives,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_texture2DLodEXT_0H1B0B(
+ BuiltInId::texture2DLodEXT_Sampler2D1_Float2_Float1,
+ BuiltInName::texture2DLodEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0H1B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProjLodEXT_0H2B0B(
+ BuiltInId::texture2DProjLodEXT_Sampler2D1_Float3_Float1,
+ BuiltInName::texture2DProjLodEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0H2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProjLodEXT_0H3B0B(
+ BuiltInId::texture2DProjLodEXT_Sampler2D1_Float4_Float1,
+ BuiltInName::texture2DProjLodEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0H3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureCubeLodEXT_0J2B0B(
+ BuiltInId::textureCubeLodEXT_SamplerCube1_Float3_Float1,
+ BuiltInName::textureCubeLodEXT,
+ TExtension::EXT_shader_texture_lod,
+ BuiltInParameters::p0J2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture3D_0I2B(
+ BuiltInId::texture3D_Sampler3D1_Float3,
+ BuiltInName::texture3D,
+ TExtension::OES_texture_3D,
+ BuiltInParameters::p0I2B0B2C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture3D_0I2B0B(
+ BuiltInId::texture3D_Sampler3D1_Float3_Float1,
+ BuiltInName::texture3D,
+ TExtension::OES_texture_3D,
+ BuiltInParameters::p0I2B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture3DProj_0I3B(
+ BuiltInId::texture3DProj_Sampler3D1_Float4,
+ BuiltInName::texture3DProj,
+ TExtension::OES_texture_3D,
+ BuiltInParameters::p0I3B2C0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture3DProj_0I3B0B(
+ BuiltInId::texture3DProj_Sampler3D1_Float4_Float1,
+ BuiltInName::texture3DProj,
+ TExtension::OES_texture_3D,
+ BuiltInParameters::p0I3B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture3DLod_0I2B0B(
+ BuiltInId::texture3DLod_Sampler3D1_Float3_Float1,
+ BuiltInName::texture3DLod,
+ TExtension::OES_texture_3D,
+ BuiltInParameters::p0I2B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture3DProjLod_0I3B0B(
+ BuiltInId::texture3DProjLod_Sampler3D1_Float4_Float1,
+ BuiltInName::texture3DProjLod,
+ TExtension::OES_texture_3D,
+ BuiltInParameters::p0I3B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DLod_0H1B0B(
+ BuiltInId::texture2DLod_Sampler2D1_Float2_Float1,
+ BuiltInName::texture2DLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProjLod_0H2B0B(
+ BuiltInId::texture2DProjLod_Sampler2D1_Float3_Float1,
+ BuiltInName::texture2DProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture2DProjLod_0H3B0B(
+ BuiltInId::texture2DProjLod_Sampler2D1_Float4_Float1,
+ BuiltInName::texture2DProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureCubeLod_0J2B0B(
+ BuiltInId::textureCubeLod_SamplerCube1_Float3_Float1,
+ BuiltInName::textureCubeLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0H1B(
+ BuiltInId::texture_Sampler2D1_Float2,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1B1B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0Q1B(
+ BuiltInId::texture_ISampler2D1_Float2,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1B1B1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0W1B(
+ BuiltInId::texture_USampler2D1_Float2,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0I2B(
+ BuiltInId::texture_Sampler3D1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B0B2C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0R2B(
+ BuiltInId::texture_ISampler3D1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B0B2C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0X2B(
+ BuiltInId::texture_USampler3D1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B0B2C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0J2B(
+ BuiltInId::texture_SamplerCube1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B2B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0S2B(
+ BuiltInId::texture_ISamplerCube1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S2B0B,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0Y2B(
+ BuiltInId::texture_USamplerCube1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y2B2B2B,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0K2B(
+ BuiltInId::texture_Sampler2DArray1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0T2B(
+ BuiltInId::texture_ISampler2DArray1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1B1B1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0Z2B(
+ BuiltInId::texture_USampler2DArray1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1B1B1C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0H2B(
+ BuiltInId::textureProj_Sampler2D1_Float3,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0Q2B(
+ BuiltInId::textureProj_ISampler2D1_Float3,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B1B1B1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0W2B(
+ BuiltInId::textureProj_USampler2D1_Float3,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B1C0B,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0H3B(
+ BuiltInId::textureProj_Sampler2D1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0Q3B(
+ BuiltInId::textureProj_ISampler2D1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B1B1B1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0W3B(
+ BuiltInId::textureProj_USampler2D1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B1B1B1C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0I3B(
+ BuiltInId::textureProj_Sampler3D1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B2C0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0R3B(
+ BuiltInId::textureProj_ISampler3D1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B0B2C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0X3B(
+ BuiltInId::textureProj_USampler3D1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B2B2B2C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0H1B0B(
+ BuiltInId::textureLod_Sampler2D1_Float2_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0Q1B0B(
+ BuiltInId::textureLod_ISampler2D1_Float2_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0W1B0B(
+ BuiltInId::textureLod_USampler2D1_Float2_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0I2B0B(
+ BuiltInId::textureLod_Sampler3D1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0R2B0B(
+ BuiltInId::textureLod_ISampler3D1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B0B2C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0X2B0B(
+ BuiltInId::textureLod_USampler3D1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B0B2C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0J2B0B(
+ BuiltInId::textureLod_SamplerCube1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0S2B0B(
+ BuiltInId::textureLod_ISamplerCube1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S2B0B,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0Y2B0B(
+ BuiltInId::textureLod_USamplerCube1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y2B0B,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0K2B0B(
+ BuiltInId::textureLod_Sampler2DArray1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0T2B0B(
+ BuiltInId::textureLod_ISampler2DArray1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0Z2B0B(
+ BuiltInId::textureLod_USampler2DArray1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0c2B(
+ BuiltInId::texture_Sampler2DShadow1_Float3,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B1B1B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0d3B(
+ BuiltInId::texture_SamplerCubeShadow1_Float4,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0d3B2B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0e3B(
+ BuiltInId::texture_Sampler2DArrayShadow1_Float4,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e3B1B1B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0c3B(
+ BuiltInId::textureProj_Sampler2DShadow1_Float4,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLod_0c2B0B(
+ BuiltInId::textureLod_Sampler2DShadow1_Float3_Float1,
+ BuiltInName::textureLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0H0C(
+ BuiltInId::textureSize_Sampler2D1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0Q0C(
+ BuiltInId::textureSize_ISampler2D1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0W0C(
+ BuiltInId::textureSize_USampler2D1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0I0C(
+ BuiltInId::textureSize_Sampler3D1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0R0C(
+ BuiltInId::textureSize_ISampler3D1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0X0C(
+ BuiltInId::textureSize_USampler3D1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0J0C(
+ BuiltInId::textureSize_SamplerCube1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0S0C(
+ BuiltInId::textureSize_ISamplerCube1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0Y0C(
+ BuiltInId::textureSize_USamplerCube1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0K0C(
+ BuiltInId::textureSize_Sampler2DArray1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0T0C(
+ BuiltInId::textureSize_ISampler2DArray1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0Z0C(
+ BuiltInId::textureSize_USampler2DArray1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0c0C(
+ BuiltInId::textureSize_Sampler2DShadow1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0d0C(
+ BuiltInId::textureSize_SamplerCubeShadow1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0d0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0e0C(
+ BuiltInId::textureSize_Sampler2DArrayShadow1_Int1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0H2B0B(
+ BuiltInId::textureProjLod_Sampler2D1_Float3_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0Q2B0B(
+ BuiltInId::textureProjLod_ISampler2D1_Float3_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0W2B0B(
+ BuiltInId::textureProjLod_USampler2D1_Float3_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0H3B0B(
+ BuiltInId::textureProjLod_Sampler2D1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0Q3B0B(
+ BuiltInId::textureProjLod_ISampler2D1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0W3B0B(
+ BuiltInId::textureProjLod_USampler2D1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0I3B0B(
+ BuiltInId::textureProjLod_Sampler3D1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0R3B0B(
+ BuiltInId::textureProjLod_ISampler3D1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B0B2C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0X3B0B(
+ BuiltInId::textureProjLod_USampler3D1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B0B2C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLod_0c3B0B(
+ BuiltInId::textureProjLod_Sampler2DShadow1_Float4_Float1,
+ BuiltInName::textureProjLod,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0H1C0C(
+ BuiltInId::texelFetch_Sampler2D1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1C0C1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0Q1C0C(
+ BuiltInId::texelFetch_ISampler2D1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1C0C1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0W1C0C(
+ BuiltInId::texelFetch_USampler2D1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1C0C1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0I2C0C(
+ BuiltInId::texelFetch_Sampler3D1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2C0C2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0R2C0C(
+ BuiltInId::texelFetch_ISampler3D1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2C0C2C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0X2C0C(
+ BuiltInId::texelFetch_USampler3D1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2C0C2C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0K2C0C(
+ BuiltInId::texelFetch_Sampler2DArray1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2C0C1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0T2C0C(
+ BuiltInId::texelFetch_ISampler2DArray1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2C0C1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0Z2C0C(
+ BuiltInId::texelFetch_USampler2DArray1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2C0C1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0H1B1B1B(
+ BuiltInId::textureGrad_Sampler2D1_Float2_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0Q1B1B1B(
+ BuiltInId::textureGrad_ISampler2D1_Float2_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1B1B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0W1B1B1B(
+ BuiltInId::textureGrad_USampler2D1_Float2_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1B1B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0I2B2B2B(
+ BuiltInId::textureGrad_Sampler3D1_Float3_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B2B2B2C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0R2B2B2B(
+ BuiltInId::textureGrad_ISampler3D1_Float3_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B2B2B2C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0X2B2B2B(
+ BuiltInId::textureGrad_USampler3D1_Float3_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B2B2B2C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0J2B2B2B(
+ BuiltInId::textureGrad_SamplerCube1_Float3_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B2B2B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0S2B2B2B(
+ BuiltInId::textureGrad_ISamplerCube1_Float3_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S2B2B2B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0Y2B2B2B(
+ BuiltInId::textureGrad_USamplerCube1_Float3_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y2B2B2B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0c2B1B1B(
+ BuiltInId::textureGrad_Sampler2DShadow1_Float3_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0d3B2B2B(
+ BuiltInId::textureGrad_SamplerCubeShadow1_Float4_Float3_Float3,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0d3B2B2B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0K2B1B1B(
+ BuiltInId::textureGrad_Sampler2DArray1_Float3_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0T2B1B1B(
+ BuiltInId::textureGrad_ISampler2DArray1_Float3_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1B1B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0Z2B1B1B(
+ BuiltInId::textureGrad_USampler2DArray1_Float3_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1B1B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGrad_0e3B1B1B(
+ BuiltInId::textureGrad_Sampler2DArrayShadow1_Float4_Float2_Float2,
+ BuiltInName::textureGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e3B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0H2B1B1B(
+ BuiltInId::textureProjGrad_Sampler2D1_Float3_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0Q2B1B1B(
+ BuiltInId::textureProjGrad_ISampler2D1_Float3_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B1B1B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0W2B1B1B(
+ BuiltInId::textureProjGrad_USampler2D1_Float3_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B1B1B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0H3B1B1B(
+ BuiltInId::textureProjGrad_Sampler2D1_Float4_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0Q3B1B1B(
+ BuiltInId::textureProjGrad_ISampler2D1_Float4_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B1B1B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0W3B1B1B(
+ BuiltInId::textureProjGrad_USampler2D1_Float4_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B1B1B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0I3B2B2B(
+ BuiltInId::textureProjGrad_Sampler3D1_Float4_Float3_Float3,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B2B2B2C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0R3B2B2B(
+ BuiltInId::textureProjGrad_ISampler3D1_Float4_Float3_Float3,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B2B2B2C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0X3B2B2B(
+ BuiltInId::textureProjGrad_USampler3D1_Float4_Float3_Float3,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B2B2B2C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGrad_0c3B1B1B(
+ BuiltInId::textureProjGrad_Sampler2DShadow1_Float4_Float2_Float2,
+ BuiltInName::textureProjGrad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B1B1B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0O(
+ BuiltInId::textureSize_Sampler2DMS1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0O1C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0U(
+ BuiltInId::textureSize_ISampler2DMS1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0U1C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0a(
+ BuiltInId::textureSize_USampler2DMS1,
+ BuiltInName::textureSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0a1C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSizeExt_0O(
+ BuiltInId::textureSizeExt_Sampler2DMS1,
+ BuiltInName::textureSizeExt,
+ TExtension::ANGLE_texture_multisample,
+ BuiltInParameters::p0O1C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSizeExt_0U(
+ BuiltInId::textureSizeExt_ISampler2DMS1,
+ BuiltInName::textureSizeExt,
+ TExtension::ANGLE_texture_multisample,
+ BuiltInParameters::p0U1C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSizeExt_0a(
+ BuiltInId::textureSizeExt_USampler2DMS1,
+ BuiltInName::textureSizeExt,
+ TExtension::ANGLE_texture_multisample,
+ BuiltInParameters::p0a1C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0P(
+ BuiltInId::textureSize_Sampler2DMSArray1,
+ BuiltInName::textureSize,
+ TExtension::OES_texture_storage_multisample_2d_array,
+ BuiltInParameters::p0P2C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0V(
+ BuiltInId::textureSize_ISampler2DMSArray1,
+ BuiltInName::textureSize,
+ TExtension::OES_texture_storage_multisample_2d_array,
+ BuiltInParameters::p0V2C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0b(
+ BuiltInId::textureSize_USampler2DMSArray1,
+ BuiltInName::textureSize,
+ TExtension::OES_texture_storage_multisample_2d_array,
+ BuiltInParameters::p0b2C0C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0H1B1C(
+ BuiltInId::textureOffset_Sampler2D1_Float2_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0Q1B1C(
+ BuiltInId::textureOffset_ISampler2D1_Float2_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0W1B1C(
+ BuiltInId::textureOffset_USampler2D1_Float2_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0I2B2C(
+ BuiltInId::textureOffset_Sampler3D1_Float3_Int3,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B2C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0R2B2C(
+ BuiltInId::textureOffset_ISampler3D1_Float3_Int3,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B2C0B,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0X2B2C(
+ BuiltInId::textureOffset_USampler3D1_Float3_Int3,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B2C0B,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0c2B1C(
+ BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B1C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0K2B1C(
+ BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B1C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0T2B1C(
+ BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0Z2B1C(
+ BuiltInId::textureOffset_USampler2DArray1_Float3_Int2,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0H2B1C(
+ BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B1C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0Q2B1C(
+ BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B1C0B,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0W2B1C(
+ BuiltInId::textureProjOffset_USampler2D1_Float3_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B1C0B,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0H3B1C(
+ BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B1C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0Q3B1C(
+ BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B1C0B,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0W3B1C(
+ BuiltInId::textureProjOffset_USampler2D1_Float4_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B1C0B,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0I3B2C(
+ BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B2C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0R3B2C(
+ BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B2C0B,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0X3B2C(
+ BuiltInId::textureProjOffset_USampler3D1_Float4_Int3,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B2C0B,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0c3B1C(
+ BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B1C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0H1B0B1C(
+ BuiltInId::textureLodOffset_Sampler2D1_Float2_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0Q1B0B1C(
+ BuiltInId::textureLodOffset_ISampler2D1_Float2_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B0B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0W1B0B1C(
+ BuiltInId::textureLodOffset_USampler2D1_Float2_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B0B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0I2B0B2C(
+ BuiltInId::textureLodOffset_Sampler3D1_Float3_Float1_Int3,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B0B2C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0R2B0B2C(
+ BuiltInId::textureLodOffset_ISampler3D1_Float3_Float1_Int3,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B0B2C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0X2B0B2C(
+ BuiltInId::textureLodOffset_USampler3D1_Float3_Float1_Int3,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B0B2C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0c2B0B1C(
+ BuiltInId::textureLodOffset_Sampler2DShadow1_Float3_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0K2B0B1C(
+ BuiltInId::textureLodOffset_Sampler2DArray1_Float3_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0T2B0B1C(
+ BuiltInId::textureLodOffset_ISampler2DArray1_Float3_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B0B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureLodOffset_0Z2B0B1C(
+ BuiltInId::textureLodOffset_USampler2DArray1_Float3_Float1_Int2,
+ BuiltInName::textureLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B0B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0H2B0B1C(
+ BuiltInId::textureProjLodOffset_Sampler2D1_Float3_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0Q2B0B1C(
+ BuiltInId::textureProjLodOffset_ISampler2D1_Float3_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B0B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0W2B0B1C(
+ BuiltInId::textureProjLodOffset_USampler2D1_Float3_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B0B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0H3B0B1C(
+ BuiltInId::textureProjLodOffset_Sampler2D1_Float4_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0Q3B0B1C(
+ BuiltInId::textureProjLodOffset_ISampler2D1_Float4_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B0B1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0W3B0B1C(
+ BuiltInId::textureProjLodOffset_USampler2D1_Float4_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B0B1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0I3B0B2C(
+ BuiltInId::textureProjLodOffset_Sampler3D1_Float4_Float1_Int3,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B0B2C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0R3B0B2C(
+ BuiltInId::textureProjLodOffset_ISampler3D1_Float4_Float1_Int3,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B0B2C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0X3B0B2C(
+ BuiltInId::textureProjLodOffset_USampler3D1_Float4_Float1_Int3,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B0B2C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjLodOffset_0c3B0B1C(
+ BuiltInId::textureProjLodOffset_Sampler2DShadow1_Float4_Float1_Int2,
+ BuiltInName::textureProjLodOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0H1C0C1C(
+ BuiltInId::texelFetchOffset_Sampler2D1_Int2_Int1_Int2,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1C0C1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0Q1C0C1C(
+ BuiltInId::texelFetchOffset_ISampler2D1_Int2_Int1_Int2,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1C0C1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0W1C0C1C(
+ BuiltInId::texelFetchOffset_USampler2D1_Int2_Int1_Int2,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1C0C1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0I2C0C2C(
+ BuiltInId::texelFetchOffset_Sampler3D1_Int3_Int1_Int3,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2C0C2C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0R2C0C2C(
+ BuiltInId::texelFetchOffset_ISampler3D1_Int3_Int1_Int3,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2C0C2C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0X2C0C2C(
+ BuiltInId::texelFetchOffset_USampler3D1_Int3_Int1_Int3,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2C0C2C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0K2C0C1C(
+ BuiltInId::texelFetchOffset_Sampler2DArray1_Int3_Int1_Int2,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2C0C1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0T2C0C1C(
+ BuiltInId::texelFetchOffset_ISampler2DArray1_Int3_Int1_Int2,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2C0C1C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchOffset_0Z2C0C1C(
+ BuiltInId::texelFetchOffset_USampler2DArray1_Int3_Int1_Int2,
+ BuiltInName::texelFetchOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2C0C1C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0H1B1B1B1C(
+ BuiltInId::textureGradOffset_Sampler2D1_Float2_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0Q1B1B1B1C(
+ BuiltInId::textureGradOffset_ISampler2D1_Float2_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1B1B1C,
+ 5,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0W1B1B1B1C(
+ BuiltInId::textureGradOffset_USampler2D1_Float2_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1B1B1C,
+ 5,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0I2B2B2B2C(
+ BuiltInId::textureGradOffset_Sampler3D1_Float3_Float3_Float3_Int3,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B2B2B2C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0R2B2B2B2C(
+ BuiltInId::textureGradOffset_ISampler3D1_Float3_Float3_Float3_Int3,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B2B2B2C,
+ 5,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0X2B2B2B2C(
+ BuiltInId::textureGradOffset_USampler3D1_Float3_Float3_Float3_Int3,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B2B2B2C,
+ 5,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0c2B1B1B1C(
+ BuiltInId::textureGradOffset_Sampler2DShadow1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0K2B1B1B1C(
+ BuiltInId::textureGradOffset_Sampler2DArray1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0T2B1B1B1C(
+ BuiltInId::textureGradOffset_ISampler2DArray1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1B1B1C,
+ 5,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0Z2B1B1B1C(
+ BuiltInId::textureGradOffset_USampler2DArray1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1B1B1C,
+ 5,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGradOffset_0e3B1B1B1C(
+ BuiltInId::textureGradOffset_Sampler2DArrayShadow1_Float4_Float2_Float2_Int2,
+ BuiltInName::textureGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e3B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0H2B1B1B1C(
+ BuiltInId::textureProjGradOffset_Sampler2D1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0Q2B1B1B1C(
+ BuiltInId::textureProjGradOffset_ISampler2D1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B1B1B1C,
+ 5,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0W2B1B1B1C(
+ BuiltInId::textureProjGradOffset_USampler2D1_Float3_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B1B1B1C,
+ 5,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0H3B1B1B1C(
+ BuiltInId::textureProjGradOffset_Sampler2D1_Float4_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0Q3B1B1B1C(
+ BuiltInId::textureProjGradOffset_ISampler2D1_Float4_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B1B1B1C,
+ 5,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0W3B1B1B1C(
+ BuiltInId::textureProjGradOffset_USampler2D1_Float4_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B1B1B1C,
+ 5,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0I3B2B2B2C(
+ BuiltInId::textureProjGradOffset_Sampler3D1_Float4_Float3_Float3_Int3,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B2B2B2C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0R3B2B2B2C(
+ BuiltInId::textureProjGradOffset_ISampler3D1_Float4_Float3_Float3_Int3,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B2B2B2C,
+ 5,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0X3B2B2B2C(
+ BuiltInId::textureProjGradOffset_USampler3D1_Float4_Float3_Float3_Int3,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B2B2B2C,
+ 5,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjGradOffset_0c3B1B1B1C(
+ BuiltInId::textureProjGradOffset_Sampler2DShadow1_Float4_Float2_Float2_Int2,
+ BuiltInName::textureProjGradOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B1B1B1C,
+ 5,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0H1B1C0B(
+ BuiltInId::textureOffset_Sampler2D1_Float2_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0Q1B1C0B(
+ BuiltInId::textureOffset_ISampler2D1_Float2_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1C0B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0W1B1C0B(
+ BuiltInId::textureOffset_USampler2D1_Float2_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1C0B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0I2B2C0B(
+ BuiltInId::textureOffset_Sampler3D1_Float3_Int3_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B2C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0R2B2C0B(
+ BuiltInId::textureOffset_ISampler3D1_Float3_Int3_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B2C0B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0X2B2C0B(
+ BuiltInId::textureOffset_USampler3D1_Float3_Int3_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B2C0B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0c2B1C0B(
+ BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B1C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0K2B1C0B(
+ BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B1C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0T2B1C0B(
+ BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1C0B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureOffset_0Z2B1C0B(
+ BuiltInId::textureOffset_USampler2DArray1_Float3_Int2_Float1,
+ BuiltInName::textureOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1C0B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0H2B1C0B(
+ BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B1C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0Q2B1C0B(
+ BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B1C0B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0W2B1C0B(
+ BuiltInId::textureProjOffset_USampler2D1_Float3_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B1C0B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0H3B1C0B(
+ BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B1C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0Q3B1C0B(
+ BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B1C0B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0W3B1C0B(
+ BuiltInId::textureProjOffset_USampler2D1_Float4_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B1C0B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0I3B2C0B(
+ BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B2C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0R3B2C0B(
+ BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B2C0B,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0X3B2C0B(
+ BuiltInId::textureProjOffset_USampler3D1_Float4_Int3_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B2C0B,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProjOffset_0c3B1C0B(
+ BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2_Float1,
+ BuiltInName::textureProjOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B1C0B,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0L1B(
+ BuiltInId::texture_SamplerExternalOES1_Float2,
+ BuiltInName::texture,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0L2B(
+ BuiltInId::textureProj_SamplerExternalOES1_Float3,
+ BuiltInName::textureProj,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0L3B(
+ BuiltInId::textureProj_SamplerExternalOES1_Float4,
+ BuiltInName::textureProj,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0L0C(
+ BuiltInId::textureSize_SamplerExternalOES1_Int1,
+ BuiltInName::textureSize,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0L1C0C(
+ BuiltInId::texelFetch_SamplerExternalOES1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L1C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0M1B(
+ BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2,
+ BuiltInName::texture,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M1B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0M2B(
+ BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3,
+ BuiltInName::textureProj,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0M3B(
+ BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4,
+ BuiltInName::textureProj,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M3B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_rgb_2_yuv_2B0G(
+ BuiltInId::rgb_2_yuv_Float3_YuvCscStandardEXT1,
+ BuiltInName::rgb_2_yuv,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p2B0G,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_yuv_2_rgb_2B0G(
+ BuiltInId::yuv_2_rgb_Float3_YuvCscStandardEXT1,
+ BuiltInName::yuv_2_rgb,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p2B0G,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureSize_0M0C(
+ BuiltInId::textureSize_SamplerExternal2DY2YEXT1_Int1,
+ BuiltInName::textureSize,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0M1C0C(
+ BuiltInId::texelFetch_SamplerExternal2DY2YEXT1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M1C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0H1B0B(
+ BuiltInId::texture_Sampler2D1_Float2_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0Q1B0B(
+ BuiltInId::texture_ISampler2D1_Float2_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0W1B0B(
+ BuiltInId::texture_USampler2D1_Float2_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0I2B0B(
+ BuiltInId::texture_Sampler3D1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I2B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0R2B0B(
+ BuiltInId::texture_ISampler3D1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R2B0B2C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0X2B0B(
+ BuiltInId::texture_USampler3D1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X2B0B2C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0J2B0B(
+ BuiltInId::texture_SamplerCube1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0S2B0B(
+ BuiltInId::texture_ISamplerCube1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S2B0B,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0Y2B0B(
+ BuiltInId::texture_USamplerCube1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y2B0B,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0K2B0B(
+ BuiltInId::texture_Sampler2DArray1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0T2B0B(
+ BuiltInId::texture_ISampler2DArray1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0Z2B0B(
+ BuiltInId::texture_USampler2DArray1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0H2B0B(
+ BuiltInId::textureProj_Sampler2D1_Float3_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0Q2B0B(
+ BuiltInId::textureProj_ISampler2D1_Float3_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q2B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0W2B0B(
+ BuiltInId::textureProj_USampler2D1_Float3_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W2B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0H3B0B(
+ BuiltInId::textureProj_Sampler2D1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0Q3B0B(
+ BuiltInId::textureProj_ISampler2D1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q3B0B1C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0W3B0B(
+ BuiltInId::textureProj_USampler2D1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W3B0B1C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0I3B0B(
+ BuiltInId::textureProj_Sampler3D1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0I3B0B2C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0R3B0B(
+ BuiltInId::textureProj_ISampler3D1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0R3B0B2C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0X3B0B(
+ BuiltInId::textureProj_USampler3D1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0X3B0B2C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0c2B0B(
+ BuiltInId::texture_Sampler2DShadow1_Float3_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0d3B0B(
+ BuiltInId::texture_SamplerCubeShadow1_Float4_Float1,
+ BuiltInName::texture,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0d3B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0c3B0B(
+ BuiltInId::textureProj_Sampler2DShadow1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c3B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0L1B0B(
+ BuiltInId::texture_SamplerExternalOES1_Float2_Float1,
+ BuiltInName::texture,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L1B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0L2B0B(
+ BuiltInId::textureProj_SamplerExternalOES1_Float3_Float1,
+ BuiltInName::textureProj,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0L3B0B(
+ BuiltInId::textureProj_SamplerExternalOES1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::OES_EGL_image_external_essl3,
+ BuiltInParameters::p0L3B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texture_0M1B0B(
+ BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2_Float1,
+ BuiltInName::texture,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M1B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0M2B0B(
+ BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3_Float1,
+ BuiltInName::textureProj,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureProj_0M3B0B(
+ BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4_Float1,
+ BuiltInName::textureProj,
+ TExtension::EXT_YUV_target,
+ BuiltInParameters::p0M3B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0O1C0C(
+ BuiltInId::texelFetch_Sampler2DMS1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0O1C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0U1C0C(
+ BuiltInId::texelFetch_ISampler2DMS1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0U1C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0a1C0C(
+ BuiltInId::texelFetch_USampler2DMS1_Int2_Int1,
+ BuiltInName::texelFetch,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0a1C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchExt_0O1C0C(
+ BuiltInId::texelFetchExt_Sampler2DMS1_Int2_Int1,
+ BuiltInName::texelFetchExt,
+ TExtension::ANGLE_texture_multisample,
+ BuiltInParameters::p0O1C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchExt_0U1C0C(
+ BuiltInId::texelFetchExt_ISampler2DMS1_Int2_Int1,
+ BuiltInName::texelFetchExt,
+ TExtension::ANGLE_texture_multisample,
+ BuiltInParameters::p0U1C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetchExt_0a1C0C(
+ BuiltInId::texelFetchExt_USampler2DMS1_Int2_Int1,
+ BuiltInName::texelFetchExt,
+ TExtension::ANGLE_texture_multisample,
+ BuiltInParameters::p0a1C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0P2C0C(
+ BuiltInId::texelFetch_Sampler2DMSArray1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::OES_texture_storage_multisample_2d_array,
+ BuiltInParameters::p0P2C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0V2C0C(
+ BuiltInId::texelFetch_ISampler2DMSArray1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::OES_texture_storage_multisample_2d_array,
+ BuiltInParameters::p0V2C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_texelFetch_0b2C0C(
+ BuiltInId::texelFetch_USampler2DMSArray1_Int3_Int1,
+ BuiltInName::texelFetch,
+ TExtension::OES_texture_storage_multisample_2d_array,
+ BuiltInParameters::p0b2C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0H1B(
+ BuiltInId::textureGather_Sampler2D1_Float2,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1B1B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0Q1B(
+ BuiltInId::textureGather_ISampler2D1_Float2,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1B1B1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0W1B(
+ BuiltInId::textureGather_USampler2D1_Float2,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1C0C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0H1B0C(
+ BuiltInId::textureGather_Sampler2D1_Float2_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0Q1B0C(
+ BuiltInId::textureGather_ISampler2D1_Float2_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0W1B0C(
+ BuiltInId::textureGather_USampler2D1_Float2_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0K2B(
+ BuiltInId::textureGather_Sampler2DArray1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0T2B(
+ BuiltInId::textureGather_ISampler2DArray1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1B1B1C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0Z2B(
+ BuiltInId::textureGather_USampler2DArray1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1B1B1C,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0K2B0C(
+ BuiltInId::textureGather_Sampler2DArray1_Float3_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0T2B0C(
+ BuiltInId::textureGather_ISampler2DArray1_Float3_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0Z2B0C(
+ BuiltInId::textureGather_USampler2DArray1_Float3_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0J2B(
+ BuiltInId::textureGather_SamplerCube1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B2B2B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0S2B(
+ BuiltInId::textureGather_ISamplerCube1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S2B0B,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0Y2B(
+ BuiltInId::textureGather_USamplerCube1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y2B2B2B,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0J2B0C(
+ BuiltInId::textureGather_SamplerCube1_Float3_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0J2B0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0S2B0C(
+ BuiltInId::textureGather_ISamplerCube1_Float3_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0S2B0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0Y2B0C(
+ BuiltInId::textureGather_USamplerCube1_Float3_Int1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Y2B0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0c1B(
+ BuiltInId::textureGather_Sampler2DShadow1_Float2,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c1B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0c1B0B(
+ BuiltInId::textureGather_Sampler2DShadow1_Float2_Float1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c1B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0e2B(
+ BuiltInId::textureGather_Sampler2DArrayShadow1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e2B0B1C,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0e2B0B(
+ BuiltInId::textureGather_Sampler2DArrayShadow1_Float3_Float1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e2B0B1C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0d2B(
+ BuiltInId::textureGather_SamplerCubeShadow1_Float3,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0d2B0B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGather_0d2B0B(
+ BuiltInId::textureGather_SamplerCubeShadow1_Float3_Float1,
+ BuiltInName::textureGather,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0d2B0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0H1B1C(
+ BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1C0B,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0Q1B1C(
+ BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0W1B1C(
+ BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0H1B1C0C(
+ BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2_Int1,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0H1B1C0C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0Q1B1C0C(
+ BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2_Int1,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Q1B1C0C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0W1B1C0C(
+ BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2_Int1,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0W1B1C0C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0K2B1C(
+ BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B1C0C,
+ 3,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0T2B1C(
+ BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0Z2B1C(
+ BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1C0C,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0K2B1C0C(
+ BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2_Int1,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0K2B1C0C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0T2B1C0C(
+ BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2_Int1,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0T2B1C0C,
+ 4,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0Z2B1C0C(
+ BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2_Int1,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0Z2B1C0C,
+ 4,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0c1B0B1C(
+ BuiltInId::textureGatherOffset_Sampler2DShadow1_Float2_Float1_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0c1B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_textureGatherOffset_0e2B0B1C(
+ BuiltInId::textureGatherOffset_Sampler2DArrayShadow1_Float3_Float1_Int2,
+ BuiltInName::textureGatherOffset,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0e2B0B1C,
+ 4,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_dFdx_0B(
+ BuiltInId::dFdx_Float1,
+ BuiltInName::dFdx,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdx_1B(
+ BuiltInId::dFdx_Float2,
+ BuiltInName::dFdx,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdx_2B(
+ BuiltInId::dFdx_Float3,
+ BuiltInName::dFdx,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdx_3B(
+ BuiltInId::dFdx_Float4,
+ BuiltInName::dFdx,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpDFdx,
+ false);
+constexpr const TFunction kFunction_dFdy_0B(
+ BuiltInId::dFdy_Float1,
+ BuiltInName::dFdy,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_dFdy_1B(
+ BuiltInId::dFdy_Float2,
+ BuiltInName::dFdy,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_dFdy_2B(
+ BuiltInId::dFdy_Float3,
+ BuiltInName::dFdy,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_dFdy_3B(
+ BuiltInId::dFdy_Float4,
+ BuiltInName::dFdy,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpDFdy,
+ false);
+constexpr const TFunction kFunction_fwidth_0B(
+ BuiltInId::fwidth_Float1,
+ BuiltInName::fwidth,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0B0C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_fwidth_1B(
+ BuiltInId::fwidth_Float2,
+ BuiltInName::fwidth,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p1B1B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_fwidth_2B(
+ BuiltInId::fwidth_Float3,
+ BuiltInName::fwidth,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p2B_o_2C,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_fwidth_3B(
+ BuiltInId::fwidth_Float4,
+ BuiltInName::fwidth,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p3B0B0B,
+ 1,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpFwidth,
+ false);
+constexpr const TFunction kFunction_atomicCounter_0F(
+ BuiltInId::atomicCounter_AtomicCounter1,
+ BuiltInName::atomicCounter,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0F,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_atomicCounterIncrement_0F(
+ BuiltInId::atomicCounterIncrement_AtomicCounter1,
+ BuiltInName::atomicCounterIncrement,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0F,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_atomicCounterDecrement_0F(
+ BuiltInId::atomicCounterDecrement_AtomicCounter1,
+ BuiltInName::atomicCounterDecrement,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0F,
+ 1,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_atomicAdd_0D0D(
+ BuiltInId::atomicAdd_UInt1_UInt1,
+ BuiltInName::atomicAdd,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicAdd,
+ false);
+constexpr const TFunction kFunction_atomicAdd_0C0C(
+ BuiltInId::atomicAdd_Int1_Int1,
+ BuiltInName::atomicAdd,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicAdd,
+ false);
+constexpr const TFunction kFunction_atomicMin_0D0D(
+ BuiltInId::atomicMin_UInt1_UInt1,
+ BuiltInName::atomicMin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicMin,
+ false);
+constexpr const TFunction kFunction_atomicMin_0C0C(
+ BuiltInId::atomicMin_Int1_Int1,
+ BuiltInName::atomicMin,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicMin,
+ false);
+constexpr const TFunction kFunction_atomicMax_0D0D(
+ BuiltInId::atomicMax_UInt1_UInt1,
+ BuiltInName::atomicMax,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicMax,
+ false);
+constexpr const TFunction kFunction_atomicMax_0C0C(
+ BuiltInId::atomicMax_Int1_Int1,
+ BuiltInName::atomicMax,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicMax,
+ false);
+constexpr const TFunction kFunction_atomicAnd_0D0D(
+ BuiltInId::atomicAnd_UInt1_UInt1,
+ BuiltInName::atomicAnd,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicAnd,
+ false);
+constexpr const TFunction kFunction_atomicAnd_0C0C(
+ BuiltInId::atomicAnd_Int1_Int1,
+ BuiltInName::atomicAnd,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicAnd,
+ false);
+constexpr const TFunction kFunction_atomicOr_0D0D(
+ BuiltInId::atomicOr_UInt1_UInt1,
+ BuiltInName::atomicOr,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicOr,
+ false);
+constexpr const TFunction kFunction_atomicOr_0C0C(
+ BuiltInId::atomicOr_Int1_Int1,
+ BuiltInName::atomicOr,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicOr,
+ false);
+constexpr const TFunction kFunction_atomicXor_0D0D(
+ BuiltInId::atomicXor_UInt1_UInt1,
+ BuiltInName::atomicXor,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicXor,
+ false);
+constexpr const TFunction kFunction_atomicXor_0C0C(
+ BuiltInId::atomicXor_Int1_Int1,
+ BuiltInName::atomicXor,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicXor,
+ false);
+constexpr const TFunction kFunction_atomicExchange_0D0D(
+ BuiltInId::atomicExchange_UInt1_UInt1,
+ BuiltInName::atomicExchange,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicExchange,
+ false);
+constexpr const TFunction kFunction_atomicExchange_0C0C(
+ BuiltInId::atomicExchange_Int1_Int1,
+ BuiltInName::atomicExchange,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicExchange,
+ false);
+constexpr const TFunction kFunction_atomicCompSwap_0D0D0D(
+ BuiltInId::atomicCompSwap_UInt1_UInt1_UInt1,
+ BuiltInName::atomicCompSwap,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0D0D0D,
+ 3,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicCompSwap,
+ false);
+constexpr const TFunction kFunction_atomicCompSwap_0C0C0C(
+ BuiltInId::atomicCompSwap_Int1_Int1_Int1,
+ BuiltInName::atomicCompSwap,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p_io_0C0C0C,
+ 3,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpAtomicCompSwap,
+ false);
+constexpr const TFunction kFunction_imageSize_0f(
+ BuiltInId::imageSize_Image2D1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0f1C3B,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0g(
+ BuiltInId::imageSize_IImage2D1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0g1C3C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0h(
+ BuiltInId::imageSize_UImage2D1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0h1C3D,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0i(
+ BuiltInId::imageSize_Image3D1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0i2C3B,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0j(
+ BuiltInId::imageSize_IImage3D1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0j2C3C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0k(
+ BuiltInId::imageSize_UImage3D1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0k2C3D,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0l(
+ BuiltInId::imageSize_Image2DArray1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0l2C3B,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0m(
+ BuiltInId::imageSize_IImage2DArray1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0m2C3C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0n(
+ BuiltInId::imageSize_UImage2DArray1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0n2C3D,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0o(
+ BuiltInId::imageSize_ImageCube1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0o2C3B,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0p(
+ BuiltInId::imageSize_IImageCube1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0p2C3C,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageSize_0q(
+ BuiltInId::imageSize_UImageCube1,
+ BuiltInName::imageSize,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0q2C3D,
+ 1,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0f1C(
+ BuiltInId::imageLoad_Image2D1_Int2,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0f1C3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0g1C(
+ BuiltInId::imageLoad_IImage2D1_Int2,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0g1C3C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0h1C(
+ BuiltInId::imageLoad_UImage2D1_Int2,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0h1C3D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0i2C(
+ BuiltInId::imageLoad_Image3D1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0i2C3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0j2C(
+ BuiltInId::imageLoad_IImage3D1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0j2C3C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0k2C(
+ BuiltInId::imageLoad_UImage3D1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0k2C3D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0l2C(
+ BuiltInId::imageLoad_Image2DArray1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0l2C3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0m2C(
+ BuiltInId::imageLoad_IImage2DArray1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0m2C3C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0n2C(
+ BuiltInId::imageLoad_UImage2DArray1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0n2C3D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0o2C(
+ BuiltInId::imageLoad_ImageCube1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0o2C3B,
+ 2,
+ StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0p2C(
+ BuiltInId::imageLoad_IImageCube1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0p2C3C,
+ 2,
+ StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageLoad_0q2C(
+ BuiltInId::imageLoad_UImageCube1_Int3,
+ BuiltInName::imageLoad,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0q2C3D,
+ 2,
+ StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0f1C3B(
+ BuiltInId::imageStore_Image2D1_Int2_Float4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0f1C3B,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0g1C3C(
+ BuiltInId::imageStore_IImage2D1_Int2_Int4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0g1C3C,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0h1C3D(
+ BuiltInId::imageStore_UImage2D1_Int2_UInt4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0h1C3D,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0i2C3B(
+ BuiltInId::imageStore_Image3D1_Int3_Float4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0i2C3B,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0j2C3C(
+ BuiltInId::imageStore_IImage3D1_Int3_Int4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0j2C3C,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0k2C3D(
+ BuiltInId::imageStore_UImage3D1_Int3_UInt4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0k2C3D,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0l2C3B(
+ BuiltInId::imageStore_Image2DArray1_Int3_Float4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0l2C3B,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0m2C3C(
+ BuiltInId::imageStore_IImage2DArray1_Int3_Int4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0m2C3C,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0n2C3D(
+ BuiltInId::imageStore_UImage2DArray1_Int3_UInt4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0n2C3D,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0o2C3B(
+ BuiltInId::imageStore_ImageCube1_Int3_Float4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0o2C3B,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0p2C3C(
+ BuiltInId::imageStore_IImageCube1_Int3_Int4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0p2C3C,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_imageStore_0q2C3D(
+ BuiltInId::imageStore_UImageCube1_Int3_UInt4,
+ BuiltInName::imageStore,
+ TExtension::UNDEFINED,
+ BuiltInParameters::p0q2C3D,
+ 3,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpCallBuiltInFunction,
+ false);
+constexpr const TFunction kFunction_memoryBarrier_(
+ BuiltInId::memoryBarrier,
+ BuiltInName::memoryBarrier,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMemoryBarrier,
+ false);
+constexpr const TFunction kFunction_memoryBarrierAtomicCounter_(
+ BuiltInId::memoryBarrierAtomicCounter,
+ BuiltInName::memoryBarrierAtomicCounter,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMemoryBarrierAtomicCounter,
+ false);
+constexpr const TFunction kFunction_memoryBarrierBuffer_(
+ BuiltInId::memoryBarrierBuffer,
+ BuiltInName::memoryBarrierBuffer,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMemoryBarrierBuffer,
+ false);
+constexpr const TFunction kFunction_memoryBarrierImage_(
+ BuiltInId::memoryBarrierImage,
+ BuiltInName::memoryBarrierImage,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMemoryBarrierImage,
+ false);
+constexpr const TFunction kFunction_barrier_(
+ BuiltInId::barrier,
+ BuiltInName::barrier,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpBarrier,
+ false);
+constexpr const TFunction kFunction_memoryBarrierShared_(
+ BuiltInId::memoryBarrierShared,
+ BuiltInName::memoryBarrierShared,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpMemoryBarrierShared,
+ false);
+constexpr const TFunction kFunction_groupMemoryBarrier_(
+ BuiltInId::groupMemoryBarrier,
+ BuiltInName::groupMemoryBarrier,
+ TExtension::UNDEFINED,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpGroupMemoryBarrier,
+ false);
+constexpr const TFunction kFunction_EmitVertex_(
+ BuiltInId::EmitVertex,
+ BuiltInName::EmitVertex,
+ TExtension::EXT_geometry_shader,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpEmitVertex,
+ false);
+constexpr const TFunction kFunction_EndPrimitive_(
+ BuiltInId::EndPrimitive,
+ BuiltInName::EndPrimitive,
+ TExtension::EXT_geometry_shader,
+ BuiltInParameters::empty,
+ 0,
+ StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(),
+ EOpEndPrimitive,
+ false);
+
+} // namespace BuiltInFunction
+
+void TSymbolTable::initializeBuiltInVariables(sh::GLenum shaderType,
+ ShShaderSpec spec,
+ const ShBuiltInResources &resources)
+{
+ const TSourceLoc zeroSourceLoc = {0, 0, 0, 0};
+ TFieldList *fields_gl_DepthRangeParameters = new TFieldList();
+ fields_gl_DepthRangeParameters->push_back(
+ new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), BuiltInName::near, zeroSourceLoc,
+ SymbolType::BuiltIn));
+ fields_gl_DepthRangeParameters->push_back(
+ new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), BuiltInName::far, zeroSourceLoc,
+ SymbolType::BuiltIn));
+ fields_gl_DepthRangeParameters->push_back(
+ new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), BuiltInName::diff, zeroSourceLoc,
+ SymbolType::BuiltIn));
+ TStructure *gl_DepthRangeParameters =
+ new TStructure(BuiltInId::gl_DepthRangeParameters, BuiltInName::gl_DepthRangeParameters,
+ TExtension::UNDEFINED, fields_gl_DepthRangeParameters);
+ mVar_gl_DepthRangeParameters = gl_DepthRangeParameters;
+ TType *type_gl_DepthRange = new TType(gl_DepthRangeParameters, false);
+ type_gl_DepthRange->setQualifier(EvqUniform);
+ type_gl_DepthRange->realize();
+ mVar_gl_DepthRange =
+ new TVariable(BuiltInId::gl_DepthRange, BuiltInName::gl_DepthRange, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, type_gl_DepthRange);
+ mVar_gl_MaxVertexAttribs = new TVariable(
+ BuiltInId::gl_MaxVertexAttribs, BuiltInName::gl_MaxVertexAttribs, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexAttribs);
+ mVar_gl_MaxVertexAttribs->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVertexUniformVectors =
+ new TVariable(BuiltInId::gl_MaxVertexUniformVectors,
+ BuiltInName::gl_MaxVertexUniformVectors, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexUniformVectors);
+ mVar_gl_MaxVertexUniformVectors->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVertexTextureImageUnits =
+ new TVariable(BuiltInId::gl_MaxVertexTextureImageUnits,
+ BuiltInName::gl_MaxVertexTextureImageUnits, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexTextureImageUnits);
+ mVar_gl_MaxVertexTextureImageUnits->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxCombinedTextureImageUnits =
+ new TVariable(BuiltInId::gl_MaxCombinedTextureImageUnits,
+ BuiltInName::gl_MaxCombinedTextureImageUnits, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxCombinedTextureImageUnits);
+ mVar_gl_MaxCombinedTextureImageUnits->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxTextureImageUnits =
+ new TVariable(BuiltInId::gl_MaxTextureImageUnits, BuiltInName::gl_MaxTextureImageUnits,
+ SymbolType::BuiltIn, TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxTextureImageUnits);
+ mVar_gl_MaxTextureImageUnits->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxFragmentUniformVectors =
+ new TVariable(BuiltInId::gl_MaxFragmentUniformVectors,
+ BuiltInName::gl_MaxFragmentUniformVectors, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxFragmentUniformVectors);
+ mVar_gl_MaxFragmentUniformVectors->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVaryingVectors = new TVariable(
+ BuiltInId::gl_MaxVaryingVectors, BuiltInName::gl_MaxVaryingVectors, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVaryingVectors);
+ mVar_gl_MaxVaryingVectors->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxDrawBuffers = new TVariable(
+ BuiltInId::gl_MaxDrawBuffers, BuiltInName::gl_MaxDrawBuffers, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxDrawBuffers);
+ mVar_gl_MaxDrawBuffers->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxDualSourceDrawBuffersEXT = new TVariable(
+ BuiltInId::gl_MaxDualSourceDrawBuffersEXT, BuiltInName::gl_MaxDualSourceDrawBuffersEXT,
+ SymbolType::BuiltIn, TExtension::EXT_blend_func_extended,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxDualSourceDrawBuffers);
+ mVar_gl_MaxDualSourceDrawBuffersEXT->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVertexOutputVectors =
+ new TVariable(BuiltInId::gl_MaxVertexOutputVectors, BuiltInName::gl_MaxVertexOutputVectors,
+ SymbolType::BuiltIn, TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexOutputVectors);
+ mVar_gl_MaxVertexOutputVectors->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxFragmentInputVectors =
+ new TVariable(BuiltInId::gl_MaxFragmentInputVectors,
+ BuiltInName::gl_MaxFragmentInputVectors, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxFragmentInputVectors);
+ mVar_gl_MaxFragmentInputVectors->shareConstPointer(unionArray);
+ }
+ mVar_gl_MinProgramTexelOffset =
+ new TVariable(BuiltInId::gl_MinProgramTexelOffset, BuiltInName::gl_MinProgramTexelOffset,
+ SymbolType::BuiltIn, TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MinProgramTexelOffset);
+ mVar_gl_MinProgramTexelOffset->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxProgramTexelOffset =
+ new TVariable(BuiltInId::gl_MaxProgramTexelOffset, BuiltInName::gl_MaxProgramTexelOffset,
+ SymbolType::BuiltIn, TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxProgramTexelOffset);
+ mVar_gl_MaxProgramTexelOffset->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxImageUnits = new TVariable(
+ BuiltInId::gl_MaxImageUnits, BuiltInName::gl_MaxImageUnits, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxImageUnits);
+ mVar_gl_MaxImageUnits->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVertexImageUniforms =
+ new TVariable(BuiltInId::gl_MaxVertexImageUniforms, BuiltInName::gl_MaxVertexImageUniforms,
+ SymbolType::BuiltIn, TExtension::UNDEFINED,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexImageUniforms);
+ mVar_gl_MaxVertexImageUniforms->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxFragmentImageUniforms =
+ new TVariable(BuiltInId::gl_MaxFragmentImageUniforms,
+ BuiltInName::gl_MaxFragmentImageUniforms, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxFragmentImageUniforms);
+ mVar_gl_MaxFragmentImageUniforms->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeImageUniforms =
+ new TVariable(BuiltInId::gl_MaxComputeImageUniforms,
+ BuiltInName::gl_MaxComputeImageUniforms, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxComputeImageUniforms);
+ mVar_gl_MaxComputeImageUniforms->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxCombinedImageUniforms =
+ new TVariable(BuiltInId::gl_MaxCombinedImageUniforms,
+ BuiltInName::gl_MaxCombinedImageUniforms, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxCombinedImageUniforms);
+ mVar_gl_MaxCombinedImageUniforms->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxCombinedShaderOutputResources =
+ new TVariable(BuiltInId::gl_MaxCombinedShaderOutputResources,
+ BuiltInName::gl_MaxCombinedShaderOutputResources, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxCombinedShaderOutputResources);
+ mVar_gl_MaxCombinedShaderOutputResources->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeWorkGroupCount =
+ new TVariable(BuiltInId::gl_MaxComputeWorkGroupCount,
+ BuiltInName::gl_MaxComputeWorkGroupCount, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpHigh, EvqConst, 3, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[3];
+ for (size_t index = 0u; index < 3; ++index)
+ {
+ unionArray[index].setIConst(resources.MaxComputeWorkGroupCount[index]);
+ }
+ mVar_gl_MaxComputeWorkGroupCount->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeWorkGroupSize =
+ new TVariable(BuiltInId::gl_MaxComputeWorkGroupSize,
+ BuiltInName::gl_MaxComputeWorkGroupSize, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpHigh, EvqConst, 3, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[3];
+ for (size_t index = 0u; index < 3; ++index)
+ {
+ unionArray[index].setIConst(resources.MaxComputeWorkGroupSize[index]);
+ }
+ mVar_gl_MaxComputeWorkGroupSize->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeUniformComponents =
+ new TVariable(BuiltInId::gl_MaxComputeUniformComponents,
+ BuiltInName::gl_MaxComputeUniformComponents, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxComputeUniformComponents);
+ mVar_gl_MaxComputeUniformComponents->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeTextureImageUnits =
+ new TVariable(BuiltInId::gl_MaxComputeTextureImageUnits,
+ BuiltInName::gl_MaxComputeTextureImageUnits, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxComputeTextureImageUnits);
+ mVar_gl_MaxComputeTextureImageUnits->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeAtomicCounters =
+ new TVariable(BuiltInId::gl_MaxComputeAtomicCounters,
+ BuiltInName::gl_MaxComputeAtomicCounters, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxComputeAtomicCounters);
+ mVar_gl_MaxComputeAtomicCounters->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxComputeAtomicCounterBuffers =
+ new TVariable(BuiltInId::gl_MaxComputeAtomicCounterBuffers,
+ BuiltInName::gl_MaxComputeAtomicCounterBuffers, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxComputeAtomicCounterBuffers);
+ mVar_gl_MaxComputeAtomicCounterBuffers->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVertexAtomicCounters =
+ new TVariable(BuiltInId::gl_MaxVertexAtomicCounters,
+ BuiltInName::gl_MaxVertexAtomicCounters, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexAtomicCounters);
+ mVar_gl_MaxVertexAtomicCounters->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxFragmentAtomicCounters =
+ new TVariable(BuiltInId::gl_MaxFragmentAtomicCounters,
+ BuiltInName::gl_MaxFragmentAtomicCounters, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxFragmentAtomicCounters);
+ mVar_gl_MaxFragmentAtomicCounters->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxCombinedAtomicCounters =
+ new TVariable(BuiltInId::gl_MaxCombinedAtomicCounters,
+ BuiltInName::gl_MaxCombinedAtomicCounters, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxCombinedAtomicCounters);
+ mVar_gl_MaxCombinedAtomicCounters->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxAtomicCounterBindings =
+ new TVariable(BuiltInId::gl_MaxAtomicCounterBindings,
+ BuiltInName::gl_MaxAtomicCounterBindings, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxAtomicCounterBindings);
+ mVar_gl_MaxAtomicCounterBindings->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxVertexAtomicCounterBuffers =
+ new TVariable(BuiltInId::gl_MaxVertexAtomicCounterBuffers,
+ BuiltInName::gl_MaxVertexAtomicCounterBuffers, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxVertexAtomicCounterBuffers);
+ mVar_gl_MaxVertexAtomicCounterBuffers->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxFragmentAtomicCounterBuffers =
+ new TVariable(BuiltInId::gl_MaxFragmentAtomicCounterBuffers,
+ BuiltInName::gl_MaxFragmentAtomicCounterBuffers, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxFragmentAtomicCounterBuffers);
+ mVar_gl_MaxFragmentAtomicCounterBuffers->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxCombinedAtomicCounterBuffers =
+ new TVariable(BuiltInId::gl_MaxCombinedAtomicCounterBuffers,
+ BuiltInName::gl_MaxCombinedAtomicCounterBuffers, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxCombinedAtomicCounterBuffers);
+ mVar_gl_MaxCombinedAtomicCounterBuffers->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxAtomicCounterBufferSize =
+ new TVariable(BuiltInId::gl_MaxAtomicCounterBufferSize,
+ BuiltInName::gl_MaxAtomicCounterBufferSize, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxAtomicCounterBufferSize);
+ mVar_gl_MaxAtomicCounterBufferSize->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryInputComponents = new TVariable(
+ BuiltInId::gl_MaxGeometryInputComponents, BuiltInName::gl_MaxGeometryInputComponents,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryInputComponents);
+ mVar_gl_MaxGeometryInputComponents->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryOutputComponents = new TVariable(
+ BuiltInId::gl_MaxGeometryOutputComponents, BuiltInName::gl_MaxGeometryOutputComponents,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryOutputComponents);
+ mVar_gl_MaxGeometryOutputComponents->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryImageUniforms = new TVariable(
+ BuiltInId::gl_MaxGeometryImageUniforms, BuiltInName::gl_MaxGeometryImageUniforms,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryImageUniforms);
+ mVar_gl_MaxGeometryImageUniforms->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryTextureImageUnits = new TVariable(
+ BuiltInId::gl_MaxGeometryTextureImageUnits, BuiltInName::gl_MaxGeometryTextureImageUnits,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryTextureImageUnits);
+ mVar_gl_MaxGeometryTextureImageUnits->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryOutputVertices = new TVariable(
+ BuiltInId::gl_MaxGeometryOutputVertices, BuiltInName::gl_MaxGeometryOutputVertices,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryOutputVertices);
+ mVar_gl_MaxGeometryOutputVertices->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryTotalOutputComponents = new TVariable(
+ BuiltInId::gl_MaxGeometryTotalOutputComponents,
+ BuiltInName::gl_MaxGeometryTotalOutputComponents, SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryTotalOutputComponents);
+ mVar_gl_MaxGeometryTotalOutputComponents->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryUniformComponents = new TVariable(
+ BuiltInId::gl_MaxGeometryUniformComponents, BuiltInName::gl_MaxGeometryUniformComponents,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryUniformComponents);
+ mVar_gl_MaxGeometryUniformComponents->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryAtomicCounters = new TVariable(
+ BuiltInId::gl_MaxGeometryAtomicCounters, BuiltInName::gl_MaxGeometryAtomicCounters,
+ SymbolType::BuiltIn, TExtension::EXT_geometry_shader,
+ StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryAtomicCounters);
+ mVar_gl_MaxGeometryAtomicCounters->shareConstPointer(unionArray);
+ }
+ mVar_gl_MaxGeometryAtomicCounterBuffers = new TVariable(
+ BuiltInId::gl_MaxGeometryAtomicCounterBuffers,
+ BuiltInName::gl_MaxGeometryAtomicCounterBuffers, SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>());
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(resources.MaxGeometryAtomicCounterBuffers);
+ mVar_gl_MaxGeometryAtomicCounterBuffers->shareConstPointer(unionArray);
+ }
+ if (shaderType == GL_FRAGMENT_SHADER)
+ {
+ TType *type_gl_FragData = new TType(EbtFloat, EbpMedium, EvqFragData, 4);
+ if (spec != SH_WEBGL2_SPEC && spec != SH_WEBGL3_SPEC)
+ {
+ type_gl_FragData->makeArray(resources.MaxDrawBuffers);
+ }
+ else
+ {
+ type_gl_FragData->makeArray(1u);
+ }
+ type_gl_FragData->realize();
+ mVar_gl_FragData =
+ new TVariable(BuiltInId::gl_FragData, BuiltInName::gl_FragData, SymbolType::BuiltIn,
+ TExtension::UNDEFINED, type_gl_FragData);
+ }
+ if ((shaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_blend_func_extended))
+ {
+ TType *type_gl_SecondaryFragDataEXT =
+ new TType(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1);
+ type_gl_SecondaryFragDataEXT->makeArray(resources.MaxDualSourceDrawBuffers);
+ type_gl_SecondaryFragDataEXT->realize();
+ mVar_gl_SecondaryFragDataEXT = new TVariable(
+ BuiltInId::gl_SecondaryFragDataEXT, BuiltInName::gl_SecondaryFragDataEXT,
+ SymbolType::BuiltIn, TExtension::EXT_blend_func_extended, type_gl_SecondaryFragDataEXT);
+ }
+ if ((shaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_frag_depth))
+ {
+ TType *type_gl_FragDepthEXT = new TType(
+ EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepthEXT, 1);
+ type_gl_FragDepthEXT->realize();
+ mVar_gl_FragDepthEXT =
+ new TVariable(BuiltInId::gl_FragDepthEXT, BuiltInName::gl_FragDepthEXT,
+ SymbolType::BuiltIn, TExtension::EXT_frag_depth, type_gl_FragDepthEXT);
+ }
+ TType *type_gl_LastFragData = new TType(EbtFloat, EbpMedium, EvqLastFragData, 4, 1);
+ type_gl_LastFragData->makeArray(resources.MaxDrawBuffers);
+ type_gl_LastFragData->realize();
+ mVar_gl_LastFragData =
+ new TVariable(BuiltInId::gl_LastFragData, BuiltInName::gl_LastFragData, SymbolType::BuiltIn,
+ TExtension::EXT_shader_framebuffer_fetch, type_gl_LastFragData);
+ TType *type_gl_LastFragDataNV = new TType(EbtFloat, EbpMedium, EvqLastFragData, 4, 1);
+ type_gl_LastFragDataNV->makeArray(resources.MaxDrawBuffers);
+ type_gl_LastFragDataNV->realize();
+ mVar_gl_LastFragDataNV = new TVariable(
+ BuiltInId::gl_LastFragDataNV, BuiltInName::gl_LastFragData, SymbolType::BuiltIn,
+ TExtension::NV_shader_framebuffer_fetch, type_gl_LastFragDataNV);
+ TFieldList *fields_gl_PerVertex = new TFieldList();
+ fields_gl_PerVertex->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqPosition, 4, 1),
+ BuiltInName::gl_Position, zeroSourceLoc,
+ SymbolType::BuiltIn));
+ TInterfaceBlock *gl_PerVertex =
+ new TInterfaceBlock(BuiltInId::gl_PerVertex, BuiltInName::gl_PerVertex,
+ TExtension::EXT_geometry_shader, fields_gl_PerVertex);
+ mVar_gl_PerVertex = gl_PerVertex;
+ if (shaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ TType *type_gl_in = new TType(gl_PerVertex, EvqPerVertexIn, TLayoutQualifier::Create());
+ type_gl_in->makeArray(0u);
+ type_gl_in->realize();
+ mVar_gl_in = new TVariable(BuiltInId::gl_in, BuiltInName::gl_in, SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader, type_gl_in);
+ }
+ TFieldList *fields_gl_PerVertexOutBlock = new TFieldList();
+ fields_gl_PerVertexOutBlock->push_back(
+ new TField(new TType(EbtFloat, EbpHigh, EvqPosition, 4, 1), BuiltInName::gl_Position,
+ zeroSourceLoc, SymbolType::BuiltIn));
+ TInterfaceBlock *gl_PerVertexOutBlock =
+ new TInterfaceBlock(BuiltInId::gl_PerVertexOutBlock, BuiltInName::gl_PerVertex,
+ TExtension::EXT_geometry_shader, fields_gl_PerVertexOutBlock);
+ TType *type_gl_PositionGS = new TType(EbtFloat, EbpHigh, EvqPosition, 4);
+ type_gl_PositionGS->setInterfaceBlock(gl_PerVertexOutBlock);
+ type_gl_PositionGS->realize();
+ mVar_gl_PositionGS =
+ new TVariable(BuiltInId::gl_PositionGS, BuiltInName::gl_Position, SymbolType::BuiltIn,
+ TExtension::EXT_geometry_shader, type_gl_PositionGS);
+}
+
+const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, int shaderVersion) const
+{
+ if (name.length() > 35)
+ {
+ return nullptr;
+ }
+ uint32_t nameHash = name.mangledNameHash();
+ if ((nameHash >> 31) != 0)
+ {
+ // The name contains [ or {.
+ return nullptr;
+ }
+ if (shaderVersion >= 310)
+ {
+ switch (nameHash)
+ {
+ case 0x0a50832eu:
+ {
+ if (name.beginsWith(BuiltInName::ldexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_ldexp_1B1C;
+ }
+ break;
+ }
+ case 0x0a50a6eeu:
+ {
+ if (name.beginsWith(BuiltInName::frexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_frexp_2B2C;
+ }
+ break;
+ }
+ case 0x0a52bed1u:
+ {
+ if (name.beginsWith(BuiltInName::ldexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_ldexp_0B0C;
+ }
+ break;
+ }
+ case 0x0a53e9c4u:
+ {
+ if (name == BuiltInName::frexp_3B3C)
+ {
+ return &BuiltInFunction::kFunction_frexp_3B3C;
+ }
+ break;
+ }
+ case 0x0a54aa52u:
+ {
+ if (name.beginsWith(BuiltInName::ldexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_ldexp_2B2C;
+ }
+ break;
+ }
+ case 0x0a55008fu:
+ {
+ if (name.beginsWith(BuiltInName::frexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_frexp_1B1C;
+ }
+ break;
+ }
+ case 0x0a5799e7u:
+ {
+ if (name.beginsWith(BuiltInName::frexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_frexp_0B0C;
+ }
+ break;
+ }
+ case 0x0a57c201u:
+ {
+ if (name.beginsWith(BuiltInName::ldexp))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_ldexp_3B3C;
+ }
+ break;
+ }
+ case 0x0e500330u:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_3C;
+ }
+ break;
+ }
+ case 0x0e503089u:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_3D;
+ }
+ break;
+ }
+ case 0x0e508070u:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_0C;
+ }
+ break;
+ }
+ case 0x0e508a05u:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_0D;
+ }
+ break;
+ }
+ case 0x0e51917du:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_1C;
+ }
+ break;
+ }
+ case 0x0e51dc78u:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_1D;
+ }
+ break;
+ }
+ case 0x0e54832eu:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_2C;
+ }
+ break;
+ }
+ case 0x0e54b667u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_2D;
+ }
+ break;
+ }
+ case 0x0e550f72u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_1D;
+ }
+ break;
+ }
+ case 0x0e5514e7u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_1C;
+ }
+ break;
+ }
+ case 0x0e5607c2u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_0C;
+ }
+ break;
+ }
+ case 0x0e5650c7u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_0D;
+ }
+ break;
+ }
+ case 0x0e56a99cu:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_2D;
+ }
+ break;
+ }
+ case 0x0e56cd55u:
+ {
+ if (name.beginsWith(BuiltInName::findMSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findMSB_2C;
+ }
+ break;
+ }
+ case 0x0e573680u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_3D;
+ }
+ break;
+ }
+ case 0x0e574a59u:
+ {
+ if (name.beginsWith(BuiltInName::findLSB))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_findLSB_3C;
+ }
+ break;
+ }
+ case 0x10581cccu:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_2D;
+ }
+ break;
+ }
+ case 0x10584c2du:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_2C;
+ }
+ break;
+ }
+ case 0x105896f1u:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_1D;
+ }
+ break;
+ }
+ case 0x1058cbf7u:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_1C;
+ }
+ break;
+ }
+ case 0x1059a37cu:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_0D;
+ }
+ break;
+ }
+ case 0x1059dae9u:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_0C;
+ }
+ break;
+ }
+ case 0x105b1832u:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_3C;
+ }
+ break;
+ }
+ case 0x105b2810u:
+ {
+ if (name.beginsWith(BuiltInName::bitCount))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_bitCount_3D;
+ }
+ break;
+ }
+ case 0x106a2daeu:
+ {
+ if (name.beginsWith(BuiltInName::atomicOr))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_atomicOr_0D0D;
+ }
+ break;
+ }
+ case 0x106bd5b6u:
+ {
+ if (name.beginsWith(BuiltInName::atomicOr))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_atomicOr_0C0C;
+ }
+ break;
+ }
+ case 0x126520f8u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0p;
+ }
+ break;
+ }
+ case 0x12653967u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0q;
+ }
+ break;
+ }
+ case 0x1265b53eu:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0g;
+ }
+ break;
+ }
+ case 0x1265cbcau:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0k;
+ }
+ break;
+ }
+ case 0x1265cc8du:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0f;
+ }
+ break;
+ }
+ case 0x1265e196u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0o;
+ }
+ break;
+ }
+ case 0x1265e603u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0h;
+ }
+ break;
+ }
+ case 0x1265f559u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0j;
+ }
+ break;
+ }
+ case 0x1265fcacu:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0i;
+ }
+ break;
+ }
+ case 0x12660ccfu:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0l;
+ }
+ break;
+ }
+ case 0x12661578u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0m;
+ }
+ break;
+ }
+ case 0x12661be5u:
+ {
+ if (name.beginsWith(BuiltInName::imageSize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_imageSize_0n;
+ }
+ break;
+ }
+ case 0x12700109u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0h1C;
+ }
+ break;
+ }
+ case 0x1270b3f8u:
+ {
+ if (name.beginsWith(BuiltInName::atomicAdd))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicAdd_0C0C;
+ }
+ break;
+ }
+ case 0x1270b766u:
+ {
+ if (name.beginsWith(BuiltInName::atomicXor))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicXor_0C0C;
+ }
+ break;
+ }
+ case 0x12712664u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0n2C;
+ }
+ break;
+ }
+ case 0x12715f47u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0j2C;
+ }
+ break;
+ }
+ case 0x12717c89u:
+ {
+ if (name.beginsWith(BuiltInName::atomicMin))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicMin_0C0C;
+ }
+ break;
+ }
+ case 0x127258f0u:
+ {
+ if (name.beginsWith(BuiltInName::atomicAdd))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicAdd_0D0D;
+ }
+ break;
+ }
+ case 0x12731984u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0m2C;
+ }
+ break;
+ }
+ case 0x12737ed6u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0q2C;
+ }
+ break;
+ }
+ case 0x12739c87u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0f1C;
+ }
+ break;
+ }
+ case 0x1273d1adu:
+ {
+ if (name.beginsWith(BuiltInName::atomicMax))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicMax_0D0D;
+ }
+ break;
+ }
+ case 0x1273e62au:
+ {
+ if (name.beginsWith(BuiltInName::atomicMin))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicMin_0D0D;
+ }
+ break;
+ }
+ case 0x12744c0du:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0o2C;
+ }
+ break;
+ }
+ case 0x127474cau:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0k2C;
+ }
+ break;
+ }
+ case 0x127478d9u:
+ {
+ if (name.beginsWith(BuiltInName::atomicAnd))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicAnd_0C0C;
+ }
+ break;
+ }
+ case 0x1274d54bu:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0p2C;
+ }
+ break;
+ }
+ case 0x127539b2u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0i2C;
+ }
+ break;
+ }
+ case 0x12755603u:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0g1C;
+ }
+ break;
+ }
+ case 0x127648cau:
+ {
+ if (name.beginsWith(BuiltInName::atomicAnd))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicAnd_0D0D;
+ }
+ break;
+ }
+ case 0x1276656cu:
+ {
+ if (name.beginsWith(BuiltInName::imageLoad))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_imageLoad_0l2C;
+ }
+ break;
+ }
+ case 0x12771119u:
+ {
+ if (name.beginsWith(BuiltInName::atomicXor))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicXor_0D0D;
+ }
+ break;
+ }
+ case 0x1277882au:
+ {
+ if (name.beginsWith(BuiltInName::atomicMax))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_atomicMax_0C0C;
+ }
+ break;
+ }
+ case 0x1283ba95u:
+ {
+ if (name.beginsWith(BuiltInName::uaddCarry))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_uaddCarry_0D0D0D;
+ }
+ break;
+ }
+ case 0x12840dfbu:
+ {
+ if (name == BuiltInName::uaddCarry_2D2D2D)
+ {
+ return &BuiltInFunction::kFunction_uaddCarry_2D2D2D;
+ }
+ break;
+ }
+ case 0x12842566u:
+ {
+ if (name == BuiltInName::uaddCarry_3D3D3D)
+ {
+ return &BuiltInFunction::kFunction_uaddCarry_3D3D3D;
+ }
+ break;
+ }
+ case 0x12843bc0u:
+ {
+ if (name.beginsWith(BuiltInName::uaddCarry))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_uaddCarry_1D1D1D;
+ }
+ break;
+ }
+ case 0x1488078cu:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0k2C3D;
+ }
+ break;
+ }
+ case 0x14880e11u:
+ {
+ if (name == BuiltInName::texelFetch_0V2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0V2C0C;
+ }
+ break;
+ }
+ case 0x1488ffa7u:
+ {
+ if (name == BuiltInName::usubBorrow_3D3D3D)
+ {
+ return &BuiltInFunction::kFunction_usubBorrow_3D3D3D;
+ }
+ break;
+ }
+ case 0x1489244fu:
+ {
+ if (name.beginsWith(BuiltInName::texelFetch))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetch_0b2C0C;
+ }
+ break;
+ }
+ case 0x14896692u:
+ {
+ if (name.beginsWith(BuiltInName::usubBorrow))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_usubBorrow_2D2D2D;
+ }
+ break;
+ }
+ case 0x14896e41u:
+ {
+ if (name == BuiltInName::texelFetch_0O1C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0O1C0C;
+ }
+ break;
+ }
+ case 0x148a0cecu:
+ {
+ if (name == BuiltInName::imageStore_0p2C3C)
+ {
+ return &BuiltInFunction::kFunction_imageStore_0p2C3C;
+ }
+ break;
+ }
+ case 0x148ab5f1u:
+ {
+ if (name == BuiltInName::usubBorrow_1D1D1D)
+ {
+ return &BuiltInFunction::kFunction_usubBorrow_1D1D1D;
+ }
+ break;
+ }
+ case 0x148bb1bdu:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0g1C3C;
+ }
+ break;
+ }
+ case 0x148c1e41u:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0q2C3D;
+ }
+ break;
+ }
+ case 0x148d86dcu:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0f1C3B;
+ }
+ break;
+ }
+ case 0x148dcfd5u:
+ {
+ if (name == BuiltInName::imageStore_0l2C3B)
+ {
+ return &BuiltInFunction::kFunction_imageStore_0l2C3B;
+ }
+ break;
+ }
+ case 0x148ddb10u:
+ {
+ if (name.beginsWith(BuiltInName::texelFetch))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetch_0a1C0C;
+ }
+ break;
+ }
+ case 0x148e37b8u:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0m2C3C;
+ }
+ break;
+ }
+ case 0x148e668au:
+ {
+ if (name == BuiltInName::imageStore_0j2C3C)
+ {
+ return &BuiltInFunction::kFunction_imageStore_0j2C3C;
+ }
+ break;
+ }
+ case 0x148e872bu:
+ {
+ if (name == BuiltInName::texelFetch_0P2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0P2C0C;
+ }
+ break;
+ }
+ case 0x148ed16fu:
+ {
+ if (name.beginsWith(BuiltInName::texelFetch))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetch_0U1C0C;
+ }
+ break;
+ }
+ case 0x148ed534u:
+ {
+ if (name == BuiltInName::imageStore_0n2C3D)
+ {
+ return &BuiltInFunction::kFunction_imageStore_0n2C3D;
+ }
+ break;
+ }
+ case 0x148f6fe1u:
+ {
+ if (name == BuiltInName::usubBorrow_0D0D0D)
+ {
+ return &BuiltInFunction::kFunction_usubBorrow_0D0D0D;
+ }
+ break;
+ }
+ case 0x148f7a82u:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0o2C3B;
+ }
+ break;
+ }
+ case 0x148fd5f1u:
+ {
+ if (name.beginsWith(BuiltInName::imageStore))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_imageStore_0i2C3B;
+ }
+ break;
+ }
+ case 0x148ffee8u:
+ {
+ if (name == BuiltInName::imageStore_0h1C3D)
+ {
+ return &BuiltInFunction::kFunction_imageStore_0h1C3D;
+ }
+ break;
+ }
+ case 0x167394d8u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSize_0U;
+ }
+ break;
+ }
+ case 0x1673a791u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSize_0V;
+ }
+ break;
+ }
+ case 0x1673b4b7u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSize_0P;
+ }
+ break;
+ }
+ case 0x1673f496u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSize_0O;
+ }
+ break;
+ }
+ case 0x16752ab6u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSize_0a;
+ }
+ break;
+ }
+ case 0x1675566fu:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSize_0b;
+ }
+ break;
+ }
+ case 0x187b7b7cu:
+ {
+ if (name.beginsWith(BuiltInName::packSnorm4x8))
+ {
+ ASSERT(name.length() == 15);
+ return &BuiltInFunction::kFunction_packSnorm4x8_3B;
+ }
+ break;
+ }
+ case 0x187c1f3fu:
+ {
+ if (name.beginsWith(BuiltInName::packUnorm4x8))
+ {
+ ASSERT(name.length() == 15);
+ return &BuiltInFunction::kFunction_packUnorm4x8_3B;
+ }
+ break;
+ }
+ case 0x18a851efu:
+ {
+ if (name == BuiltInName::imulExtended_2C2C2C2C)
+ {
+ return &BuiltInFunction::kFunction_imulExtended_2C2C2C2C;
+ }
+ break;
+ }
+ case 0x18a93bdcu:
+ {
+ if (name == BuiltInName::umulExtended_0D0D0D0D)
+ {
+ return &BuiltInFunction::kFunction_umulExtended_0D0D0D0D;
+ }
+ break;
+ }
+ case 0x18a94b63u:
+ {
+ if (name == BuiltInName::umulExtended_3D3D3D3D)
+ {
+ return &BuiltInFunction::kFunction_umulExtended_3D3D3D3D;
+ }
+ break;
+ }
+ case 0x18aa71ceu:
+ {
+ if (name == BuiltInName::umulExtended_2D2D2D2D)
+ {
+ return &BuiltInFunction::kFunction_umulExtended_2D2D2D2D;
+ }
+ break;
+ }
+ case 0x18ab4baeu:
+ {
+ if (name == BuiltInName::umulExtended_1D1D1D1D)
+ {
+ return &BuiltInFunction::kFunction_umulExtended_1D1D1D1D;
+ }
+ break;
+ }
+ case 0x18ac1df0u:
+ {
+ if (name == BuiltInName::imulExtended_3C3C3C3C)
+ {
+ return &BuiltInFunction::kFunction_imulExtended_3C3C3C3C;
+ }
+ break;
+ }
+ case 0x18ac377fu:
+ {
+ if (name == BuiltInName::imulExtended_0C0C0C0C)
+ {
+ return &BuiltInFunction::kFunction_imulExtended_0C0C0C0C;
+ }
+ break;
+ }
+ case 0x18ae7b8cu:
+ {
+ if (name == BuiltInName::imulExtended_1C1C1C1C)
+ {
+ return &BuiltInFunction::kFunction_imulExtended_1C1C1C1C;
+ }
+ break;
+ }
+ case 0x1a7538dfu:
+ {
+ if (name.beginsWith(BuiltInName::memoryBarrier))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_memoryBarrier_;
+ }
+ break;
+ }
+ case 0x1a805162u:
+ {
+ if (name.beginsWith(BuiltInName::atomicCounter))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_atomicCounter_0F;
+ }
+ break;
+ }
+ case 0x1a910beau:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0Y2B;
+ }
+ break;
+ }
+ case 0x1a91963cu:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0d2B;
+ }
+ break;
+ }
+ case 0x1a926b0du:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0c1B;
+ }
+ break;
+ }
+ case 0x1a92a168u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0W1B;
+ }
+ break;
+ }
+ case 0x1a92a1ceu:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0H1B;
+ }
+ break;
+ }
+ case 0x1a92c882u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0Q1B;
+ }
+ break;
+ }
+ case 0x1a9418e8u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0S2B;
+ }
+ break;
+ }
+ case 0x1a94543du:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0K2B;
+ }
+ break;
+ }
+ case 0x1a94d27du:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0e2B;
+ }
+ break;
+ }
+ case 0x1a94eb48u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0Z2B;
+ }
+ break;
+ }
+ case 0x1a95f707u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0T2B;
+ }
+ break;
+ }
+ case 0x1a979ae3u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureGather_0J2B;
+ }
+ break;
+ }
+ case 0x1aa039c7u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0e2B0B;
+ }
+ break;
+ }
+ case 0x1aa133bcu:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0Q1B0C;
+ }
+ break;
+ }
+ case 0x1aa17115u:
+ {
+ if (name == BuiltInName::textureGather_0Z2B0C)
+ {
+ return &BuiltInFunction::kFunction_textureGather_0Z2B0C;
+ }
+ break;
+ }
+ case 0x1aa182eeu:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0c1B0B;
+ }
+ break;
+ }
+ case 0x1aa220b0u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0W1B0C;
+ }
+ break;
+ }
+ case 0x1aa2aafeu:
+ {
+ if (name == BuiltInName::textureGather_0T2B0C)
+ {
+ return &BuiltInFunction::kFunction_textureGather_0T2B0C;
+ }
+ break;
+ }
+ case 0x1aa353f8u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0d2B0B;
+ }
+ break;
+ }
+ case 0x1aa3ef46u:
+ {
+ if (name == BuiltInName::textureGather_0S2B0C)
+ {
+ return &BuiltInFunction::kFunction_textureGather_0S2B0C;
+ }
+ break;
+ }
+ case 0x1aa4986bu:
+ {
+ if (name == BuiltInName::textureGather_0J2B0C)
+ {
+ return &BuiltInFunction::kFunction_textureGather_0J2B0C;
+ }
+ break;
+ }
+ case 0x1aa4c59du:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0H1B0C;
+ }
+ break;
+ }
+ case 0x1aa78b86u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0K2B0C;
+ }
+ break;
+ }
+ case 0x1aa7fa48u:
+ {
+ if (name.beginsWith(BuiltInName::textureGather))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureGather_0Y2B0C;
+ }
+ break;
+ }
+ case 0x1c894fb3u:
+ {
+ if (name.beginsWith(BuiltInName::unpackSnorm4x8))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_unpackSnorm4x8_0D;
+ }
+ break;
+ }
+ case 0x1c8be3bau:
+ {
+ if (name.beginsWith(BuiltInName::unpackUnorm4x8))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_unpackUnorm4x8_0D;
+ }
+ break;
+ }
+ case 0x1c9986beu:
+ {
+ if (name.beginsWith(BuiltInName::atomicExchange))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_atomicExchange_0D0D;
+ }
+ break;
+ }
+ case 0x1c9b5eecu:
+ {
+ if (name.beginsWith(BuiltInName::atomicExchange))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_atomicExchange_0C0C;
+ }
+ break;
+ }
+ case 0x1ca86085u:
+ {
+ if (name.beginsWith(BuiltInName::atomicCompSwap))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_atomicCompSwap_0C0C0C;
+ }
+ break;
+ }
+ case 0x1caa900cu:
+ {
+ if (name == BuiltInName::atomicCompSwap_0D0D0D)
+ {
+ return &BuiltInFunction::kFunction_atomicCompSwap_0D0D0D;
+ }
+ break;
+ }
+ case 0x1cb84b0cu:
+ {
+ if (name == BuiltInName::bitfieldInsert_3D3D0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_3D3D0C0C;
+ }
+ break;
+ }
+ case 0x1cb880bfu:
+ {
+ if (name == BuiltInName::bitfieldInsert_3C3C0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_3C3C0C0C;
+ }
+ break;
+ }
+ case 0x1cb90fd0u:
+ {
+ if (name == BuiltInName::bitfieldInsert_1C1C0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_1C1C0C0C;
+ }
+ break;
+ }
+ case 0x1cb9fb13u:
+ {
+ if (name == BuiltInName::bitfieldInsert_1D1D0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_1D1D0C0C;
+ }
+ break;
+ }
+ case 0x1cbb43f5u:
+ {
+ if (name == BuiltInName::bitfieldInsert_0D0D0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_0D0D0C0C;
+ }
+ break;
+ }
+ case 0x1cbb9db3u:
+ {
+ if (name == BuiltInName::bitfieldInsert_2D2D0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_2D2D0C0C;
+ }
+ break;
+ }
+ case 0x1cbdf898u:
+ {
+ if (name == BuiltInName::bitfieldInsert_0C0C0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_0C0C0C0C;
+ }
+ break;
+ }
+ case 0x1cbfaf73u:
+ {
+ if (name == BuiltInName::bitfieldInsert_2C2C0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldInsert_2C2C0C0C;
+ }
+ break;
+ }
+ case 0x1e907f62u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_3D;
+ }
+ break;
+ }
+ case 0x1e9088f7u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_3C;
+ }
+ break;
+ }
+ case 0x1e91c654u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_0C;
+ }
+ break;
+ }
+ case 0x1e91e675u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_0D;
+ }
+ break;
+ }
+ case 0x1e96ddc2u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_1D;
+ }
+ break;
+ }
+ case 0x1e970da3u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_1C;
+ }
+ break;
+ }
+ case 0x1e9744d7u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_2D;
+ }
+ break;
+ }
+ case 0x1e9797d2u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldReverse))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_bitfieldReverse_2C;
+ }
+ break;
+ }
+ case 0x1eb0c64fu:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldExtract))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_bitfieldExtract_2C0C0C;
+ }
+ break;
+ }
+ case 0x1eb0f9fau:
+ {
+ if (name == BuiltInName::bitfieldExtract_0D0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldExtract_0D0C0C;
+ }
+ break;
+ }
+ case 0x1eb12f29u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldExtract))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_bitfieldExtract_3D0C0C;
+ }
+ break;
+ }
+ case 0x1eb17d11u:
+ {
+ if (name == BuiltInName::bitfieldExtract_3C0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldExtract_3C0C0C;
+ }
+ break;
+ }
+ case 0x1eb17f7du:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldExtract))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_bitfieldExtract_0C0C0C;
+ }
+ break;
+ }
+ case 0x1eb19a50u:
+ {
+ if (name == BuiltInName::bitfieldExtract_1C0C0C)
+ {
+ return &BuiltInFunction::kFunction_bitfieldExtract_1C0C0C;
+ }
+ break;
+ }
+ case 0x1eb28b55u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldExtract))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_bitfieldExtract_2D0C0C;
+ }
+ break;
+ }
+ case 0x1eb5f0c8u:
+ {
+ if (name.beginsWith(BuiltInName::bitfieldExtract))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_bitfieldExtract_1D0C0C;
+ }
+ break;
+ }
+ case 0x249e7359u:
+ {
+ if (name.beginsWith(BuiltInName::memoryBarrierImage))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_memoryBarrierImage_;
+ }
+ break;
+ }
+ case 0x26a7e24bu:
+ {
+ if (name.beginsWith(BuiltInName::memoryBarrierBuffer))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_memoryBarrierBuffer_;
+ }
+ break;
+ }
+ case 0x26d00e91u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0W1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0W1B1C;
+ }
+ break;
+ }
+ case 0x26d0b451u:
+ {
+ if (name.beginsWith(BuiltInName::textureGatherOffset))
+ {
+ ASSERT(name.length() == 26);
+ return &BuiltInFunction::kFunction_textureGatherOffset_0Q1B1C;
+ }
+ break;
+ }
+ case 0x26d0db41u:
+ {
+ if (name.beginsWith(BuiltInName::textureGatherOffset))
+ {
+ ASSERT(name.length() == 26);
+ return &BuiltInFunction::kFunction_textureGatherOffset_0Z2B1C;
+ }
+ break;
+ }
+ case 0x26d1f440u:
+ {
+ if (name.beginsWith(BuiltInName::textureGatherOffset))
+ {
+ ASSERT(name.length() == 26);
+ return &BuiltInFunction::kFunction_textureGatherOffset_0K2B1C;
+ }
+ break;
+ }
+ case 0x26d2d875u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0T2B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0T2B1C;
+ }
+ break;
+ }
+ case 0x26d71952u:
+ {
+ if (name.beginsWith(BuiltInName::textureGatherOffset))
+ {
+ ASSERT(name.length() == 26);
+ return &BuiltInFunction::kFunction_textureGatherOffset_0H1B1C;
+ }
+ break;
+ }
+ case 0x26e1982cu:
+ {
+ if (name == BuiltInName::textureGatherOffset_0T2B1C0C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0T2B1C0C;
+ }
+ break;
+ }
+ case 0x26e459f8u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0K2B1C0C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0K2B1C0C;
+ }
+ break;
+ }
+ case 0x26e476d0u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0H1B1C0C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0H1B1C0C;
+ }
+ break;
+ }
+ case 0x26e47c82u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0Z2B1C0C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0Z2B1C0C;
+ }
+ break;
+ }
+ case 0x26e53ca1u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0e2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0e2B0B1C;
+ }
+ break;
+ }
+ case 0x26e567feu:
+ {
+ if (name == BuiltInName::textureGatherOffset_0Q1B1C0C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0Q1B1C0C;
+ }
+ break;
+ }
+ case 0x26e580eau:
+ {
+ if (name == BuiltInName::textureGatherOffset_0c1B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0c1B0B1C;
+ }
+ break;
+ }
+ case 0x26e737a0u:
+ {
+ if (name == BuiltInName::textureGatherOffset_0W1B1C0C)
+ {
+ return &BuiltInFunction::kFunction_textureGatherOffset_0W1B1C0C;
+ }
+ break;
+ }
+ case 0x2ccf8f34u:
+ {
+ if (name.beginsWith(BuiltInName::atomicCounterIncrement))
+ {
+ ASSERT(name.length() == 25);
+ return &BuiltInFunction::kFunction_atomicCounterIncrement_0F;
+ }
+ break;
+ }
+ case 0x2ccfbbbeu:
+ {
+ if (name.beginsWith(BuiltInName::atomicCounterDecrement))
+ {
+ ASSERT(name.length() == 25);
+ return &BuiltInFunction::kFunction_atomicCounterDecrement_0F;
+ }
+ break;
+ }
+ case 0x34ded18du:
+ {
+ if (name.beginsWith(BuiltInName::memoryBarrierAtomicCounter))
+ {
+ ASSERT(name.length() == 27);
+ return &BuiltInFunction::kFunction_memoryBarrierAtomicCounter_;
+ }
+ break;
+ }
+ case 0x7e2bef7au:
+ {
+ if (name == BuiltInName::gl_in)
+ {
+ // Only initialized if shaderType == GL_GEOMETRY_SHADER_EXT
+ return mVar_gl_in;
+ }
+ break;
+ }
+ case 0x7e8166efu:
+ {
+ if (name == BuiltInName::gl_MaxImageUnits)
+ {
+ return mVar_gl_MaxImageUnits;
+ }
+ break;
+ }
+ case 0x7ecf4a1bu:
+ {
+ if (name == BuiltInName::gl_MaxVertexImageUniforms)
+ {
+ return mVar_gl_MaxVertexImageUniforms;
+ }
+ break;
+ }
+ case 0x7ed27574u:
+ {
+ if (name == BuiltInName::gl_MaxVertexAtomicCounters)
+ {
+ return mVar_gl_MaxVertexAtomicCounters;
+ }
+ break;
+ }
+ case 0x7ed2bd5cu:
+ {
+ if (name == BuiltInName::gl_MaxComputeImageUniforms)
+ {
+ return mVar_gl_MaxComputeImageUniforms;
+ }
+ break;
+ }
+ case 0x7ed77973u:
+ {
+ if (name == BuiltInName::gl_MaxComputeWorkGroupSize)
+ {
+ return mVar_gl_MaxComputeWorkGroupSize;
+ }
+ break;
+ }
+ case 0x7ed9ae57u:
+ {
+ if (name == BuiltInName::gl_MaxCombinedImageUniforms)
+ {
+ return mVar_gl_MaxCombinedImageUniforms;
+ }
+ break;
+ }
+ case 0x7ed9f437u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryImageUniforms)
+ {
+ return mVar_gl_MaxGeometryImageUniforms;
+ }
+ break;
+ }
+ case 0x7edacc17u:
+ {
+ if (name == BuiltInName::gl_MaxAtomicCounterBindings)
+ {
+ return mVar_gl_MaxAtomicCounterBindings;
+ }
+ break;
+ }
+ case 0x7ede0db3u:
+ {
+ if (name == BuiltInName::gl_MaxComputeAtomicCounters)
+ {
+ return mVar_gl_MaxComputeAtomicCounters;
+ }
+ break;
+ }
+ case 0x7edeadeeu:
+ {
+ if (name == BuiltInName::gl_MaxComputeWorkGroupCount)
+ {
+ return mVar_gl_MaxComputeWorkGroupCount;
+ }
+ break;
+ }
+ case 0x7edf534au:
+ {
+ if (name == BuiltInName::gl_MaxFragmentImageUniforms)
+ {
+ return mVar_gl_MaxFragmentImageUniforms;
+ }
+ break;
+ }
+ case 0x7ee1b439u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryOutputVertices)
+ {
+ return mVar_gl_MaxGeometryOutputVertices;
+ }
+ break;
+ }
+ case 0x7ee23dcau:
+ {
+ if (name == BuiltInName::gl_MaxFragmentAtomicCounters)
+ {
+ return mVar_gl_MaxFragmentAtomicCounters;
+ }
+ break;
+ }
+ case 0x7ee400c5u:
+ {
+ if (name == BuiltInName::gl_MaxCombinedAtomicCounters)
+ {
+ return mVar_gl_MaxCombinedAtomicCounters;
+ }
+ break;
+ }
+ case 0x7ee6d3cfu:
+ {
+ if (name == BuiltInName::gl_MaxGeometryAtomicCounters)
+ {
+ return mVar_gl_MaxGeometryAtomicCounters;
+ }
+ break;
+ }
+ case 0x7eec3ae1u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryInputComponents)
+ {
+ return mVar_gl_MaxGeometryInputComponents;
+ }
+ break;
+ }
+ case 0x7eecdfadu:
+ {
+ if (name == BuiltInName::gl_MaxAtomicCounterBufferSize)
+ {
+ return mVar_gl_MaxAtomicCounterBufferSize;
+ }
+ break;
+ }
+ case 0x7ef00fc2u:
+ {
+ if (name == BuiltInName::gl_MaxComputeTextureImageUnits)
+ {
+ return mVar_gl_MaxComputeTextureImageUnits;
+ }
+ break;
+ }
+ case 0x7ef3740bu:
+ {
+ if (name == BuiltInName::gl_MaxComputeUniformComponents)
+ {
+ return mVar_gl_MaxComputeUniformComponents;
+ }
+ break;
+ }
+ case 0x7ef69ab4u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryOutputComponents)
+ {
+ return mVar_gl_MaxGeometryOutputComponents;
+ }
+ break;
+ }
+ case 0x7ef9b17du:
+ {
+ if (name == BuiltInName::gl_MaxGeometryTextureImageUnits)
+ {
+ return mVar_gl_MaxGeometryTextureImageUnits;
+ }
+ break;
+ }
+ case 0x7efe1865u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryUniformComponents)
+ {
+ return mVar_gl_MaxGeometryUniformComponents;
+ }
+ break;
+ }
+ case 0x7f008375u:
+ {
+ if (name == BuiltInName::gl_MaxVertexAtomicCounterBuffers)
+ {
+ return mVar_gl_MaxVertexAtomicCounterBuffers;
+ }
+ break;
+ }
+ case 0x7f0d626fu:
+ {
+ if (name == BuiltInName::gl_MaxComputeAtomicCounterBuffers)
+ {
+ return mVar_gl_MaxComputeAtomicCounterBuffers;
+ }
+ break;
+ }
+ case 0x7f11e359u:
+ {
+ if (name == BuiltInName::gl_MaxCombinedAtomicCounterBuffers)
+ {
+ return mVar_gl_MaxCombinedAtomicCounterBuffers;
+ }
+ break;
+ }
+ case 0x7f170f84u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryAtomicCounterBuffers)
+ {
+ return mVar_gl_MaxGeometryAtomicCounterBuffers;
+ }
+ break;
+ }
+ case 0x7f17bd18u:
+ {
+ if (name == BuiltInName::gl_MaxFragmentAtomicCounterBuffers)
+ {
+ return mVar_gl_MaxFragmentAtomicCounterBuffers;
+ }
+ break;
+ }
+ case 0x7f1c60f8u:
+ {
+ if (name == BuiltInName::gl_MaxCombinedShaderOutputResources)
+ {
+ return mVar_gl_MaxCombinedShaderOutputResources;
+ }
+ break;
+ }
+ case 0x7f1cd073u:
+ {
+ if (name == BuiltInName::gl_MaxGeometryTotalOutputComponents)
+ {
+ return mVar_gl_MaxGeometryTotalOutputComponents;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_COMPUTE_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x0e41a660u:
+ {
+ if (name.beginsWith(BuiltInName::barrier))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_barrier_;
+ }
+ break;
+ }
+ case 0x249ee97cu:
+ {
+ if (name.beginsWith(BuiltInName::groupMemoryBarrier))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_groupMemoryBarrier_;
+ }
+ break;
+ }
+ case 0x26a4d8e6u:
+ {
+ if (name.beginsWith(BuiltInName::memoryBarrierShared))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_memoryBarrierShared_;
+ }
+ break;
+ }
+ case 0x7e736b62u:
+ {
+ if (name == BuiltInName::gl_WorkGroupID)
+ {
+ return &BuiltInVariable::kVar_gl_WorkGroupID;
+ }
+ break;
+ }
+ case 0x7e808e8fu:
+ {
+ if (name == BuiltInName::gl_WorkGroupSize)
+ {
+ return &BuiltInVariable::kVar_gl_WorkGroupSize;
+ }
+ break;
+ }
+ case 0x7e82b146u:
+ {
+ if (name == BuiltInName::gl_NumWorkGroups)
+ {
+ return &BuiltInVariable::kVar_gl_NumWorkGroups;
+ }
+ break;
+ }
+ case 0x7ea251edu:
+ {
+ if (name == BuiltInName::gl_LocalInvocationID)
+ {
+ return &BuiltInVariable::kVar_gl_LocalInvocationID;
+ }
+ break;
+ }
+ case 0x7ead13a8u:
+ {
+ if (name == BuiltInName::gl_GlobalInvocationID)
+ {
+ return &BuiltInVariable::kVar_gl_GlobalInvocationID;
+ }
+ break;
+ }
+ case 0x7ebcd395u:
+ {
+ if (name == BuiltInName::gl_LocalInvocationIndex)
+ {
+ return &BuiltInVariable::kVar_gl_LocalInvocationIndex;
+ }
+ break;
+ }
+ }
+ }
+ if (mShaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ switch (nameHash)
+ {
+ case 0x145d55c9u:
+ {
+ if (name.beginsWith(BuiltInName::EmitVertex))
+ {
+ ASSERT(name.length() == 11);
+ return &BuiltInFunction::kFunction_EmitVertex_;
+ }
+ break;
+ }
+ case 0x186fcde2u:
+ {
+ if (name.beginsWith(BuiltInName::EndPrimitive))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_EndPrimitive_;
+ }
+ break;
+ }
+ case 0x7e400f84u:
+ {
+ if (name == BuiltInName::gl_Layer)
+ {
+ return &BuiltInVariable::kVar_gl_LayerGS;
+ }
+ break;
+ }
+ case 0x7e580bc5u:
+ {
+ if (name == BuiltInName::gl_Position)
+ {
+ return mVar_gl_PositionGS;
+ }
+ break;
+ }
+ case 0x7e67167au:
+ {
+ if (name == BuiltInName::gl_PerVertex)
+ {
+ return mVar_gl_PerVertex;
+ }
+ break;
+ }
+ case 0x7e742076u:
+ {
+ if (name == BuiltInName::gl_PrimitiveID)
+ {
+ return &BuiltInVariable::kVar_gl_PrimitiveIDGS;
+ }
+ break;
+ }
+ case 0x7e7fe684u:
+ {
+ if (name == BuiltInName::gl_InvocationID)
+ {
+ return &BuiltInVariable::kVar_gl_InvocationID;
+ }
+ break;
+ }
+ case 0x7e865240u:
+ {
+ if (name == BuiltInName::gl_PrimitiveIDIn)
+ {
+ return &BuiltInVariable::kVar_gl_PrimitiveIDIn;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_geometry_shader))
+ {
+ switch (nameHash)
+ {
+ case 0x7e400f84u:
+ {
+ if (name == BuiltInName::gl_Layer)
+ {
+ return &BuiltInVariable::kVar_gl_Layer;
+ }
+ break;
+ }
+ case 0x7e742076u:
+ {
+ if (name == BuiltInName::gl_PrimitiveID)
+ {
+ return &BuiltInVariable::kVar_gl_PrimitiveID;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (shaderVersion >= 300)
+ {
+ switch (nameHash)
+ {
+ case 0x06309dbcu:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_0C;
+ }
+ break;
+ }
+ case 0x0631d85fu:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_3C;
+ }
+ break;
+ }
+ case 0x06370c70u:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_2C;
+ }
+ break;
+ }
+ case 0x06378eb0u:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_1C;
+ }
+ break;
+ }
+ case 0x06408ba2u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_2D0D;
+ }
+ break;
+ }
+ case 0x0640f128u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_1C0C;
+ }
+ break;
+ }
+ case 0x06420bb0u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_0D0D;
+ }
+ break;
+ }
+ case 0x064236d1u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_2D2D;
+ }
+ break;
+ }
+ case 0x06425522u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_3C0C;
+ }
+ break;
+ }
+ case 0x06425db3u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_2C0C;
+ }
+ break;
+ }
+ case 0x06429550u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_2D2D;
+ }
+ break;
+ }
+ case 0x06429e9cu:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_2C0C;
+ }
+ break;
+ }
+ case 0x0642c869u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_3D3D;
+ }
+ break;
+ }
+ case 0x0642dbfeu:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_3C3C;
+ }
+ break;
+ }
+ case 0x064305b5u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_3D3D;
+ }
+ break;
+ }
+ case 0x06436c9au:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_1D0D;
+ }
+ break;
+ }
+ case 0x0643ebd5u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_3D0D;
+ }
+ break;
+ }
+ case 0x06441467u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_2C2C;
+ }
+ break;
+ }
+ case 0x0644176eu:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_1C1C;
+ }
+ break;
+ }
+ case 0x06443b94u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_2D0D;
+ }
+ break;
+ }
+ case 0x06448798u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_3C3C;
+ }
+ break;
+ }
+ case 0x0644a6dfu:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_1D1D;
+ }
+ break;
+ }
+ case 0x0644cd73u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_2C2C;
+ }
+ break;
+ }
+ case 0x06450593u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_1C0C;
+ }
+ break;
+ }
+ case 0x06452105u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_1D0D;
+ }
+ break;
+ }
+ case 0x06454045u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_0C0C;
+ }
+ break;
+ }
+ case 0x0645e25du:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_0C0C;
+ }
+ break;
+ }
+ case 0x06460349u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_1D1D;
+ }
+ break;
+ }
+ case 0x06472b16u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_3D0D;
+ }
+ break;
+ }
+ case 0x06473146u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_0D0D;
+ }
+ break;
+ }
+ case 0x06475b89u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_3C0C;
+ }
+ break;
+ }
+ case 0x0647bc75u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_1C1C;
+ }
+ break;
+ }
+ case 0x0654b2f8u:
+ {
+ if (name.beginsWith(BuiltInName::mix))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_mix_2B2B2E;
+ }
+ break;
+ }
+ case 0x0655a7e2u:
+ {
+ if (name == BuiltInName::mix_0B0B0E)
+ {
+ return &BuiltInFunction::kFunction_mix_0B0B0E;
+ }
+ break;
+ }
+ case 0x06567d08u:
+ {
+ if (name.beginsWith(BuiltInName::mix))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_mix_3B3B3E;
+ }
+ break;
+ }
+ case 0x0657f3adu:
+ {
+ if (name == BuiltInName::mix_1B1B1E)
+ {
+ return &BuiltInFunction::kFunction_mix_1B1B1E;
+ }
+ break;
+ }
+ case 0x0838025eu:
+ {
+ if (name.beginsWith(BuiltInName::tanh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_tanh_3B;
+ }
+ break;
+ }
+ case 0x0838944cu:
+ {
+ if (name.beginsWith(BuiltInName::tanh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_tanh_0B;
+ }
+ break;
+ }
+ case 0x08392747u:
+ {
+ if (name.beginsWith(BuiltInName::sinh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sinh_2B;
+ }
+ break;
+ }
+ case 0x08398f4au:
+ {
+ if (name.beginsWith(BuiltInName::sinh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sinh_1B;
+ }
+ break;
+ }
+ case 0x083991ddu:
+ {
+ if (name.beginsWith(BuiltInName::tanh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_tanh_1B;
+ }
+ break;
+ }
+ case 0x083aa373u:
+ {
+ if (name.beginsWith(BuiltInName::sinh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sinh_0B;
+ }
+ break;
+ }
+ case 0x083acb5eu:
+ {
+ if (name.beginsWith(BuiltInName::tanh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_tanh_2B;
+ }
+ break;
+ }
+ case 0x083acbf5u:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_1C;
+ }
+ break;
+ }
+ case 0x083b5c45u:
+ {
+ if (name.beginsWith(BuiltInName::cosh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_cosh_0B;
+ }
+ break;
+ }
+ case 0x083bd9f8u:
+ {
+ if (name.beginsWith(BuiltInName::sinh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sinh_3B;
+ }
+ break;
+ }
+ case 0x083c1656u:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_2C;
+ }
+ break;
+ }
+ case 0x083c57c4u:
+ {
+ if (name.beginsWith(BuiltInName::cosh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_cosh_1B;
+ }
+ break;
+ }
+ case 0x083d503bu:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_3C;
+ }
+ break;
+ }
+ case 0x083d8227u:
+ {
+ if (name.beginsWith(BuiltInName::cosh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_cosh_2B;
+ }
+ break;
+ }
+ case 0x083dd369u:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_0C;
+ }
+ break;
+ }
+ case 0x083ed2deu:
+ {
+ if (name.beginsWith(BuiltInName::cosh))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_cosh_3B;
+ }
+ break;
+ }
+ case 0x084807e9u:
+ {
+ if (name.beginsWith(BuiltInName::modf))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_modf_3B3B;
+ }
+ break;
+ }
+ case 0x084a908au:
+ {
+ if (name.beginsWith(BuiltInName::modf))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_modf_1B1B;
+ }
+ break;
+ }
+ case 0x084bf445u:
+ {
+ if (name.beginsWith(BuiltInName::modf))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_modf_0B0B;
+ }
+ break;
+ }
+ case 0x084fa835u:
+ {
+ if (name.beginsWith(BuiltInName::modf))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_modf_2B2B;
+ }
+ break;
+ }
+ case 0x0a400148u:
+ {
+ if (name.beginsWith(BuiltInName::asinh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_asinh_2B;
+ }
+ break;
+ }
+ case 0x0a406460u:
+ {
+ if (name.beginsWith(BuiltInName::isnan))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isnan_2B;
+ }
+ break;
+ }
+ case 0x0a407c52u:
+ {
+ if (name.beginsWith(BuiltInName::round))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_round_0B;
+ }
+ break;
+ }
+ case 0x0a412446u:
+ {
+ if (name.beginsWith(BuiltInName::trunc))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_trunc_0B;
+ }
+ break;
+ }
+ case 0x0a4125d1u:
+ {
+ if (name.beginsWith(BuiltInName::asinh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_asinh_3B;
+ }
+ break;
+ }
+ case 0x0a4189d9u:
+ {
+ if (name.beginsWith(BuiltInName::round))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_round_3B;
+ }
+ break;
+ }
+ case 0x0a41bc4bu:
+ {
+ if (name.beginsWith(BuiltInName::trunc))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_trunc_3B;
+ }
+ break;
+ }
+ case 0x0a4262ceu:
+ {
+ if (name.beginsWith(BuiltInName::isinf))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isinf_2B;
+ }
+ break;
+ }
+ case 0x0a42b872u:
+ {
+ if (name.beginsWith(BuiltInName::trunc))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_trunc_2B;
+ }
+ break;
+ }
+ case 0x0a430643u:
+ {
+ if (name.beginsWith(BuiltInName::atanh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_atanh_2B;
+ }
+ break;
+ }
+ case 0x0a43b397u:
+ {
+ if (name.beginsWith(BuiltInName::isinf))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isinf_3B;
+ }
+ break;
+ }
+ case 0x0a43edf9u:
+ {
+ if (name.beginsWith(BuiltInName::trunc))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_trunc_1B;
+ }
+ break;
+ }
+ case 0x0a4431a8u:
+ {
+ if (name.beginsWith(BuiltInName::atanh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_atanh_1B;
+ }
+ break;
+ }
+ case 0x0a443a26u:
+ {
+ if (name.beginsWith(BuiltInName::isinf))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isinf_0B;
+ }
+ break;
+ }
+ case 0x0a44ad91u:
+ {
+ if (name.beginsWith(BuiltInName::acosh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_acosh_1B;
+ }
+ break;
+ }
+ case 0x0a452617u:
+ {
+ if (name.beginsWith(BuiltInName::isinf))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isinf_1B;
+ }
+ break;
+ }
+ case 0x0a4561b0u:
+ {
+ if (name.beginsWith(BuiltInName::isnan))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isnan_3B;
+ }
+ break;
+ }
+ case 0x0a4582c9u:
+ {
+ if (name.beginsWith(BuiltInName::atanh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_atanh_0B;
+ }
+ break;
+ }
+ case 0x0a45fcfdu:
+ {
+ if (name.beginsWith(BuiltInName::atanh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_atanh_3B;
+ }
+ break;
+ }
+ case 0x0a461d10u:
+ {
+ if (name.beginsWith(BuiltInName::acosh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_acosh_0B;
+ }
+ break;
+ }
+ case 0x0a464ad3u:
+ {
+ if (name.beginsWith(BuiltInName::asinh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_asinh_0B;
+ }
+ break;
+ }
+ case 0x0a46778au:
+ {
+ if (name.beginsWith(BuiltInName::acosh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_acosh_3B;
+ }
+ break;
+ }
+ case 0x0a46ab3bu:
+ {
+ if (name.beginsWith(BuiltInName::isnan))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isnan_0B;
+ }
+ break;
+ }
+ case 0x0a46f2d2u:
+ {
+ if (name.beginsWith(BuiltInName::round))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_round_2B;
+ }
+ break;
+ }
+ case 0x0a4758c8u:
+ {
+ if (name.beginsWith(BuiltInName::round))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_round_1B;
+ }
+ break;
+ }
+ case 0x0a478c93u:
+ {
+ if (name.beginsWith(BuiltInName::acosh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_acosh_2B;
+ }
+ break;
+ }
+ case 0x0a47bb52u:
+ {
+ if (name.beginsWith(BuiltInName::asinh))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_asinh_1B;
+ }
+ break;
+ }
+ case 0x0a47fa7au:
+ {
+ if (name.beginsWith(BuiltInName::isnan))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_isnan_1B;
+ }
+ break;
+ }
+ case 0x0a524bc4u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_2D2D;
+ }
+ break;
+ }
+ case 0x0a5613e7u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_1D1D;
+ }
+ break;
+ }
+ case 0x0a56ba24u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_3D3D;
+ }
+ break;
+ }
+ case 0x0a601dd8u:
+ {
+ if (name == BuiltInName::clamp_2C2C2C)
+ {
+ return &BuiltInFunction::kFunction_clamp_2C2C2C;
+ }
+ break;
+ }
+ case 0x0a60570du:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_1D0D0D;
+ }
+ break;
+ }
+ case 0x0a60d0c5u:
+ {
+ if (name == BuiltInName::clamp_1C0C0C)
+ {
+ return &BuiltInFunction::kFunction_clamp_1C0C0C;
+ }
+ break;
+ }
+ case 0x0a621a2bu:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_0C0C0C;
+ }
+ break;
+ }
+ case 0x0a623042u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_2D0D0D;
+ }
+ break;
+ }
+ case 0x0a624f01u:
+ {
+ if (name == BuiltInName::clamp_3C0C0C)
+ {
+ return &BuiltInFunction::kFunction_clamp_3C0C0C;
+ }
+ break;
+ }
+ case 0x0a62ab50u:
+ {
+ if (name == BuiltInName::clamp_1C1C1C)
+ {
+ return &BuiltInFunction::kFunction_clamp_1C1C1C;
+ }
+ break;
+ }
+ case 0x0a631d0bu:
+ {
+ if (name == BuiltInName::clamp_1D1D1D)
+ {
+ return &BuiltInFunction::kFunction_clamp_1D1D1D;
+ }
+ break;
+ }
+ case 0x0a64f567u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_2D2D2D;
+ }
+ break;
+ }
+ case 0x0a656274u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_3C3C3C;
+ }
+ break;
+ }
+ case 0x0a65a625u:
+ {
+ if (name == BuiltInName::clamp_3D0D0D)
+ {
+ return &BuiltInFunction::kFunction_clamp_3D0D0D;
+ }
+ break;
+ }
+ case 0x0a660047u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_2C0C0C;
+ }
+ break;
+ }
+ case 0x0a660f60u:
+ {
+ if (name == BuiltInName::clamp_0D0D0D)
+ {
+ return &BuiltInFunction::kFunction_clamp_0D0D0D;
+ }
+ break;
+ }
+ case 0x0a674065u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_3D3D3D;
+ }
+ break;
+ }
+ case 0x0e503084u:
+ {
+ if (name.beginsWith(BuiltInName::inverse))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_inverse_5B;
+ }
+ break;
+ }
+ case 0x0e507cbdu:
+ {
+ if (name.beginsWith(BuiltInName::inverse))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_inverse_AB;
+ }
+ break;
+ }
+ case 0x0e50cc43u:
+ {
+ if (name.beginsWith(BuiltInName::inverse))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_inverse_FB;
+ }
+ break;
+ }
+ case 0x0e600d82u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0c2B;
+ }
+ break;
+ }
+ case 0x0e60445cu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0S2B;
+ }
+ break;
+ }
+ case 0x0e6044aeu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0e3B;
+ }
+ break;
+ }
+ case 0x0e60bb56u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0Q1B;
+ }
+ break;
+ }
+ case 0x0e61222eu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0K2B;
+ }
+ break;
+ }
+ case 0x0e61e49du:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0Z2B;
+ }
+ break;
+ }
+ case 0x0e625169u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0I2B;
+ }
+ break;
+ }
+ case 0x0e62790eu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0T2B;
+ }
+ break;
+ }
+ case 0x0e63b9efu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0M1B;
+ }
+ break;
+ }
+ case 0x0e6470f1u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0J2B;
+ }
+ break;
+ }
+ case 0x0e64854cu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0X2B;
+ }
+ break;
+ }
+ case 0x0e64ec86u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0W1B;
+ }
+ break;
+ }
+ case 0x0e65ea73u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0H1B;
+ }
+ break;
+ }
+ case 0x0e661665u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0L1B;
+ }
+ break;
+ }
+ case 0x0e663be3u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0N1B;
+ }
+ break;
+ }
+ case 0x0e67665bu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0d3B;
+ }
+ break;
+ }
+ case 0x0e67a979u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0R2B;
+ }
+ break;
+ }
+ case 0x0e67dce5u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_texture_0Y2B;
+ }
+ break;
+ }
+ case 0x106843efu:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_3D3D;
+ }
+ break;
+ }
+ case 0x10697de8u:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_2D2D;
+ }
+ break;
+ }
+ case 0x106ad530u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_1D1D;
+ }
+ break;
+ }
+ case 0x106d7bd6u:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_1D1D;
+ }
+ break;
+ }
+ case 0x106e2903u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_3D3D;
+ }
+ break;
+ }
+ case 0x106e7a45u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_2D2D;
+ }
+ break;
+ }
+ case 0x12601c9du:
+ {
+ if (name.beginsWith(BuiltInName::roundEven))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_roundEven_3B;
+ }
+ break;
+ }
+ case 0x12602fd7u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_AB;
+ }
+ break;
+ }
+ case 0x12614fd4u:
+ {
+ if (name.beginsWith(BuiltInName::roundEven))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_roundEven_2B;
+ }
+ break;
+ }
+ case 0x1264f5e4u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_EB;
+ }
+ break;
+ }
+ case 0x12650771u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_6B;
+ }
+ break;
+ }
+ case 0x12655b22u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_BB;
+ }
+ break;
+ }
+ case 0x12658f24u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_9B;
+ }
+ break;
+ }
+ case 0x1265cf4cu:
+ {
+ if (name.beginsWith(BuiltInName::roundEven))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_roundEven_1B;
+ }
+ break;
+ }
+ case 0x12661b07u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_FB;
+ }
+ break;
+ }
+ case 0x12665430u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_7B;
+ }
+ break;
+ }
+ case 0x1266c2deu:
+ {
+ if (name.beginsWith(BuiltInName::roundEven))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_roundEven_0B;
+ }
+ break;
+ }
+ case 0x1267db60u:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_5B;
+ }
+ break;
+ }
+ case 0x1267de6cu:
+ {
+ if (name.beginsWith(BuiltInName::transpose))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_transpose_DB;
+ }
+ break;
+ }
+ case 0x1273f9dbu:
+ {
+ if (name.beginsWith(BuiltInName::yuv_2_rgb))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_yuv_2_rgb_2B0G;
+ }
+ break;
+ }
+ case 0x127589a7u:
+ {
+ if (name.beginsWith(BuiltInName::rgb_2_yuv))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_rgb_2_yuv_2B0G;
+ }
+ break;
+ }
+ case 0x14882ba7u:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0X2B0B;
+ }
+ break;
+ }
+ case 0x14885983u:
+ {
+ if (name.beginsWith(BuiltInName::texelFetch))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetch_0R2C0C;
+ }
+ break;
+ }
+ case 0x14885e67u:
+ {
+ if (name == BuiltInName::texelFetch_0Z2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0Z2C0C;
+ }
+ break;
+ }
+ case 0x1488a5bfu:
+ {
+ if (name == BuiltInName::textureLod_0W1B0B)
+ {
+ return &BuiltInFunction::kFunction_textureLod_0W1B0B;
+ }
+ break;
+ }
+ case 0x14896e41u:
+ {
+ if (name == BuiltInName::texelFetchExt_0O1C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchExt_0O1C0C;
+ }
+ break;
+ }
+ case 0x1489e510u:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0T2B0B;
+ }
+ break;
+ }
+ case 0x148a14a7u:
+ {
+ if (name.beginsWith(BuiltInName::texelFetch))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetch_0M1C0C;
+ }
+ break;
+ }
+ case 0x148a66beu:
+ {
+ if (name == BuiltInName::textureLod_0S2B0B)
+ {
+ return &BuiltInFunction::kFunction_textureLod_0S2B0B;
+ }
+ break;
+ }
+ case 0x148a95e7u:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0c2B0B;
+ }
+ break;
+ }
+ case 0x148b00dbu:
+ {
+ if (name == BuiltInName::textureLod_0J2B0B)
+ {
+ return &BuiltInFunction::kFunction_textureLod_0J2B0B;
+ }
+ break;
+ }
+ case 0x148b33b6u:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0H1B0B;
+ }
+ break;
+ }
+ case 0x148bab65u:
+ {
+ if (name == BuiltInName::texelFetch_0I2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0I2C0C;
+ }
+ break;
+ }
+ case 0x148cccafu:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0R2B0B;
+ }
+ break;
+ }
+ case 0x148d0a7bu:
+ {
+ if (name == BuiltInName::texelFetch_0K2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0K2C0C;
+ }
+ break;
+ }
+ case 0x148d335cu:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0I2B0B;
+ }
+ break;
+ }
+ case 0x148ddb10u:
+ {
+ if (name.beginsWith(BuiltInName::texelFetchExt))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetchExt_0a1C0C;
+ }
+ break;
+ }
+ case 0x148e100eu:
+ {
+ if (name == BuiltInName::texelFetch_0X2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0X2C0C;
+ }
+ break;
+ }
+ case 0x148e44d3u:
+ {
+ if (name == BuiltInName::textureLod_0Y2B0B)
+ {
+ return &BuiltInFunction::kFunction_textureLod_0Y2B0B;
+ }
+ break;
+ }
+ case 0x148e5d86u:
+ {
+ if (name == BuiltInName::texelFetch_0Q1C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0Q1C0C;
+ }
+ break;
+ }
+ case 0x148e6d96u:
+ {
+ if (name.beginsWith(BuiltInName::texelFetch))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetch_0W1C0C;
+ }
+ break;
+ }
+ case 0x148ed16fu:
+ {
+ if (name.beginsWith(BuiltInName::texelFetchExt))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_texelFetchExt_0U1C0C;
+ }
+ break;
+ }
+ case 0x148ed87fu:
+ {
+ if (name.beginsWith(BuiltInName::textureLod))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_textureLod_0K2B0B;
+ }
+ break;
+ }
+ case 0x148eff58u:
+ {
+ if (name == BuiltInName::texelFetch_0L1C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0L1C0C;
+ }
+ break;
+ }
+ case 0x148fa8bbu:
+ {
+ if (name == BuiltInName::textureLod_0Q1B0B)
+ {
+ return &BuiltInFunction::kFunction_textureLod_0Q1B0B;
+ }
+ break;
+ }
+ case 0x148fb13cu:
+ {
+ if (name == BuiltInName::texelFetch_0T2C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0T2C0C;
+ }
+ break;
+ }
+ case 0x148fd5b6u:
+ {
+ if (name == BuiltInName::texelFetch_0H1C0C)
+ {
+ return &BuiltInFunction::kFunction_texelFetch_0H1C0C;
+ }
+ break;
+ }
+ case 0x148fe911u:
+ {
+ if (name == BuiltInName::textureLod_0Z2B0B)
+ {
+ return &BuiltInFunction::kFunction_textureLod_0Z2B0B;
+ }
+ break;
+ }
+ case 0x167394d8u:
+ {
+ if (name.beginsWith(BuiltInName::textureSizeExt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSizeExt_0U;
+ }
+ break;
+ }
+ case 0x1673f496u:
+ {
+ if (name.beginsWith(BuiltInName::textureSizeExt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSizeExt_0O;
+ }
+ break;
+ }
+ case 0x1674ed12u:
+ {
+ if (name.beginsWith(BuiltInName::determinant))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_determinant_FB;
+ }
+ break;
+ }
+ case 0x16752ab6u:
+ {
+ if (name.beginsWith(BuiltInName::textureSizeExt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_textureSizeExt_0a;
+ }
+ break;
+ }
+ case 0x1676ad75u:
+ {
+ if (name.beginsWith(BuiltInName::determinant))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_determinant_5B;
+ }
+ break;
+ }
+ case 0x167719ccu:
+ {
+ if (name.beginsWith(BuiltInName::determinant))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_determinant_AB;
+ }
+ break;
+ }
+ case 0x16803d05u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0I0C;
+ }
+ break;
+ }
+ case 0x168046b0u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0M0C;
+ }
+ break;
+ }
+ case 0x168093aau:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0T0C;
+ }
+ break;
+ }
+ case 0x168115fbu:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0e0C;
+ }
+ break;
+ }
+ case 0x16812c54u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_3D3D;
+ }
+ break;
+ }
+ case 0x16812eeeu:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0W3B;
+ }
+ break;
+ }
+ case 0x168174f7u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_1D1D;
+ }
+ break;
+ }
+ case 0x168178c7u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0H2B;
+ }
+ break;
+ }
+ case 0x1681d6b4u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_2D2D;
+ }
+ break;
+ }
+ case 0x1681f153u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0J0C;
+ }
+ break;
+ }
+ case 0x168245a4u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0S0C;
+ }
+ break;
+ }
+ case 0x1682b6c4u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0X3B;
+ }
+ break;
+ }
+ case 0x1682d0c8u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0M2B;
+ }
+ break;
+ }
+ case 0x1682d660u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0Y0C;
+ }
+ break;
+ }
+ case 0x16838d15u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0L2B;
+ }
+ break;
+ }
+ case 0x1683ecb1u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0M3B;
+ }
+ break;
+ }
+ case 0x16840064u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0H3B;
+ }
+ break;
+ }
+ case 0x168434eeu:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0H0C;
+ }
+ break;
+ }
+ case 0x16845c90u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0L0C;
+ }
+ break;
+ }
+ case 0x16846c6cu:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0W0C;
+ }
+ break;
+ }
+ case 0x16849618u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0Z0C;
+ }
+ break;
+ }
+ case 0x1684f1b3u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0d0C;
+ }
+ break;
+ }
+ case 0x1685011eu:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0Q2B;
+ }
+ break;
+ }
+ case 0x1685b785u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0N3B;
+ }
+ break;
+ }
+ case 0x1685ca01u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0I3B;
+ }
+ break;
+ }
+ case 0x16860d28u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0Q3B;
+ }
+ break;
+ }
+ case 0x16861104u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0K0C;
+ }
+ break;
+ }
+ case 0x16863c73u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0R0C;
+ }
+ break;
+ }
+ case 0x16865716u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0L3B;
+ }
+ break;
+ }
+ case 0x16869d00u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0Q0C;
+ }
+ break;
+ }
+ case 0x1686a82au:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0X0C;
+ }
+ break;
+ }
+ case 0x1686aa87u:
+ {
+ if (name.beginsWith(BuiltInName::textureSize))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureSize_0c0C;
+ }
+ break;
+ }
+ case 0x1686cb94u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0N2B;
+ }
+ break;
+ }
+ case 0x16875a59u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0c3B;
+ }
+ break;
+ }
+ case 0x1687c54du:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0R3B;
+ }
+ break;
+ }
+ case 0x1687d107u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureProj_0W2B;
+ }
+ break;
+ }
+ case 0x16a00e04u:
+ {
+ if (name == BuiltInName::textureGrad_0I2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0I2B2B2B;
+ }
+ break;
+ }
+ case 0x16a04ad9u:
+ {
+ if (name == BuiltInName::textureGrad_0X2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0X2B2B2B;
+ }
+ break;
+ }
+ case 0x16a1478fu:
+ {
+ if (name == BuiltInName::textureGrad_0e3B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0e3B1B1B;
+ }
+ break;
+ }
+ case 0x16a19c8du:
+ {
+ if (name == BuiltInName::textureGrad_0H1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0H1B1B1B;
+ }
+ break;
+ }
+ case 0x16a1ec87u:
+ {
+ if (name == BuiltInName::textureGrad_0J2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0J2B2B2B;
+ }
+ break;
+ }
+ case 0x16a2ff3du:
+ {
+ if (name == BuiltInName::textureGrad_0Q1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0Q1B1B1B;
+ }
+ break;
+ }
+ case 0x16a34692u:
+ {
+ if (name == BuiltInName::textureGrad_0R2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0R2B2B2B;
+ }
+ break;
+ }
+ case 0x16a3a842u:
+ {
+ if (name == BuiltInName::textureGrad_0c2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0c2B1B1B;
+ }
+ break;
+ }
+ case 0x16a3b8f6u:
+ {
+ if (name == BuiltInName::textureGrad_0Y2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0Y2B2B2B;
+ }
+ break;
+ }
+ case 0x16a4a66cu:
+ {
+ if (name == BuiltInName::textureGrad_0W1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0W1B1B1B;
+ }
+ break;
+ }
+ case 0x16a4e27cu:
+ {
+ if (name == BuiltInName::textureGrad_0d3B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0d3B2B2B;
+ }
+ break;
+ }
+ case 0x16a66883u:
+ {
+ if (name == BuiltInName::textureGrad_0T2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0T2B1B1B;
+ }
+ break;
+ }
+ case 0x16a68a81u:
+ {
+ if (name == BuiltInName::textureGrad_0S2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0S2B2B2B;
+ }
+ break;
+ }
+ case 0x16a6a742u:
+ {
+ if (name == BuiltInName::textureGrad_0Z2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0Z2B1B1B;
+ }
+ break;
+ }
+ case 0x16a71104u:
+ {
+ if (name == BuiltInName::textureGrad_0K2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureGrad_0K2B1B1B;
+ }
+ break;
+ }
+ case 0x187df788u:
+ {
+ if (name.beginsWith(BuiltInName::packHalf2x16))
+ {
+ ASSERT(name.length() == 15);
+ return &BuiltInFunction::kFunction_packHalf2x16_1B;
+ }
+ break;
+ }
+ case 0x18887331u:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_2B3B;
+ }
+ break;
+ }
+ case 0x188880cbu:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_1B1B;
+ }
+ break;
+ }
+ case 0x1888c44du:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_3B2B;
+ }
+ break;
+ }
+ case 0x188916c3u:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_1B2B;
+ }
+ break;
+ }
+ case 0x188a12cau:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_1B3B;
+ }
+ break;
+ }
+ case 0x188db87au:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_2B2B;
+ }
+ break;
+ }
+ case 0x188e0232u:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_3B3B;
+ }
+ break;
+ }
+ case 0x188e2270u:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_2B1B;
+ }
+ break;
+ }
+ case 0x188f8feeu:
+ {
+ if (name.beginsWith(BuiltInName::outerProduct))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_outerProduct_3B1B;
+ }
+ break;
+ }
+ case 0x1a84fa77u:
+ {
+ if (name.beginsWith(BuiltInName::packSnorm2x16))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_packSnorm2x16_1B;
+ }
+ break;
+ }
+ case 0x1a873678u:
+ {
+ if (name.beginsWith(BuiltInName::packUnorm2x16))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_packUnorm2x16_1B;
+ }
+ break;
+ }
+ case 0x1a92589du:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_2D2D;
+ }
+ break;
+ }
+ case 0x1a95efdcu:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_1D1D;
+ }
+ break;
+ }
+ case 0x1a96ec62u:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_3D3D;
+ }
+ break;
+ }
+ case 0x1aa01270u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0Q1B1C;
+ }
+ break;
+ }
+ case 0x1aa05156u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0c2B1C;
+ }
+ break;
+ }
+ case 0x1aa11785u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0H1B1C;
+ }
+ break;
+ }
+ case 0x1aa26095u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0T2B1C;
+ }
+ break;
+ }
+ case 0x1aa31637u:
+ {
+ if (name == BuiltInName::textureOffset_0X2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0X2B2C;
+ }
+ break;
+ }
+ case 0x1aa385c2u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0Z2B1C;
+ }
+ break;
+ }
+ case 0x1aa41f4au:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0K2B1C;
+ }
+ break;
+ }
+ case 0x1aa541b7u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0W1B1C;
+ }
+ break;
+ }
+ case 0x1aa64995u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0I2B2C;
+ }
+ break;
+ }
+ case 0x1aa7a781u:
+ {
+ if (name.beginsWith(BuiltInName::textureOffset))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_textureOffset_0R2B2C;
+ }
+ break;
+ }
+ case 0x1c887424u:
+ {
+ if (name.beginsWith(BuiltInName::intBitsToFloat))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_intBitsToFloat_2C;
+ }
+ break;
+ }
+ case 0x1c887f5eu:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToInt))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_floatBitsToInt_2B;
+ }
+ break;
+ }
+ case 0x1c88f18cu:
+ {
+ if (name.beginsWith(BuiltInName::intBitsToFloat))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_intBitsToFloat_1C;
+ }
+ break;
+ }
+ case 0x1c89b11cu:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToInt))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_floatBitsToInt_1B;
+ }
+ break;
+ }
+ case 0x1c89e261u:
+ {
+ if (name.beginsWith(BuiltInName::intBitsToFloat))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_intBitsToFloat_0C;
+ }
+ break;
+ }
+ case 0x1c8ae0a5u:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToInt))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_floatBitsToInt_0B;
+ }
+ break;
+ }
+ case 0x1c8b20dau:
+ {
+ if (name.beginsWith(BuiltInName::intBitsToFloat))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_intBitsToFloat_3C;
+ }
+ break;
+ }
+ case 0x1c8dd4e6u:
+ {
+ if (name.beginsWith(BuiltInName::unpackHalf2x16))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_unpackHalf2x16_0D;
+ }
+ break;
+ }
+ case 0x1c8f60afu:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToInt))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_floatBitsToInt_3B;
+ }
+ break;
+ }
+ case 0x1c9876e4u:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_9B9B;
+ }
+ break;
+ }
+ case 0x1c99affcu:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_7B7B;
+ }
+ break;
+ }
+ case 0x1c9c8697u:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_6B6B;
+ }
+ break;
+ }
+ case 0x1c9ccd5au:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_BBBB;
+ }
+ break;
+ }
+ case 0x1c9ea241u:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_DBDB;
+ }
+ break;
+ }
+ case 0x1c9fa571u:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_EBEB;
+ }
+ break;
+ }
+ case 0x1ca81af6u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureProjLod_0c3B0B;
+ }
+ break;
+ }
+ case 0x1ca85d55u:
+ {
+ if (name == BuiltInName::textureProjLod_0Q3B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjLod_0Q3B0B;
+ }
+ break;
+ }
+ case 0x1ca8c89au:
+ {
+ if (name == BuiltInName::textureProjLod_0H3B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjLod_0H3B0B;
+ }
+ break;
+ }
+ case 0x1ca9ff27u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureProjLod_0W2B0B;
+ }
+ break;
+ }
+ case 0x1caa108bu:
+ {
+ if (name.beginsWith(BuiltInName::textureProjLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureProjLod_0H2B0B;
+ }
+ break;
+ }
+ case 0x1caa957cu:
+ {
+ if (name == BuiltInName::textureProjLod_0Q2B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjLod_0Q2B0B;
+ }
+ break;
+ }
+ case 0x1cab3a35u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureProjLod_0W3B0B;
+ }
+ break;
+ }
+ case 0x1cadb5feu:
+ {
+ if (name.beginsWith(BuiltInName::textureProjLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureProjLod_0X3B0B;
+ }
+ break;
+ }
+ case 0x1cae6ef8u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureProjLod_0R3B0B;
+ }
+ break;
+ }
+ case 0x1caf96afu:
+ {
+ if (name == BuiltInName::textureProjLod_0I3B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjLod_0I3B0B;
+ }
+ break;
+ }
+ case 0x1e903284u:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToUint))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_floatBitsToUint_0B;
+ }
+ break;
+ }
+ case 0x1e92e353u:
+ {
+ if (name.beginsWith(BuiltInName::uintBitsToFloat))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_uintBitsToFloat_3D;
+ }
+ break;
+ }
+ case 0x1e93c13fu:
+ {
+ if (name.beginsWith(BuiltInName::uintBitsToFloat))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_uintBitsToFloat_0D;
+ }
+ break;
+ }
+ case 0x1e95201fu:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToUint))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_floatBitsToUint_1B;
+ }
+ break;
+ }
+ case 0x1e95511bu:
+ {
+ if (name.beginsWith(BuiltInName::unpackSnorm2x16))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_unpackSnorm2x16_0D;
+ }
+ break;
+ }
+ case 0x1e95582au:
+ {
+ if (name.beginsWith(BuiltInName::uintBitsToFloat))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_uintBitsToFloat_1D;
+ }
+ break;
+ }
+ case 0x1e95b0a7u:
+ {
+ if (name.beginsWith(BuiltInName::uintBitsToFloat))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_uintBitsToFloat_2D;
+ }
+ break;
+ }
+ case 0x1e966adcu:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToUint))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_floatBitsToUint_2B;
+ }
+ break;
+ }
+ case 0x1e9718ffu:
+ {
+ if (name.beginsWith(BuiltInName::unpackUnorm2x16))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_unpackUnorm2x16_0D;
+ }
+ break;
+ }
+ case 0x1e97a505u:
+ {
+ if (name.beginsWith(BuiltInName::floatBitsToUint))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_floatBitsToUint_3B;
+ }
+ break;
+ }
+ case 0x1ec1a98bu:
+ {
+ if (name == BuiltInName::textureProjGrad_0Q2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0Q2B1B1B;
+ }
+ break;
+ }
+ case 0x1ec2304bu:
+ {
+ if (name == BuiltInName::textureProjGrad_0X3B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0X3B2B2B;
+ }
+ break;
+ }
+ case 0x1ec25826u:
+ {
+ if (name == BuiltInName::textureProjGrad_0W2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0W2B1B1B;
+ }
+ break;
+ }
+ case 0x1ec323fdu:
+ {
+ if (name == BuiltInName::textureProjGrad_0H3B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0H3B1B1B;
+ }
+ break;
+ }
+ case 0x1ec3ee61u:
+ {
+ if (name == BuiltInName::textureProjGrad_0I3B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0I3B2B2B;
+ }
+ break;
+ }
+ case 0x1ec578cfu:
+ {
+ if (name == BuiltInName::textureProjGrad_0R3B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0R3B2B2B;
+ }
+ break;
+ }
+ case 0x1ec5ab9du:
+ {
+ if (name == BuiltInName::textureProjGrad_0H2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0H2B1B1B;
+ }
+ break;
+ }
+ case 0x1ec5fc9fu:
+ {
+ if (name == BuiltInName::textureProjGrad_0Q3B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0Q3B1B1B;
+ }
+ break;
+ }
+ case 0x1ec67b05u:
+ {
+ if (name == BuiltInName::textureProjGrad_0W3B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0W3B1B1B;
+ }
+ break;
+ }
+ case 0x1ec719d1u:
+ {
+ if (name == BuiltInName::textureProjGrad_0c3B1B1B)
+ {
+ return &BuiltInFunction::kFunction_textureProjGrad_0c3B1B1B;
+ }
+ break;
+ }
+ case 0x20a92dc6u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_2D2D;
+ }
+ break;
+ }
+ case 0x20ae96edu:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_3D3D;
+ }
+ break;
+ }
+ case 0x20aedbacu:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_1D1D;
+ }
+ break;
+ }
+ case 0x20c8fa96u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0I2C0C2C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0I2C0C2C;
+ }
+ break;
+ }
+ case 0x20c9733bu:
+ {
+ if (name == BuiltInName::textureLodOffset_0c2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0c2B0B1C;
+ }
+ break;
+ }
+ case 0x20c9a178u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0X2C0C2C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0X2C0C2C;
+ }
+ break;
+ }
+ case 0x20ca4914u:
+ {
+ if (name == BuiltInName::textureLodOffset_0Z2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0Z2B0B1C;
+ }
+ break;
+ }
+ case 0x20cac068u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0K2C0C1C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0K2C0C1C;
+ }
+ break;
+ }
+ case 0x20cb3102u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0H1C0C1C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0H1C0C1C;
+ }
+ break;
+ }
+ case 0x20cb952du:
+ {
+ if (name == BuiltInName::texelFetchOffset_0Z2C0C1C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0Z2C0C1C;
+ }
+ break;
+ }
+ case 0x20cbf8d9u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0W1C0C1C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0W1C0C1C;
+ }
+ break;
+ }
+ case 0x20cbfefau:
+ {
+ if (name == BuiltInName::texelFetchOffset_0R2C0C2C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0R2C0C2C;
+ }
+ break;
+ }
+ case 0x20cc1a52u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0Q1C0C1C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0Q1C0C1C;
+ }
+ break;
+ }
+ case 0x20cc9477u:
+ {
+ if (name == BuiltInName::textureLodOffset_0H1B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0H1B0B1C;
+ }
+ break;
+ }
+ case 0x20ccf3edu:
+ {
+ if (name == BuiltInName::textureLodOffset_0Q1B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0Q1B0B1C;
+ }
+ break;
+ }
+ case 0x20cd0de3u:
+ {
+ if (name == BuiltInName::textureLodOffset_0K2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0K2B0B1C;
+ }
+ break;
+ }
+ case 0x20cd8d8du:
+ {
+ if (name == BuiltInName::textureLodOffset_0T2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0T2B0B1C;
+ }
+ break;
+ }
+ case 0x20cdc61au:
+ {
+ if (name == BuiltInName::textureLodOffset_0W1B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0W1B0B1C;
+ }
+ break;
+ }
+ case 0x20cde370u:
+ {
+ if (name == BuiltInName::textureLodOffset_0X2B0B2C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0X2B0B2C;
+ }
+ break;
+ }
+ case 0x20cde748u:
+ {
+ if (name == BuiltInName::textureLodOffset_0I2B0B2C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0I2B0B2C;
+ }
+ break;
+ }
+ case 0x20ceb3dau:
+ {
+ if (name == BuiltInName::textureLodOffset_0R2B0B2C)
+ {
+ return &BuiltInFunction::kFunction_textureLodOffset_0R2B0B2C;
+ }
+ break;
+ }
+ case 0x20cfe609u:
+ {
+ if (name == BuiltInName::texelFetchOffset_0T2C0C1C)
+ {
+ return &BuiltInFunction::kFunction_texelFetchOffset_0T2C0C1C;
+ }
+ break;
+ }
+ case 0x22c03489u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjOffset))
+ {
+ ASSERT(name.length() == 24);
+ return &BuiltInFunction::kFunction_textureProjOffset_0W2B1C;
+ }
+ break;
+ }
+ case 0x22c0a359u:
+ {
+ if (name == BuiltInName::textureProjOffset_0H2B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0H2B1C;
+ }
+ break;
+ }
+ case 0x22c19992u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjOffset))
+ {
+ ASSERT(name.length() == 24);
+ return &BuiltInFunction::kFunction_textureProjOffset_0c3B1C;
+ }
+ break;
+ }
+ case 0x22c246a2u:
+ {
+ if (name == BuiltInName::textureProjOffset_0Q3B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0Q3B1C;
+ }
+ break;
+ }
+ case 0x22c29005u:
+ {
+ if (name == BuiltInName::textureProjOffset_0Q2B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0Q2B1C;
+ }
+ break;
+ }
+ case 0x22c2da46u:
+ {
+ if (name == BuiltInName::textureProjOffset_0H3B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0H3B1C;
+ }
+ break;
+ }
+ case 0x22c3e359u:
+ {
+ if (name == BuiltInName::textureProjOffset_0W3B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0W3B1C;
+ }
+ break;
+ }
+ case 0x22c43880u:
+ {
+ if (name.beginsWith(BuiltInName::textureProjOffset))
+ {
+ ASSERT(name.length() == 24);
+ return &BuiltInFunction::kFunction_textureProjOffset_0R3B2C;
+ }
+ break;
+ }
+ case 0x22c458dcu:
+ {
+ if (name.beginsWith(BuiltInName::textureProjOffset))
+ {
+ ASSERT(name.length() == 24);
+ return &BuiltInFunction::kFunction_textureProjOffset_0I3B2C;
+ }
+ break;
+ }
+ case 0x22c47909u:
+ {
+ if (name == BuiltInName::textureProjOffset_0X3B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0X3B2C;
+ }
+ break;
+ }
+ case 0x22e0fe8cu:
+ {
+ if (name == BuiltInName::textureGradOffset_0W1B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0W1B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e165b8u:
+ {
+ if (name == BuiltInName::textureGradOffset_0K2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0K2B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e28d80u:
+ {
+ if (name == BuiltInName::textureGradOffset_0T2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0T2B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e3ab1cu:
+ {
+ if (name == BuiltInName::textureGradOffset_0e3B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0e3B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e3e9eau:
+ {
+ if (name == BuiltInName::textureGradOffset_0I2B2B2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0I2B2B2B2C;
+ }
+ break;
+ }
+ case 0x22e5bb38u:
+ {
+ if (name == BuiltInName::textureGradOffset_0R2B2B2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0R2B2B2B2C;
+ }
+ break;
+ }
+ case 0x22e5c876u:
+ {
+ if (name == BuiltInName::textureGradOffset_0Q1B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0Q1B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e61729u:
+ {
+ if (name == BuiltInName::textureGradOffset_0X2B2B2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0X2B2B2B2C;
+ }
+ break;
+ }
+ case 0x22e68293u:
+ {
+ if (name == BuiltInName::textureGradOffset_0Z2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0Z2B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e71012u:
+ {
+ if (name == BuiltInName::textureGradOffset_0H1B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0H1B1B1B1C;
+ }
+ break;
+ }
+ case 0x22e7429eu:
+ {
+ if (name == BuiltInName::textureGradOffset_0c2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureGradOffset_0c2B1B1B1C;
+ }
+ break;
+ }
+ case 0x28e8b7d0u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0W3B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0W3B0B1C;
+ }
+ break;
+ }
+ case 0x28e91d51u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0R3B0B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0R3B0B2C;
+ }
+ break;
+ }
+ case 0x28e9a246u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0W2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0W2B0B1C;
+ }
+ break;
+ }
+ case 0x28eab462u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0H2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0H2B0B1C;
+ }
+ break;
+ }
+ case 0x28eb8605u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0I3B0B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0I3B0B2C;
+ }
+ break;
+ }
+ case 0x28ebf99eu:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0H3B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0H3B0B1C;
+ }
+ break;
+ }
+ case 0x28ec29a7u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0Q3B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0Q3B0B1C;
+ }
+ break;
+ }
+ case 0x28eecd92u:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0X3B0B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0X3B0B2C;
+ }
+ break;
+ }
+ case 0x28ef956cu:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0Q2B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0Q2B0B1C;
+ }
+ break;
+ }
+ case 0x28efb13bu:
+ {
+ if (name == BuiltInName::textureProjLodOffset_0c3B0B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjLodOffset_0c3B0B1C;
+ }
+ break;
+ }
+ case 0x2b00aacdu:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0c3B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0c3B1B1B1C;
+ }
+ break;
+ }
+ case 0x2b022418u:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0H3B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0H3B1B1B1C;
+ }
+ break;
+ }
+ case 0x2b0252ccu:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0X3B2B2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0X3B2B2B2C;
+ }
+ break;
+ }
+ case 0x2b02af8fu:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0I3B2B2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0I3B2B2B2C;
+ }
+ break;
+ }
+ case 0x2b03ccf9u:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0Q2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0Q2B1B1B1C;
+ }
+ break;
+ }
+ case 0x2b03db51u:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0W2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0W2B1B1B1C;
+ }
+ break;
+ }
+ case 0x2b047dfau:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0R3B2B2B2C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0R3B2B2B2C;
+ }
+ break;
+ }
+ case 0x2b06f874u:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0Q3B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0Q3B1B1B1C;
+ }
+ break;
+ }
+ case 0x2b077535u:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0H2B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0H2B1B1B1C;
+ }
+ break;
+ }
+ case 0x2b07f768u:
+ {
+ if (name == BuiltInName::textureProjGradOffset_0W3B1B1B1C)
+ {
+ return &BuiltInFunction::kFunction_textureProjGradOffset_0W3B1B1B1C;
+ }
+ break;
+ }
+ case 0x7ec10648u:
+ {
+ if (name == BuiltInName::gl_MaxProgramTexelOffset)
+ {
+ return mVar_gl_MaxProgramTexelOffset;
+ }
+ break;
+ }
+ case 0x7ec3c4d1u:
+ {
+ if (name == BuiltInName::gl_MinProgramTexelOffset)
+ {
+ return mVar_gl_MinProgramTexelOffset;
+ }
+ break;
+ }
+ case 0x7ec8d677u:
+ {
+ if (name == BuiltInName::gl_MaxVertexOutputVectors)
+ {
+ return mVar_gl_MaxVertexOutputVectors;
+ }
+ break;
+ }
+ case 0x7ed1aaebu:
+ {
+ if (name == BuiltInName::gl_MaxFragmentInputVectors)
+ {
+ return mVar_gl_MaxFragmentInputVectors;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x08394c88u:
+ {
+ if (name.beginsWith(BuiltInName::dFdy))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdy_0B;
+ }
+ break;
+ }
+ case 0x08398819u:
+ {
+ if (name.beginsWith(BuiltInName::dFdx))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdx_0B;
+ }
+ break;
+ }
+ case 0x083a7081u:
+ {
+ if (name.beginsWith(BuiltInName::dFdy))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdy_1B;
+ }
+ break;
+ }
+ case 0x083abe52u:
+ {
+ if (name.beginsWith(BuiltInName::dFdx))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdx_3B;
+ }
+ break;
+ }
+ case 0x083b9d7au:
+ {
+ if (name.beginsWith(BuiltInName::dFdy))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdy_2B;
+ }
+ break;
+ }
+ case 0x083c0d13u:
+ {
+ if (name.beginsWith(BuiltInName::dFdx))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdx_2B;
+ }
+ break;
+ }
+ case 0x083c6796u:
+ {
+ if (name.beginsWith(BuiltInName::dFdx))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdx_1B;
+ }
+ break;
+ }
+ case 0x083ced8bu:
+ {
+ if (name.beginsWith(BuiltInName::dFdy))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdy_3B;
+ }
+ break;
+ }
+ case 0x0c483e39u:
+ {
+ if (name.beginsWith(BuiltInName::fwidth))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidth_1B;
+ }
+ break;
+ }
+ case 0x0c4d354eu:
+ {
+ if (name.beginsWith(BuiltInName::fwidth))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidth_0B;
+ }
+ break;
+ }
+ case 0x0c4e7b0cu:
+ {
+ if (name.beginsWith(BuiltInName::fwidth))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidth_3B;
+ }
+ break;
+ }
+ case 0x0c4fa8b5u:
+ {
+ if (name.beginsWith(BuiltInName::fwidth))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidth_2B;
+ }
+ break;
+ }
+ case 0x0e7013d9u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0T2B0B;
+ }
+ break;
+ }
+ case 0x0e70d11du:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0W1B0B;
+ }
+ break;
+ }
+ case 0x0e70eff9u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0X2B0B;
+ }
+ break;
+ }
+ case 0x0e716d8fu:
+ {
+ if (name == BuiltInName::texture_0c2B0B)
+ {
+ return &BuiltInFunction::kFunction_texture_0c2B0B;
+ }
+ break;
+ }
+ case 0x0e71856cu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0M1B0B;
+ }
+ break;
+ }
+ case 0x0e723219u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0L1B0B;
+ }
+ break;
+ }
+ case 0x0e734ff8u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0Z2B0B;
+ }
+ break;
+ }
+ case 0x0e7386b0u:
+ {
+ if (name == BuiltInName::texture_0Q1B0B)
+ {
+ return &BuiltInFunction::kFunction_texture_0Q1B0B;
+ }
+ break;
+ }
+ case 0x0e740087u:
+ {
+ if (name == BuiltInName::texture_0d3B0B)
+ {
+ return &BuiltInFunction::kFunction_texture_0d3B0B;
+ }
+ break;
+ }
+ case 0x0e742a66u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0K2B0B;
+ }
+ break;
+ }
+ case 0x0e75399eu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0S2B0B;
+ }
+ break;
+ }
+ case 0x0e755c73u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0Y2B0B;
+ }
+ break;
+ }
+ case 0x0e75d15fu:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0J2B0B;
+ }
+ break;
+ }
+ case 0x0e76e7c1u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0H1B0B;
+ }
+ break;
+ }
+ case 0x0e7720c0u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0R2B0B;
+ }
+ break;
+ }
+ case 0x0e77d1c8u:
+ {
+ if (name.beginsWith(BuiltInName::texture))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture_0I2B0B;
+ }
+ break;
+ }
+ case 0x16900558u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0L3B0B;
+ }
+ break;
+ }
+ case 0x1690a3cfu:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0W3B0B;
+ }
+ break;
+ }
+ case 0x1690ae9fu:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0M3B0B;
+ }
+ break;
+ }
+ case 0x1691c2edu:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0M2B0B;
+ }
+ break;
+ }
+ case 0x16925badu:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0Q3B0B;
+ }
+ break;
+ }
+ case 0x1692d089u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0c3B0B;
+ }
+ break;
+ }
+ case 0x169350d8u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0I3B0B;
+ }
+ break;
+ }
+ case 0x16939955u:
+ {
+ if (name == BuiltInName::textureProj_0Q2B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProj_0Q2B0B;
+ }
+ break;
+ }
+ case 0x1694622au:
+ {
+ if (name == BuiltInName::textureProj_0R3B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProj_0R3B0B;
+ }
+ break;
+ }
+ case 0x169465e2u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0W2B0B;
+ }
+ break;
+ }
+ case 0x1695f573u:
+ {
+ if (name == BuiltInName::textureProj_0X3B0B)
+ {
+ return &BuiltInFunction::kFunction_textureProj_0X3B0B;
+ }
+ break;
+ }
+ case 0x16965fd9u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0H3B0B;
+ }
+ break;
+ }
+ case 0x1696f029u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0H2B0B;
+ }
+ break;
+ }
+ case 0x1697e9b9u:
+ {
+ if (name.beginsWith(BuiltInName::textureProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureProj_0L2B0B;
+ }
+ break;
+ }
+ case 0x1ab0a952u:
+ {
+ if (name == BuiltInName::textureOffset_0X2B2C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0X2B2C0B;
+ }
+ break;
+ }
+ case 0x1ab29724u:
+ {
+ if (name == BuiltInName::textureOffset_0Z2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0Z2B1C0B;
+ }
+ break;
+ }
+ case 0x1ab55c9du:
+ {
+ if (name == BuiltInName::textureOffset_0Q1B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0Q1B1C0B;
+ }
+ break;
+ }
+ case 0x1ab5753fu:
+ {
+ if (name == BuiltInName::textureOffset_0T2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0T2B1C0B;
+ }
+ break;
+ }
+ case 0x1ab57bbcu:
+ {
+ if (name == BuiltInName::textureOffset_0H1B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0H1B1C0B;
+ }
+ break;
+ }
+ case 0x1ab59b6cu:
+ {
+ if (name == BuiltInName::textureOffset_0I2B2C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0I2B2C0B;
+ }
+ break;
+ }
+ case 0x1ab5d795u:
+ {
+ if (name == BuiltInName::textureOffset_0W1B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0W1B1C0B;
+ }
+ break;
+ }
+ case 0x1ab63ddau:
+ {
+ if (name == BuiltInName::textureOffset_0K2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0K2B1C0B;
+ }
+ break;
+ }
+ case 0x1ab63f72u:
+ {
+ if (name == BuiltInName::textureOffset_0R2B2C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0R2B2C0B;
+ }
+ break;
+ }
+ case 0x1ab7e533u:
+ {
+ if (name == BuiltInName::textureOffset_0c2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureOffset_0c2B1C0B;
+ }
+ break;
+ }
+ case 0x22d11d67u:
+ {
+ if (name == BuiltInName::textureProjOffset_0Q3B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0Q3B1C0B;
+ }
+ break;
+ }
+ case 0x22d1425bu:
+ {
+ if (name == BuiltInName::textureProjOffset_0W2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0W2B1C0B;
+ }
+ break;
+ }
+ case 0x22d17100u:
+ {
+ if (name == BuiltInName::textureProjOffset_0W3B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0W3B1C0B;
+ }
+ break;
+ }
+ case 0x22d1ca54u:
+ {
+ if (name == BuiltInName::textureProjOffset_0c3B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0c3B1C0B;
+ }
+ break;
+ }
+ case 0x22d6074cu:
+ {
+ if (name == BuiltInName::textureProjOffset_0R3B2C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0R3B2C0B;
+ }
+ break;
+ }
+ case 0x22d60cd3u:
+ {
+ if (name == BuiltInName::textureProjOffset_0X3B2C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0X3B2C0B;
+ }
+ break;
+ }
+ case 0x22d60e91u:
+ {
+ if (name == BuiltInName::textureProjOffset_0Q2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0Q2B1C0B;
+ }
+ break;
+ }
+ case 0x22d62e81u:
+ {
+ if (name == BuiltInName::textureProjOffset_0H3B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0H3B1C0B;
+ }
+ break;
+ }
+ case 0x22d6b2e8u:
+ {
+ if (name == BuiltInName::textureProjOffset_0I3B2C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0I3B2C0B;
+ }
+ break;
+ }
+ case 0x22d6ee53u:
+ {
+ if (name == BuiltInName::textureProjOffset_0H2B1C0B)
+ {
+ return &BuiltInFunction::kFunction_textureProjOffset_0H2B1C0B;
+ }
+ break;
+ }
+ case 0x7e645c89u:
+ {
+ if (name == BuiltInName::gl_FragDepth)
+ {
+ return &BuiltInVariable::kVar_gl_FragDepth;
+ }
+ break;
+ }
+ }
+ }
+ if (mShaderType == GL_VERTEX_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e5f8987u:
+ {
+ if (name == BuiltInName::gl_VertexID)
+ {
+ return &BuiltInVariable::kVar_gl_VertexID;
+ }
+ break;
+ }
+ case 0x7e6be47fu:
+ {
+ if (name == BuiltInName::gl_InstanceID)
+ {
+ return &BuiltInVariable::kVar_gl_InstanceID;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_VERTEX_SHADER) && (mResources.ANGLE_multi_draw))
+ {
+ switch (nameHash)
+ {
+ case 0x7e4c3c42u:
+ {
+ if (name == BuiltInName::gl_DrawID)
+ {
+ return &BuiltInVariable::kVar_gl_DrawID;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_VERTEX_SHADER) && (mResources.ANGLE_base_vertex_base_instance))
+ {
+ switch (nameHash)
+ {
+ case 0x7e695e00u:
+ {
+ if (name == BuiltInName::gl_BaseVertex)
+ {
+ return &BuiltInVariable::kVar_gl_BaseVertex;
+ }
+ break;
+ }
+ case 0x7e785b75u:
+ {
+ if (name == BuiltInName::gl_BaseInstance)
+ {
+ return &BuiltInVariable::kVar_gl_BaseInstance;
+ }
+ break;
+ }
+ }
+ }
+ if ((mResources.OVR_multiview || mResources.OVR_multiview2) &&
+ mShaderType != GL_COMPUTE_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e6f6de9u:
+ {
+ if (name == BuiltInName::gl_ViewID_OVR)
+ {
+ return &BuiltInVariable::kVar_gl_ViewID_OVR;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (shaderVersion == 100)
+ {
+ switch (nameHash)
+ {
+ case 0x1271689cu:
+ {
+ if (name.beginsWith(BuiltInName::texture2D))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture2D_0H1B;
+ }
+ break;
+ }
+ case 0x127728cau:
+ {
+ if (name.beginsWith(BuiltInName::texture2D))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture2D_0L1B;
+ }
+ break;
+ }
+ case 0x1680927du:
+ {
+ if (name.beginsWith(BuiltInName::textureCube))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_textureCube_0J2B;
+ }
+ break;
+ }
+ case 0x1a902408u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DRect))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_texture2DRect_0N1B;
+ }
+ break;
+ }
+ case 0x1a92969du:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_texture2DProj_0L2B;
+ }
+ break;
+ }
+ case 0x1a9584eau:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_texture2DProj_0L3B;
+ }
+ break;
+ }
+ case 0x1a95bcc7u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_texture2DProj_0H3B;
+ }
+ break;
+ }
+ case 0x1a96b8d6u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_texture2DProj_0H2B;
+ }
+ break;
+ }
+ case 0x20cb8d71u:
+ {
+ if (name == BuiltInName::texture2DGradEXT_0H1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_texture2DGradEXT_0H1B1B1B;
+ }
+ break;
+ }
+ case 0x22b53a05u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DRectProj))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_texture2DRectProj_0N3B;
+ }
+ break;
+ }
+ case 0x22b65e05u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DRectProj))
+ {
+ ASSERT(name.length() == 22);
+ return &BuiltInFunction::kFunction_texture2DRectProj_0N2B;
+ }
+ break;
+ }
+ case 0x24dbd51eu:
+ {
+ if (name == BuiltInName::textureCubeGradEXT_0J2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_textureCubeGradEXT_0J2B2B2B;
+ }
+ break;
+ }
+ case 0x28e995cbu:
+ {
+ if (name == BuiltInName::texture2DProjGradEXT_0H3B1B1B)
+ {
+ return &BuiltInFunction::kFunction_texture2DProjGradEXT_0H3B1B1B;
+ }
+ break;
+ }
+ case 0x28ed5178u:
+ {
+ if (name == BuiltInName::texture2DProjGradEXT_0H2B1B1B)
+ {
+ return &BuiltInFunction::kFunction_texture2DProjGradEXT_0H2B1B1B;
+ }
+ break;
+ }
+ case 0x7e5a0c08u:
+ {
+ if (name == BuiltInName::gl_FragData)
+ {
+ // Only initialized if shaderType == GL_FRAGMENT_SHADER
+ return mVar_gl_FragData;
+ }
+ break;
+ }
+ case 0x7e7c38efu:
+ {
+ if (name == BuiltInName::gl_FragDepthEXT)
+ {
+ // Only initialized if (shaderType == GL_FRAGMENT_SHADER) &&
+ // (mResources.EXT_frag_depth)
+ return mVar_gl_FragDepthEXT;
+ }
+ break;
+ }
+ case 0x7ea6cdf6u:
+ {
+ if (name == BuiltInName::gl_MaxVaryingVectors)
+ {
+ return mVar_gl_MaxVaryingVectors;
+ }
+ break;
+ }
+ case 0x7ebce486u:
+ {
+ if (name == BuiltInName::gl_SecondaryFragDataEXT)
+ {
+ // Only initialized if (shaderType == GL_FRAGMENT_SHADER) &&
+ // (mResources.EXT_blend_func_extended)
+ return mVar_gl_SecondaryFragDataEXT;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x08394c88u:
+ {
+ if (name.beginsWith(BuiltInName::dFdyExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdyExt_0B;
+ }
+ break;
+ }
+ case 0x08398819u:
+ {
+ if (name.beginsWith(BuiltInName::dFdxExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdxExt_0B;
+ }
+ break;
+ }
+ case 0x083a7081u:
+ {
+ if (name.beginsWith(BuiltInName::dFdyExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdyExt_1B;
+ }
+ break;
+ }
+ case 0x083abe52u:
+ {
+ if (name.beginsWith(BuiltInName::dFdxExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdxExt_3B;
+ }
+ break;
+ }
+ case 0x083b9d7au:
+ {
+ if (name.beginsWith(BuiltInName::dFdyExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdyExt_2B;
+ }
+ break;
+ }
+ case 0x083c0d13u:
+ {
+ if (name.beginsWith(BuiltInName::dFdxExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdxExt_2B;
+ }
+ break;
+ }
+ case 0x083c6796u:
+ {
+ if (name.beginsWith(BuiltInName::dFdxExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdxExt_1B;
+ }
+ break;
+ }
+ case 0x083ced8bu:
+ {
+ if (name.beginsWith(BuiltInName::dFdyExt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_dFdyExt_3B;
+ }
+ break;
+ }
+ case 0x0c483e39u:
+ {
+ if (name.beginsWith(BuiltInName::fwidthExt))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidthExt_1B;
+ }
+ break;
+ }
+ case 0x0c4d354eu:
+ {
+ if (name.beginsWith(BuiltInName::fwidthExt))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidthExt_0B;
+ }
+ break;
+ }
+ case 0x0c4e7b0cu:
+ {
+ if (name.beginsWith(BuiltInName::fwidthExt))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidthExt_3B;
+ }
+ break;
+ }
+ case 0x0c4fa8b5u:
+ {
+ if (name.beginsWith(BuiltInName::fwidthExt))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_fwidthExt_2B;
+ }
+ break;
+ }
+ case 0x12764e24u:
+ {
+ if (name.beginsWith(BuiltInName::texture3D))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_texture3D_0I2B;
+ }
+ break;
+ }
+ case 0x12810dc6u:
+ {
+ if (name == BuiltInName::texture3D_0I2B0B)
+ {
+ return &BuiltInFunction::kFunction_texture3D_0I2B0B;
+ }
+ break;
+ }
+ case 0x12846ba6u:
+ {
+ if (name.beginsWith(BuiltInName::texture2D))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_texture2D_0H1B0B;
+ }
+ break;
+ }
+ case 0x1696a314u:
+ {
+ if (name.beginsWith(BuiltInName::textureCube))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_textureCube_0J2B0B;
+ }
+ break;
+ }
+ case 0x189e8416u:
+ {
+ if (name.beginsWith(BuiltInName::texture3DLod))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_texture3DLod_0I2B0B;
+ }
+ break;
+ }
+ case 0x1a93312fu:
+ {
+ if (name.beginsWith(BuiltInName::texture3DProj))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_texture3DProj_0I3B;
+ }
+ break;
+ }
+ case 0x1aa197a7u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProj))
+ {
+ ASSERT(name.length() == 20);
+ return &BuiltInFunction::kFunction_texture2DProj_0H3B0B;
+ }
+ break;
+ }
+ case 0x1aa44389u:
+ {
+ if (name == BuiltInName::texture2DProj_0H2B0B)
+ {
+ return &BuiltInFunction::kFunction_texture2DProj_0H2B0B;
+ }
+ break;
+ }
+ case 0x1aa7eecdu:
+ {
+ if (name == BuiltInName::texture3DProj_0I3B0B)
+ {
+ return &BuiltInFunction::kFunction_texture3DProj_0I3B0B;
+ }
+ break;
+ }
+ case 0x1eb43b6cu:
+ {
+ if (name == BuiltInName::texture2DLodEXT_0H1B0B)
+ {
+ return &BuiltInFunction::kFunction_texture2DLodEXT_0H1B0B;
+ }
+ break;
+ }
+ case 0x20b9ceecu:
+ {
+ if (name.beginsWith(BuiltInName::texture3DProjLod))
+ {
+ ASSERT(name.length() == 23);
+ return &BuiltInFunction::kFunction_texture3DProjLod_0I3B0B;
+ }
+ break;
+ }
+ case 0x22c206a5u:
+ {
+ if (name.beginsWith(BuiltInName::textureCubeLodEXT))
+ {
+ ASSERT(name.length() == 24);
+ return &BuiltInFunction::kFunction_textureCubeLodEXT_0J2B0B;
+ }
+ break;
+ }
+ case 0x26d1d3beu:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProjLodEXT))
+ {
+ ASSERT(name.length() == 26);
+ return &BuiltInFunction::kFunction_texture2DProjLodEXT_0H3B0B;
+ }
+ break;
+ }
+ case 0x26d60d82u:
+ {
+ if (name == BuiltInName::texture2DProjLodEXT_0H2B0B)
+ {
+ return &BuiltInFunction::kFunction_texture2DProjLodEXT_0H2B0B;
+ }
+ break;
+ }
+ case 0x7e60c438u:
+ {
+ if (name == BuiltInName::gl_FragColor)
+ {
+ return &BuiltInVariable::kVar_gl_FragColor;
+ }
+ break;
+ }
+ }
+ }
+ if (mShaderType == GL_VERTEX_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x18986fc2u:
+ {
+ if (name == BuiltInName::texture2DLod_0H1B0B)
+ {
+ return &BuiltInFunction::kFunction_texture2DLod_0H1B0B;
+ }
+ break;
+ }
+ case 0x1cac1f4du:
+ {
+ if (name.beginsWith(BuiltInName::textureCubeLod))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_textureCubeLod_0J2B0B;
+ }
+ break;
+ }
+ case 0x20b8a0c3u:
+ {
+ if (name.beginsWith(BuiltInName::texture2DProjLod))
+ {
+ ASSERT(name.length() == 23);
+ return &BuiltInFunction::kFunction_texture2DProjLod_0H3B0B;
+ }
+ break;
+ }
+ case 0x20bc6337u:
+ {
+ if (name == BuiltInName::texture2DProjLod_0H2B0B)
+ {
+ return &BuiltInFunction::kFunction_texture2DProjLod_0H2B0B;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_blend_func_extended))
+ {
+ switch (nameHash)
+ {
+ case 0x7ec56cbeu:
+ {
+ if (name == BuiltInName::gl_SecondaryFragColorEXT)
+ {
+ return &BuiltInVariable::kVar_gl_SecondaryFragColorEXT;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_shader_framebuffer_fetch))
+ {
+ switch (nameHash)
+ {
+ case 0x7e7970c2u:
+ {
+ if (name == BuiltInName::gl_LastFragData)
+ {
+ return mVar_gl_LastFragData;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.NV_shader_framebuffer_fetch))
+ {
+ switch (nameHash)
+ {
+ case 0x7e7970c2u:
+ {
+ if (name == BuiltInName::gl_LastFragData)
+ {
+ return mVar_gl_LastFragDataNV;
+ }
+ break;
+ }
+ case 0x7e802016u:
+ {
+ if (name == BuiltInName::gl_LastFragColor)
+ {
+ return &BuiltInVariable::kVar_gl_LastFragColor;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_FRAGMENT_SHADER) &&
+ (!mResources.EXT_shader_framebuffer_fetch && !mResources.NV_shader_framebuffer_fetch &&
+ mResources.ARM_shader_framebuffer_fetch))
+ {
+ switch (nameHash)
+ {
+ case 0x7e9f0a88u:
+ {
+ if (name == BuiltInName::gl_LastFragColorARM)
+ {
+ return &BuiltInVariable::kVar_gl_LastFragColorARM;
+ }
+ break;
+ }
+ }
+ }
+ if ((mShaderType == GL_VERTEX_SHADER) && (mResources.ANGLE_multi_draw))
+ {
+ switch (nameHash)
+ {
+ case 0x7e4c3c42u:
+ {
+ if (name == BuiltInName::gl_DrawID)
+ {
+ return &BuiltInVariable::kVar_gl_DrawIDESSL1;
+ }
+ break;
+ }
+ }
+ }
+ if ((mResources.OVR_multiview || mResources.OVR_multiview2) &&
+ mShaderType != GL_COMPUTE_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e6f6de9u:
+ {
+ if (name == BuiltInName::gl_ViewID_OVR)
+ {
+ return &BuiltInVariable::kVar_gl_ViewID_OVRESSL1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ switch (nameHash)
+ {
+ case 0x063055e6u:
+ {
+ if (name.beginsWith(BuiltInName::log))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_log_0B;
+ }
+ break;
+ }
+ case 0x06307fbcu:
+ {
+ if (name.beginsWith(BuiltInName::all))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_all_1E;
+ }
+ break;
+ }
+ case 0x0630826fu:
+ {
+ if (name.beginsWith(BuiltInName::notFunc))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_notFunc_3E;
+ }
+ break;
+ }
+ case 0x0630942fu:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_0B;
+ }
+ break;
+ }
+ case 0x06309ccau:
+ {
+ if (name.beginsWith(BuiltInName::tan))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_tan_1B;
+ }
+ break;
+ }
+ case 0x0630bc6au:
+ {
+ if (name.beginsWith(BuiltInName::cos))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_cos_2B;
+ }
+ break;
+ }
+ case 0x0630dce3u:
+ {
+ if (name.beginsWith(BuiltInName::log))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_log_3B;
+ }
+ break;
+ }
+ case 0x063194bfu:
+ {
+ if (name.beginsWith(BuiltInName::any))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_any_1E;
+ }
+ break;
+ }
+ case 0x0631a1ccu:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_3B;
+ }
+ break;
+ }
+ case 0x0631d12au:
+ {
+ if (name.beginsWith(BuiltInName::log))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_log_2B;
+ }
+ break;
+ }
+ case 0x06320b8bu:
+ {
+ if (name.beginsWith(BuiltInName::cos))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_cos_3B;
+ }
+ break;
+ }
+ case 0x0632fcb3u:
+ {
+ if (name.beginsWith(BuiltInName::any))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_any_3E;
+ }
+ break;
+ }
+ case 0x06330b41u:
+ {
+ if (name.beginsWith(BuiltInName::log))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_log_1B;
+ }
+ break;
+ }
+ case 0x063314b1u:
+ {
+ if (name.beginsWith(BuiltInName::sin))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_sin_1B;
+ }
+ break;
+ }
+ case 0x063415e2u:
+ {
+ if (name.beginsWith(BuiltInName::any))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_any_2E;
+ }
+ break;
+ }
+ case 0x06344570u:
+ {
+ if (name.beginsWith(BuiltInName::sin))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_sin_0B;
+ }
+ break;
+ }
+ case 0x0634cf9au:
+ {
+ if (name.beginsWith(BuiltInName::sin))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_sin_3B;
+ }
+ break;
+ }
+ case 0x06352335u:
+ {
+ if (name.beginsWith(BuiltInName::exp))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_exp_3B;
+ }
+ break;
+ }
+ case 0x063595b9u:
+ {
+ if (name.beginsWith(BuiltInName::exp))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_exp_0B;
+ }
+ break;
+ }
+ case 0x0635a80fu:
+ {
+ if (name.beginsWith(BuiltInName::tan))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_tan_2B;
+ }
+ break;
+ }
+ case 0x0635d3b3u:
+ {
+ if (name.beginsWith(BuiltInName::sin))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_sin_2B;
+ }
+ break;
+ }
+ case 0x0635eb79u:
+ {
+ if (name.beginsWith(BuiltInName::all))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_all_2E;
+ }
+ break;
+ }
+ case 0x06366a98u:
+ {
+ if (name.beginsWith(BuiltInName::cos))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_cos_0B;
+ }
+ break;
+ }
+ case 0x0636b1f1u:
+ {
+ if (name.beginsWith(BuiltInName::exp))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_exp_1B;
+ }
+ break;
+ }
+ case 0x0636dda0u:
+ {
+ if (name.beginsWith(BuiltInName::all))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_all_3E;
+ }
+ break;
+ }
+ case 0x0636e0efu:
+ {
+ if (name.beginsWith(BuiltInName::notFunc))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_notFunc_1E;
+ }
+ break;
+ }
+ case 0x063719d6u:
+ {
+ if (name.beginsWith(BuiltInName::tan))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_tan_3B;
+ }
+ break;
+ }
+ case 0x06371aefu:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_2B;
+ }
+ break;
+ }
+ case 0x06376a86u:
+ {
+ if (name.beginsWith(BuiltInName::notFunc))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_notFunc_2E;
+ }
+ break;
+ }
+ case 0x063770d0u:
+ {
+ if (name.beginsWith(BuiltInName::tan))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_tan_0B;
+ }
+ break;
+ }
+ case 0x063770dfu:
+ {
+ if (name.beginsWith(BuiltInName::abs))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_abs_1B;
+ }
+ break;
+ }
+ case 0x063786f1u:
+ {
+ if (name.beginsWith(BuiltInName::cos))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_cos_1B;
+ }
+ break;
+ }
+ case 0x0637ca4au:
+ {
+ if (name.beginsWith(BuiltInName::exp))
+ {
+ ASSERT(name.length() == 6);
+ return &BuiltInFunction::kFunction_exp_2B;
+ }
+ break;
+ }
+ case 0x06400261u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_2B2B;
+ }
+ break;
+ }
+ case 0x06403847u:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_2B0B;
+ }
+ break;
+ }
+ case 0x064082ceu:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_1B0B;
+ }
+ break;
+ }
+ case 0x0640a98au:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_2B2B;
+ }
+ break;
+ }
+ case 0x064107b7u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_1B0B;
+ }
+ break;
+ }
+ case 0x06415ae6u:
+ {
+ if (name.beginsWith(BuiltInName::dot))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_dot_3B3B;
+ }
+ break;
+ }
+ case 0x06418e42u:
+ {
+ if (name.beginsWith(BuiltInName::pow))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_pow_3B3B;
+ }
+ break;
+ }
+ case 0x0641ceeeu:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_0B0B;
+ }
+ break;
+ }
+ case 0x0641f1d7u:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_1B1B;
+ }
+ break;
+ }
+ case 0x06421555u:
+ {
+ if (name.beginsWith(BuiltInName::dot))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_dot_1B1B;
+ }
+ break;
+ }
+ case 0x064225ceu:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_3B3B;
+ }
+ break;
+ }
+ case 0x064274eeu:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_1B1B;
+ }
+ break;
+ }
+ case 0x0642b54du:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_2B2B;
+ }
+ break;
+ }
+ case 0x064318fcu:
+ {
+ if (name.beginsWith(BuiltInName::pow))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_pow_2B2B;
+ }
+ break;
+ }
+ case 0x0643486cu:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_3B0B;
+ }
+ break;
+ }
+ case 0x06439435u:
+ {
+ if (name.beginsWith(BuiltInName::pow))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_pow_1B1B;
+ }
+ break;
+ }
+ case 0x06450933u:
+ {
+ if (name.beginsWith(BuiltInName::dot))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_dot_0B0B;
+ }
+ break;
+ }
+ case 0x0645114fu:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_1B0B;
+ }
+ break;
+ }
+ case 0x06457883u:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_3B3B;
+ }
+ break;
+ }
+ case 0x0645f03eu:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_3B0B;
+ }
+ break;
+ }
+ case 0x0645fd82u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_3B3B;
+ }
+ break;
+ }
+ case 0x0646155eu:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_1B1B;
+ }
+ break;
+ }
+ case 0x06462cf0u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_2B0B;
+ }
+ break;
+ }
+ case 0x06463219u:
+ {
+ if (name.beginsWith(BuiltInName::dot))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_dot_2B2B;
+ }
+ break;
+ }
+ case 0x06467507u:
+ {
+ if (name.beginsWith(BuiltInName::min))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_min_3B0B;
+ }
+ break;
+ }
+ case 0x06468fb1u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_2B0B;
+ }
+ break;
+ }
+ case 0x0646b392u:
+ {
+ if (name.beginsWith(BuiltInName::pow))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_pow_0B0B;
+ }
+ break;
+ }
+ case 0x06472996u:
+ {
+ if (name.beginsWith(BuiltInName::max))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_max_0B0B;
+ }
+ break;
+ }
+ case 0x064778feu:
+ {
+ if (name.beginsWith(BuiltInName::mod))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_mod_0B0B;
+ }
+ break;
+ }
+ case 0x0650f1c9u:
+ {
+ if (name.beginsWith(BuiltInName::mix))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_mix_1B1B0B;
+ }
+ break;
+ }
+ case 0x0653049du:
+ {
+ if (name.beginsWith(BuiltInName::mix))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_mix_2B2B0B;
+ }
+ break;
+ }
+ case 0x06549219u:
+ {
+ if (name.beginsWith(BuiltInName::mix))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_mix_2B2B2B;
+ }
+ break;
+ }
+ case 0x0655be57u:
+ {
+ if (name.beginsWith(BuiltInName::mix))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_mix_0B0B0B;
+ }
+ break;
+ }
+ case 0x06561bdcu:
+ {
+ if (name == BuiltInName::mix_3B3B0B)
+ {
+ return &BuiltInFunction::kFunction_mix_3B3B0B;
+ }
+ break;
+ }
+ case 0x06568deeu:
+ {
+ if (name == BuiltInName::mix_3B3B3B)
+ {
+ return &BuiltInFunction::kFunction_mix_3B3B3B;
+ }
+ break;
+ }
+ case 0x0657a0a8u:
+ {
+ if (name == BuiltInName::mix_1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_mix_1B1B1B;
+ }
+ break;
+ }
+ case 0x08383aacu:
+ {
+ if (name.beginsWith(BuiltInName::acos))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_acos_3B;
+ }
+ break;
+ }
+ case 0x0838a17eu:
+ {
+ if (name.beginsWith(BuiltInName::ceil))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_ceil_2B;
+ }
+ break;
+ }
+ case 0x0838ac89u:
+ {
+ if (name.beginsWith(BuiltInName::exp2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_exp2_3B;
+ }
+ break;
+ }
+ case 0x0838dc31u:
+ {
+ if (name.beginsWith(BuiltInName::sqrt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sqrt_0B;
+ }
+ break;
+ }
+ case 0x08396a55u:
+ {
+ if (name.beginsWith(BuiltInName::acos))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_acos_2B;
+ }
+ break;
+ }
+ case 0x0839daf2u:
+ {
+ if (name.beginsWith(BuiltInName::exp2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_exp2_0B;
+ }
+ break;
+ }
+ case 0x0839e751u:
+ {
+ if (name.beginsWith(BuiltInName::acos))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_acos_1B;
+ }
+ break;
+ }
+ case 0x0839f1a7u:
+ {
+ if (name.beginsWith(BuiltInName::ceil))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_ceil_3B;
+ }
+ break;
+ }
+ case 0x083a07bau:
+ {
+ if (name.beginsWith(BuiltInName::sqrt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sqrt_3B;
+ }
+ break;
+ }
+ case 0x083a7922u:
+ {
+ if (name.beginsWith(BuiltInName::ceil))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_ceil_0B;
+ }
+ break;
+ }
+ case 0x083aea5fu:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_atan_2B;
+ }
+ break;
+ }
+ case 0x083af266u:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_1B;
+ }
+ break;
+ }
+ case 0x083afbc8u:
+ {
+ if (name.beginsWith(BuiltInName::acos))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_acos_0B;
+ }
+ break;
+ }
+ case 0x083b2b93u:
+ {
+ if (name.beginsWith(BuiltInName::exp2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_exp2_1B;
+ }
+ break;
+ }
+ case 0x083b577bu:
+ {
+ if (name.beginsWith(BuiltInName::sqrt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sqrt_2B;
+ }
+ break;
+ }
+ case 0x083b7e52u:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_atan_1B;
+ }
+ break;
+ }
+ case 0x083bcf76u:
+ {
+ if (name.beginsWith(BuiltInName::sqrt))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sqrt_1B;
+ }
+ break;
+ }
+ case 0x083c1fc5u:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_2B;
+ }
+ break;
+ }
+ case 0x083c624bu:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_atan_0B;
+ }
+ break;
+ }
+ case 0x083ca453u:
+ {
+ if (name.beginsWith(BuiltInName::asin))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_asin_0B;
+ }
+ break;
+ }
+ case 0x083cc6e1u:
+ {
+ if (name.beginsWith(BuiltInName::log2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_log2_2B;
+ }
+ break;
+ }
+ case 0x083d6eacu:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_3B;
+ }
+ break;
+ }
+ case 0x083dac10u:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_atan_3B;
+ }
+ break;
+ }
+ case 0x083dd4deu:
+ {
+ if (name.beginsWith(BuiltInName::sign))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_sign_0B;
+ }
+ break;
+ }
+ case 0x083df752u:
+ {
+ if (name.beginsWith(BuiltInName::asin))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_asin_1B;
+ }
+ break;
+ }
+ case 0x083e1b7au:
+ {
+ if (name.beginsWith(BuiltInName::log2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_log2_1B;
+ }
+ break;
+ }
+ case 0x083e6948u:
+ {
+ if (name.beginsWith(BuiltInName::asin))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_asin_2B;
+ }
+ break;
+ }
+ case 0x083f4babu:
+ {
+ if (name.beginsWith(BuiltInName::log2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_log2_0B;
+ }
+ break;
+ }
+ case 0x083f6552u:
+ {
+ if (name.beginsWith(BuiltInName::asin))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_asin_3B;
+ }
+ break;
+ }
+ case 0x083f6afdu:
+ {
+ if (name.beginsWith(BuiltInName::ceil))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_ceil_1B;
+ }
+ break;
+ }
+ case 0x083f8b90u:
+ {
+ if (name.beginsWith(BuiltInName::exp2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_exp2_2B;
+ }
+ break;
+ }
+ case 0x083fd32eu:
+ {
+ if (name.beginsWith(BuiltInName::log2))
+ {
+ ASSERT(name.length() == 7);
+ return &BuiltInFunction::kFunction_log2_3B;
+ }
+ break;
+ }
+ case 0x08482806u:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_atan_3B3B;
+ }
+ break;
+ }
+ case 0x08491304u:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_0B1B;
+ }
+ break;
+ }
+ case 0x0849bcfdu:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_2B2B;
+ }
+ break;
+ }
+ case 0x084aa6bfu:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_atan_1B1B;
+ }
+ break;
+ }
+ case 0x084c10fau:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_atan_0B0B;
+ }
+ break;
+ }
+ case 0x084c9765u:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_1B1B;
+ }
+ break;
+ }
+ case 0x084e7af1u:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_3B3B;
+ }
+ break;
+ }
+ case 0x084e7be4u:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_0B0B;
+ }
+ break;
+ }
+ case 0x084ec1e6u:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_0B3B;
+ }
+ break;
+ }
+ case 0x084ee899u:
+ {
+ if (name.beginsWith(BuiltInName::atan))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_atan_2B2B;
+ }
+ break;
+ }
+ case 0x084feda7u:
+ {
+ if (name.beginsWith(BuiltInName::step))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_step_0B2B;
+ }
+ break;
+ }
+ case 0x0a402a9cu:
+ {
+ if (name.beginsWith(BuiltInName::fract))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_fract_0B;
+ }
+ break;
+ }
+ case 0x0a41745fu:
+ {
+ if (name.beginsWith(BuiltInName::fract))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_fract_3B;
+ }
+ break;
+ }
+ case 0x0a42a596u:
+ {
+ if (name.beginsWith(BuiltInName::fract))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_fract_2B;
+ }
+ break;
+ }
+ case 0x0a43465eu:
+ {
+ if (name.beginsWith(BuiltInName::floor))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_floor_0B;
+ }
+ break;
+ }
+ case 0x0a43be63u:
+ {
+ if (name.beginsWith(BuiltInName::floor))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_floor_3B;
+ }
+ break;
+ }
+ case 0x0a44da6bu:
+ {
+ if (name.beginsWith(BuiltInName::floor))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_floor_2B;
+ }
+ break;
+ }
+ case 0x0a45ecc0u:
+ {
+ if (name.beginsWith(BuiltInName::floor))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_floor_1B;
+ }
+ break;
+ }
+ case 0x0a4726f2u:
+ {
+ if (name.beginsWith(BuiltInName::fract))
+ {
+ ASSERT(name.length() == 8);
+ return &BuiltInFunction::kFunction_fract_1B;
+ }
+ break;
+ }
+ case 0x0a513a26u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_3E3E;
+ }
+ break;
+ }
+ case 0x0a51bddcu:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_3B3B;
+ }
+ break;
+ }
+ case 0x0a527d10u:
+ {
+ if (name.beginsWith(BuiltInName::cross))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_cross_2B2B;
+ }
+ break;
+ }
+ case 0x0a542036u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_2C2C;
+ }
+ break;
+ }
+ case 0x0a54c30cu:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_2B2B;
+ }
+ break;
+ }
+ case 0x0a554046u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_1C1C;
+ }
+ break;
+ }
+ case 0x0a56874bu:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_3C3C;
+ }
+ break;
+ }
+ case 0x0a56fc88u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_2E2E;
+ }
+ break;
+ }
+ case 0x0a5744dcu:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_1E1E;
+ }
+ break;
+ }
+ case 0x0a57a8f5u:
+ {
+ if (name.beginsWith(BuiltInName::equal))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_equal_1B1B;
+ }
+ break;
+ }
+ case 0x0a619e65u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_3B3B3B;
+ }
+ break;
+ }
+ case 0x0a62e0c3u:
+ {
+ if (name == BuiltInName::clamp_1B0B0B)
+ {
+ return &BuiltInFunction::kFunction_clamp_1B0B0B;
+ }
+ break;
+ }
+ case 0x0a635d1au:
+ {
+ if (name == BuiltInName::clamp_1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_clamp_1B1B1B;
+ }
+ break;
+ }
+ case 0x0a658fc9u:
+ {
+ if (name == BuiltInName::clamp_3B0B0B)
+ {
+ return &BuiltInFunction::kFunction_clamp_3B0B0B;
+ }
+ break;
+ }
+ case 0x0a65f6b4u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_0B0B0B;
+ }
+ break;
+ }
+ case 0x0a6670deu:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_2B0B0B;
+ }
+ break;
+ }
+ case 0x0a679af4u:
+ {
+ if (name.beginsWith(BuiltInName::clamp))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_clamp_2B2B2B;
+ }
+ break;
+ }
+ case 0x0c48bffau:
+ {
+ if (name.beginsWith(BuiltInName::length))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_length_0B;
+ }
+ break;
+ }
+ case 0x0c4924f7u:
+ {
+ if (name.beginsWith(BuiltInName::length))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_length_3B;
+ }
+ break;
+ }
+ case 0x0c4a38b6u:
+ {
+ if (name.beginsWith(BuiltInName::length))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_length_2B;
+ }
+ break;
+ }
+ case 0x0c4f6cbbu:
+ {
+ if (name.beginsWith(BuiltInName::length))
+ {
+ ASSERT(name.length() == 9);
+ return &BuiltInFunction::kFunction_length_1B;
+ }
+ break;
+ }
+ case 0x0e507f22u:
+ {
+ if (name.beginsWith(BuiltInName::degrees))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_degrees_2B;
+ }
+ break;
+ }
+ case 0x0e519bd4u:
+ {
+ if (name.beginsWith(BuiltInName::degrees))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_degrees_3B;
+ }
+ break;
+ }
+ case 0x0e52b187u:
+ {
+ if (name.beginsWith(BuiltInName::degrees))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_degrees_0B;
+ }
+ break;
+ }
+ case 0x0e52e500u:
+ {
+ if (name.beginsWith(BuiltInName::radians))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_radians_0B;
+ }
+ break;
+ }
+ case 0x0e537b7au:
+ {
+ if (name.beginsWith(BuiltInName::radians))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_radians_3B;
+ }
+ break;
+ }
+ case 0x0e541edeu:
+ {
+ if (name.beginsWith(BuiltInName::degrees))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_degrees_1B;
+ }
+ break;
+ }
+ case 0x0e547683u:
+ {
+ if (name.beginsWith(BuiltInName::radians))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_radians_2B;
+ }
+ break;
+ }
+ case 0x0e55ac28u:
+ {
+ if (name.beginsWith(BuiltInName::radians))
+ {
+ ASSERT(name.length() == 10);
+ return &BuiltInFunction::kFunction_radians_1B;
+ }
+ break;
+ }
+ case 0x0e620f44u:
+ {
+ if (name.beginsWith(BuiltInName::reflect))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_reflect_2B2B;
+ }
+ break;
+ }
+ case 0x0e631c50u:
+ {
+ if (name.beginsWith(BuiltInName::reflect))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_reflect_3B3B;
+ }
+ break;
+ }
+ case 0x0e63358eu:
+ {
+ if (name.beginsWith(BuiltInName::reflect))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_reflect_0B0B;
+ }
+ break;
+ }
+ case 0x0e665b7bu:
+ {
+ if (name.beginsWith(BuiltInName::reflect))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_reflect_1B1B;
+ }
+ break;
+ }
+ case 0x0e706684u:
+ {
+ if (name.beginsWith(BuiltInName::refract))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_refract_1B1B0B;
+ }
+ break;
+ }
+ case 0x0e71a4fcu:
+ {
+ if (name.beginsWith(BuiltInName::refract))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_refract_2B2B0B;
+ }
+ break;
+ }
+ case 0x0e71b28du:
+ {
+ if (name == BuiltInName::refract_3B3B0B)
+ {
+ return &BuiltInFunction::kFunction_refract_3B3B0B;
+ }
+ break;
+ }
+ case 0x0e73b594u:
+ {
+ if (name.beginsWith(BuiltInName::refract))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_refract_0B0B0B;
+ }
+ break;
+ }
+ case 0x1068425fu:
+ {
+ if (name.beginsWith(BuiltInName::distance))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_distance_3B3B;
+ }
+ break;
+ }
+ case 0x1068c0bfu:
+ {
+ if (name.beginsWith(BuiltInName::distance))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_distance_2B2B;
+ }
+ break;
+ }
+ case 0x1068f060u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_1E1E;
+ }
+ break;
+ }
+ case 0x10695fe7u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_2E2E;
+ }
+ break;
+ }
+ case 0x1069b2c0u:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_1B1B;
+ }
+ break;
+ }
+ case 0x106a110cu:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_3C3C;
+ }
+ break;
+ }
+ case 0x106a63f2u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_2C2C;
+ }
+ break;
+ }
+ case 0x106a713eu:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_2B2B;
+ }
+ break;
+ }
+ case 0x106ade94u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_1B1B;
+ }
+ break;
+ }
+ case 0x106b25c9u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_1C1C;
+ }
+ break;
+ }
+ case 0x106b4468u:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_1C1C;
+ }
+ break;
+ }
+ case 0x106b8219u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_3B3B;
+ }
+ break;
+ }
+ case 0x106bc4fcu:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_3E3E;
+ }
+ break;
+ }
+ case 0x106caf4fu:
+ {
+ if (name.beginsWith(BuiltInName::distance))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_distance_0B0B;
+ }
+ break;
+ }
+ case 0x106d2c39u:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_3B3B;
+ }
+ break;
+ }
+ case 0x106dabccu:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_2B2B;
+ }
+ break;
+ }
+ case 0x106eaf65u:
+ {
+ if (name.beginsWith(BuiltInName::notEqual))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_notEqual_3C3C;
+ }
+ break;
+ }
+ case 0x106faaeau:
+ {
+ if (name.beginsWith(BuiltInName::lessThan))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_lessThan_2C2C;
+ }
+ break;
+ }
+ case 0x106ff564u:
+ {
+ if (name.beginsWith(BuiltInName::distance))
+ {
+ ASSERT(name.length() == 13);
+ return &BuiltInFunction::kFunction_distance_1B1B;
+ }
+ break;
+ }
+ case 0x126235c4u:
+ {
+ if (name.beginsWith(BuiltInName::normalize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_normalize_1B;
+ }
+ break;
+ }
+ case 0x12635a67u:
+ {
+ if (name.beginsWith(BuiltInName::normalize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_normalize_2B;
+ }
+ break;
+ }
+ case 0x1264aa3eu:
+ {
+ if (name.beginsWith(BuiltInName::normalize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_normalize_3B;
+ }
+ break;
+ }
+ case 0x12650243u:
+ {
+ if (name.beginsWith(BuiltInName::normalize))
+ {
+ ASSERT(name.length() == 12);
+ return &BuiltInFunction::kFunction_normalize_0B;
+ }
+ break;
+ }
+ case 0x14888e72u:
+ {
+ if (name.beginsWith(BuiltInName::smoothstep))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_smoothstep_0B0B1B;
+ }
+ break;
+ }
+ case 0x1489436du:
+ {
+ if (name == BuiltInName::smoothstep_1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_smoothstep_1B1B1B;
+ }
+ break;
+ }
+ case 0x1489bfb6u:
+ {
+ if (name == BuiltInName::smoothstep_3B3B3B)
+ {
+ return &BuiltInFunction::kFunction_smoothstep_3B3B3B;
+ }
+ break;
+ }
+ case 0x148a33b9u:
+ {
+ if (name.beginsWith(BuiltInName::smoothstep))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_smoothstep_2B2B2B;
+ }
+ break;
+ }
+ case 0x148de9b5u:
+ {
+ if (name.beginsWith(BuiltInName::smoothstep))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_smoothstep_0B0B0B;
+ }
+ break;
+ }
+ case 0x148e5c11u:
+ {
+ if (name == BuiltInName::smoothstep_0B0B3B)
+ {
+ return &BuiltInFunction::kFunction_smoothstep_0B0B3B;
+ }
+ break;
+ }
+ case 0x148f7bf9u:
+ {
+ if (name.beginsWith(BuiltInName::smoothstep))
+ {
+ ASSERT(name.length() == 17);
+ return &BuiltInFunction::kFunction_smoothstep_0B0B2B;
+ }
+ break;
+ }
+ case 0x1670b92du:
+ {
+ if (name.beginsWith(BuiltInName::inversesqrt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_inversesqrt_2B;
+ }
+ break;
+ }
+ case 0x1671d38eu:
+ {
+ if (name.beginsWith(BuiltInName::inversesqrt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_inversesqrt_1B;
+ }
+ break;
+ }
+ case 0x16772b69u:
+ {
+ if (name.beginsWith(BuiltInName::inversesqrt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_inversesqrt_0B;
+ }
+ break;
+ }
+ case 0x1677857cu:
+ {
+ if (name.beginsWith(BuiltInName::inversesqrt))
+ {
+ ASSERT(name.length() == 14);
+ return &BuiltInFunction::kFunction_inversesqrt_3B;
+ }
+ break;
+ }
+ case 0x16817df9u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_1B1B;
+ }
+ break;
+ }
+ case 0x1681b963u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_3C3C;
+ }
+ break;
+ }
+ case 0x16829d5du:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_3B3B;
+ }
+ break;
+ }
+ case 0x16853112u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_2B2B;
+ }
+ break;
+ }
+ case 0x1685d025u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_2C2C;
+ }
+ break;
+ }
+ case 0x1685db46u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThan))
+ {
+ ASSERT(name.length() == 16);
+ return &BuiltInFunction::kFunction_greaterThan_1C1C;
+ }
+ break;
+ }
+ case 0x1690b84du:
+ {
+ if (name == BuiltInName::faceforward_3B3B3B)
+ {
+ return &BuiltInFunction::kFunction_faceforward_3B3B3B;
+ }
+ break;
+ }
+ case 0x1691c40bu:
+ {
+ if (name == BuiltInName::faceforward_1B1B1B)
+ {
+ return &BuiltInFunction::kFunction_faceforward_1B1B1B;
+ }
+ break;
+ }
+ case 0x1696babeu:
+ {
+ if (name == BuiltInName::faceforward_2B2B2B)
+ {
+ return &BuiltInFunction::kFunction_faceforward_2B2B2B;
+ }
+ break;
+ }
+ case 0x1697cde8u:
+ {
+ if (name.beginsWith(BuiltInName::faceforward))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_faceforward_0B0B0B;
+ }
+ break;
+ }
+ case 0x1a9481a8u:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_2C2C;
+ }
+ break;
+ }
+ case 0x1a94a164u:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_3C3C;
+ }
+ break;
+ }
+ case 0x1a95c72au:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_1B1B;
+ }
+ break;
+ }
+ case 0x1a9642f7u:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_3B3B;
+ }
+ break;
+ }
+ case 0x1a977782u:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_1C1C;
+ }
+ break;
+ }
+ case 0x1a97d055u:
+ {
+ if (name.beginsWith(BuiltInName::lessThanEqual))
+ {
+ ASSERT(name.length() == 18);
+ return &BuiltInFunction::kFunction_lessThanEqual_2B2B;
+ }
+ break;
+ }
+ case 0x1c993bdfu:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_5B5B;
+ }
+ break;
+ }
+ case 0x1c9b357cu:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_FBFB;
+ }
+ break;
+ }
+ case 0x1c9e72dbu:
+ {
+ if (name.beginsWith(BuiltInName::matrixCompMult))
+ {
+ ASSERT(name.length() == 19);
+ return &BuiltInFunction::kFunction_matrixCompMult_ABAB;
+ }
+ break;
+ }
+ case 0x20ab1dc0u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_2C2C;
+ }
+ break;
+ }
+ case 0x20acdd3au:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_1B1B;
+ }
+ break;
+ }
+ case 0x20ad192cu:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_3C3C;
+ }
+ break;
+ }
+ case 0x20adfc96u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_3B3B;
+ }
+ break;
+ }
+ case 0x20ae6ffbu:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_2B2B;
+ }
+ break;
+ }
+ case 0x20af1dd4u:
+ {
+ if (name.beginsWith(BuiltInName::greaterThanEqual))
+ {
+ ASSERT(name.length() == 21);
+ return &BuiltInFunction::kFunction_greaterThanEqual_1C1C;
+ }
+ break;
+ }
+ case 0x7e6af03cu:
+ {
+ if (name == BuiltInName::gl_DepthRange)
+ {
+ return mVar_gl_DepthRange;
+ }
+ break;
+ }
+ case 0x7e8ab02eu:
+ {
+ if (name == BuiltInName::gl_MaxDrawBuffers)
+ {
+ return mVar_gl_MaxDrawBuffers;
+ }
+ break;
+ }
+ case 0x7e9ad799u:
+ {
+ if (name == BuiltInName::gl_MaxVertexAttribs)
+ {
+ return mVar_gl_MaxVertexAttribs;
+ }
+ break;
+ }
+ case 0x7ebaa8e5u:
+ {
+ if (name == BuiltInName::gl_MaxTextureImageUnits)
+ {
+ return mVar_gl_MaxTextureImageUnits;
+ }
+ break;
+ }
+ case 0x7ebeff64u:
+ {
+ if (name == BuiltInName::gl_DepthRangeParameters)
+ {
+ return mVar_gl_DepthRangeParameters;
+ }
+ break;
+ }
+ case 0x7ed35151u:
+ {
+ if (name == BuiltInName::gl_MaxVertexUniformVectors)
+ {
+ return mVar_gl_MaxVertexUniformVectors;
+ }
+ break;
+ }
+ case 0x7ee45ba1u:
+ {
+ if (name == BuiltInName::gl_MaxFragmentUniformVectors)
+ {
+ return mVar_gl_MaxFragmentUniformVectors;
+ }
+ break;
+ }
+ case 0x7eea039au:
+ {
+ if (name == BuiltInName::gl_MaxVertexTextureImageUnits)
+ {
+ return mVar_gl_MaxVertexTextureImageUnits;
+ }
+ break;
+ }
+ case 0x7ef1e608u:
+ {
+ if (name == BuiltInName::gl_MaxDualSourceDrawBuffersEXT)
+ {
+ return mVar_gl_MaxDualSourceDrawBuffersEXT;
+ }
+ break;
+ }
+ case 0x7ef84293u:
+ {
+ if (name == BuiltInName::gl_MaxCombinedTextureImageUnits)
+ {
+ return mVar_gl_MaxCombinedTextureImageUnits;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e64c010u:
+ {
+ if (name == BuiltInName::gl_FragCoord)
+ {
+ return &BuiltInVariable::kVar_gl_FragCoord;
+ }
+ break;
+ }
+ case 0x7e6c2088u:
+ {
+ if (name == BuiltInName::gl_PointCoord)
+ {
+ return &BuiltInVariable::kVar_gl_PointCoord;
+ }
+ break;
+ }
+ case 0x7e73011eu:
+ {
+ if (name == BuiltInName::gl_FrontFacing)
+ {
+ return &BuiltInVariable::kVar_gl_FrontFacing;
+ }
+ break;
+ }
+ }
+ }
+ if (mShaderType == GL_VERTEX_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e580bc5u:
+ {
+ if (name == BuiltInName::gl_Position)
+ {
+ return &BuiltInVariable::kVar_gl_Position;
+ }
+ break;
+ }
+ case 0x7e63931cu:
+ {
+ if (name == BuiltInName::gl_PointSize)
+ {
+ return &BuiltInVariable::kVar_gl_PointSize;
+ }
+ break;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const UnmangledBuiltIn *TSymbolTable::getUnmangledBuiltInForShaderVersion(
+ const ImmutableString &name,
+ int shaderVersion)
+{
+ if (name.length() > 26)
+ {
+ return nullptr;
+ }
+ uint32_t nameHash = name.mangledNameHash();
+ if (shaderVersion >= 310)
+ {
+ switch (nameHash)
+ {
+ case 0x7e2c727fu:
+ {
+ if (name == BuiltInName::ldexp)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2d0692u:
+ {
+ if (name == BuiltInName::frexp)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e399596u:
+ {
+ if (name == BuiltInName::findLSB)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e3bdf3fu:
+ {
+ if (name == BuiltInName::findMSB)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e41283bu:
+ {
+ if (name == BuiltInName::bitCount)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4690b3u:
+ {
+ if (name == BuiltInName::atomicOr)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4800e3u:
+ {
+ if (name == BuiltInName::atomicAdd)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4893a8u:
+ {
+ if (name == BuiltInName::atomicMax)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e49061fu:
+ {
+ if (name == BuiltInName::atomicMin)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4a45b6u:
+ {
+ if (name == BuiltInName::imageLoad)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4b6656u:
+ {
+ if (name == BuiltInName::imageSize)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4dea77u:
+ {
+ if (name == BuiltInName::atomicXor)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4e5094u:
+ {
+ if (name == BuiltInName::uaddCarry)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4f21aeu:
+ {
+ if (name == BuiltInName::atomicAnd)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5237e1u:
+ {
+ if (name == BuiltInName::texelFetch)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5276efu:
+ {
+ if (name == BuiltInName::imageStore)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e55de86u:
+ {
+ if (name == BuiltInName::usubBorrow)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5e217eu:
+ {
+ if (name == BuiltInName::textureSize)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6273e5u:
+ {
+ if (name == BuiltInName::packSnorm4x8)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e62a9a0u:
+ {
+ if (name == BuiltInName::imulExtended)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e657e29u:
+ {
+ if (name == BuiltInName::packUnorm4x8)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6746f4u:
+ {
+ if (name == BuiltInName::umulExtended)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e69d0dbu:
+ {
+ if (name == BuiltInName::memoryBarrier)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6d0f32u:
+ {
+ if (name == BuiltInName::textureGather)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6e00a5u:
+ {
+ if (name == BuiltInName::atomicCounter)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e71963eu:
+ {
+ if (name == BuiltInName::unpackUnorm4x8)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e73f1d1u:
+ {
+ if (name == BuiltInName::unpackSnorm4x8)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e75cfb1u:
+ {
+ if (name == BuiltInName::atomicExchange)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e778ffcu:
+ {
+ if (name == BuiltInName::atomicCompSwap)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e77c121u:
+ {
+ if (name == BuiltInName::bitfieldInsert)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e7f2cb2u:
+ {
+ if (name == BuiltInName::bitfieldReverse)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e7fa0c1u:
+ {
+ if (name == BuiltInName::bitfieldExtract)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e9269d7u:
+ {
+ if (name == BuiltInName::memoryBarrierImage)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e9b7f32u:
+ {
+ if (name == BuiltInName::memoryBarrierBuffer)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e9d8ad9u:
+ {
+ if (name == BuiltInName::textureGatherOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7eb323ddu:
+ {
+ if (name == BuiltInName::atomicCounterIncrement)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7eb6aed0u:
+ {
+ if (name == BuiltInName::atomicCounterDecrement)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7ed5b06bu:
+ {
+ if (name == BuiltInName::memoryBarrierAtomicCounter)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_COMPUTE_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e39f4e9u:
+ {
+ if (name == BuiltInName::barrier)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e93c6b9u:
+ {
+ if (name == BuiltInName::groupMemoryBarrier)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e9f4b19u:
+ {
+ if (name == BuiltInName::memoryBarrierShared)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ }
+ }
+ if (mShaderType == GL_GEOMETRY_SHADER_EXT)
+ {
+ switch (nameHash)
+ {
+ case 0x7e55adc2u:
+ {
+ if (name == BuiltInName::EmitVertex)
+ {
+ return &UnmangledBuiltIns::EXT_geometry_shader;
+ }
+ break;
+ }
+ case 0x7e65b2cau:
+ {
+ if (name == BuiltInName::EndPrimitive)
+ {
+ return &UnmangledBuiltIns::EXT_geometry_shader;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (shaderVersion >= 300)
+ {
+ switch (nameHash)
+ {
+ case 0x7e19507bu:
+ {
+ if (name == BuiltInName::abs)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1e492du:
+ {
+ if (name == BuiltInName::min)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1ea71bu:
+ {
+ if (name == BuiltInName::mix)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1ebe0eu:
+ {
+ if (name == BuiltInName::max)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e205c92u:
+ {
+ if (name == BuiltInName::tanh)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e206e40u:
+ {
+ if (name == BuiltInName::sign)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e209eadu:
+ {
+ if (name == BuiltInName::sinh)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e274509u:
+ {
+ if (name == BuiltInName::modf)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e27a4feu:
+ {
+ if (name == BuiltInName::cosh)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e28294fu:
+ {
+ if (name == BuiltInName::atanh)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2924b8u:
+ {
+ if (name == BuiltInName::isinf)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e297347u:
+ {
+ if (name == BuiltInName::equal)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2a7a64u:
+ {
+ if (name == BuiltInName::round)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2d5dcbu:
+ {
+ if (name == BuiltInName::clamp)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2d8df4u:
+ {
+ if (name == BuiltInName::isnan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2dcbc6u:
+ {
+ if (name == BuiltInName::asinh)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2eab16u:
+ {
+ if (name == BuiltInName::trunc)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2f67c3u:
+ {
+ if (name == BuiltInName::acosh)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e39ebd7u:
+ {
+ if (name == BuiltInName::texture)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e3d828cu:
+ {
+ if (name == BuiltInName::inverse)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e403a20u:
+ {
+ if (name == BuiltInName::lessThan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e413f93u:
+ {
+ if (name == BuiltInName::notEqual)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4d27c2u:
+ {
+ if (name == BuiltInName::rgb_2_yuv)
+ {
+ return &UnmangledBuiltIns::EXT_YUV_target;
+ }
+ break;
+ }
+ case 0x7e4d323bu:
+ {
+ if (name == BuiltInName::roundEven)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4e024cu:
+ {
+ if (name == BuiltInName::transpose)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4e33aeu:
+ {
+ if (name == BuiltInName::yuv_2_rgb)
+ {
+ return &UnmangledBuiltIns::EXT_YUV_target;
+ }
+ break;
+ }
+ case 0x7e501e0cu:
+ {
+ if (name == BuiltInName::textureLod)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5237e1u:
+ {
+ if (name == BuiltInName::texelFetch)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e582ffcu:
+ {
+ if (name == BuiltInName::greaterThan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e599347u:
+ {
+ if (name == BuiltInName::textureGrad)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5ba531u:
+ {
+ if (name == BuiltInName::determinant)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5caafbu:
+ {
+ if (name == BuiltInName::textureProj)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5e217eu:
+ {
+ if (name == BuiltInName::textureSize)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e62daa3u:
+ {
+ if (name == BuiltInName::packHalf2x16)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e646b9bu:
+ {
+ if (name == BuiltInName::outerProduct)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e683586u:
+ {
+ if (name == BuiltInName::lessThanEqual)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6a013du:
+ {
+ if (name == BuiltInName::packSnorm2x16)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6b72b8u:
+ {
+ if (name == BuiltInName::packUnorm2x16)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e6c5187u:
+ {
+ if (name == BuiltInName::textureOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e715db5u:
+ {
+ if (name == BuiltInName::unpackHalf2x16)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e759618u:
+ {
+ if (name == BuiltInName::floatBitsToInt)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e75ae2fu:
+ {
+ if (name == BuiltInName::textureProjLod)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e76bea7u:
+ {
+ if (name == BuiltInName::matrixCompMult)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e77fc97u:
+ {
+ if (name == BuiltInName::intBitsToFloat)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e792d39u:
+ {
+ if (name == BuiltInName::unpackUnorm2x16)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e7b6a0eu:
+ {
+ if (name == BuiltInName::unpackSnorm2x16)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e7bc1fdu:
+ {
+ if (name == BuiltInName::textureProjGrad)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e7e0e81u:
+ {
+ if (name == BuiltInName::uintBitsToFloat)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e7e5132u:
+ {
+ if (name == BuiltInName::floatBitsToUint)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e80919du:
+ {
+ if (name == BuiltInName::texelFetchOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e81c71au:
+ {
+ if (name == BuiltInName::textureLodOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e876cccu:
+ {
+ if (name == BuiltInName::greaterThanEqual)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e8b5832u:
+ {
+ if (name == BuiltInName::textureGradOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e8d2d2du:
+ {
+ if (name == BuiltInName::textureProjOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7ea0be08u:
+ {
+ if (name == BuiltInName::textureProjLodOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7eac5717u:
+ {
+ if (name == BuiltInName::textureProjGradOffset)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e2624d4u:
+ {
+ if (name == BuiltInName::dFdy)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e265ea7u:
+ {
+ if (name == BuiltInName::dFdx)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e324ea1u:
+ {
+ if (name == BuiltInName::fwidth)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (shaderVersion == 100)
+ {
+ switch (nameHash)
+ {
+ case 0x7e48c50cu:
+ {
+ if (name == BuiltInName::texture2D)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5ffc48u:
+ {
+ if (name == BuiltInName::textureCube)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e69f545u:
+ {
+ if (name == BuiltInName::texture2DRect)
+ {
+ return &UnmangledBuiltIns::ARB_texture_rectangle;
+ }
+ break;
+ }
+ case 0x7e6e3735u:
+ {
+ if (name == BuiltInName::texture2DProj)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e868a22u:
+ {
+ if (name == BuiltInName::texture2DGradEXT)
+ {
+ return &UnmangledBuiltIns::EXT_shader_texture_lod;
+ }
+ break;
+ }
+ case 0x7e8b66e4u:
+ {
+ if (name == BuiltInName::texture2DRectProj)
+ {
+ return &UnmangledBuiltIns::ARB_texture_rectangle;
+ }
+ break;
+ }
+ case 0x7e90fa5bu:
+ {
+ if (name == BuiltInName::textureCubeGradEXT)
+ {
+ return &UnmangledBuiltIns::EXT_shader_texture_lod;
+ }
+ break;
+ }
+ case 0x7ea20b8fu:
+ {
+ if (name == BuiltInName::texture2DProjGradEXT)
+ {
+ return &UnmangledBuiltIns::EXT_shader_texture_lod;
+ }
+ break;
+ }
+ }
+ if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e2624d4u:
+ {
+ if (name == BuiltInName::dFdyExt)
+ {
+ return &UnmangledBuiltIns::OES_standard_derivatives;
+ }
+ break;
+ }
+ case 0x7e265ea7u:
+ {
+ if (name == BuiltInName::dFdxExt)
+ {
+ return &UnmangledBuiltIns::OES_standard_derivatives;
+ }
+ break;
+ }
+ case 0x7e324ea1u:
+ {
+ if (name == BuiltInName::fwidthExt)
+ {
+ return &UnmangledBuiltIns::OES_standard_derivatives;
+ }
+ break;
+ }
+ case 0x7e4db1c8u:
+ {
+ if (name == BuiltInName::texture3D)
+ {
+ return &UnmangledBuiltIns::OES_texture_3D;
+ }
+ break;
+ }
+ case 0x7e63c1d1u:
+ {
+ if (name == BuiltInName::texture3DLod)
+ {
+ return &UnmangledBuiltIns::OES_texture_3D;
+ }
+ break;
+ }
+ case 0x7e687e40u:
+ {
+ if (name == BuiltInName::texture3DProj)
+ {
+ return &UnmangledBuiltIns::OES_texture_3D;
+ }
+ break;
+ }
+ case 0x7e7b843eu:
+ {
+ if (name == BuiltInName::texture2DLodEXT)
+ {
+ return &UnmangledBuiltIns::EXT_shader_texture_lod;
+ }
+ break;
+ }
+ case 0x7e85692eu:
+ {
+ if (name == BuiltInName::texture3DProjLod)
+ {
+ return &UnmangledBuiltIns::OES_texture_3D;
+ }
+ break;
+ }
+ case 0x7e8b81cau:
+ {
+ if (name == BuiltInName::textureCubeLodEXT)
+ {
+ return &UnmangledBuiltIns::EXT_shader_texture_lod;
+ }
+ break;
+ }
+ case 0x7e9ddba0u:
+ {
+ if (name == BuiltInName::texture2DProjLodEXT)
+ {
+ return &UnmangledBuiltIns::EXT_shader_texture_lod;
+ }
+ break;
+ }
+ }
+ }
+ if (mShaderType == GL_VERTEX_SHADER)
+ {
+ switch (nameHash)
+ {
+ case 0x7e67c7ceu:
+ {
+ if (name == BuiltInName::texture2DLod)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e758eddu:
+ {
+ if (name == BuiltInName::textureCubeLod)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e819b90u:
+ {
+ if (name == BuiltInName::texture2DProjLod)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ }
+ }
+ }
+ switch (nameHash)
+ {
+ case 0x7e1892eeu:
+ {
+ if (name == BuiltInName::all)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e19507bu:
+ {
+ if (name == BuiltInName::abs)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e195106u:
+ {
+ if (name == BuiltInName::notFunc)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e197102u:
+ {
+ if (name == BuiltInName::any)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e19ebdbu:
+ {
+ if (name == BuiltInName::log)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1acb4eu:
+ {
+ if (name == BuiltInName::pow)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1b921cu:
+ {
+ if (name == BuiltInName::exp)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1cf321u:
+ {
+ if (name == BuiltInName::tan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1e492du:
+ {
+ if (name == BuiltInName::min)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1e8464u:
+ {
+ if (name == BuiltInName::dot)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1ea71bu:
+ {
+ if (name == BuiltInName::mix)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1ebe0eu:
+ {
+ if (name == BuiltInName::max)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1eee70u:
+ {
+ if (name == BuiltInName::mod)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1f0bccu:
+ {
+ if (name == BuiltInName::sin)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e1fdef3u:
+ {
+ if (name == BuiltInName::cos)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e203979u:
+ {
+ if (name == BuiltInName::atan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e206e40u:
+ {
+ if (name == BuiltInName::sign)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e209ec1u:
+ {
+ if (name == BuiltInName::log2)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e21ff11u:
+ {
+ if (name == BuiltInName::acos)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e23152fu:
+ {
+ if (name == BuiltInName::ceil)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e23f4beu:
+ {
+ if (name == BuiltInName::sqrt)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e24bcdbu:
+ {
+ if (name == BuiltInName::exp2)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e26202fu:
+ {
+ if (name == BuiltInName::step)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e27ebd5u:
+ {
+ if (name == BuiltInName::asin)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e295733u:
+ {
+ if (name == BuiltInName::cross)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e297347u:
+ {
+ if (name == BuiltInName::equal)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2d5dcbu:
+ {
+ if (name == BuiltInName::clamp)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2dcb25u:
+ {
+ if (name == BuiltInName::floor)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e2f6df3u:
+ {
+ if (name == BuiltInName::fract)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e340894u:
+ {
+ if (name == BuiltInName::length)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e38233fu:
+ {
+ if (name == BuiltInName::refract)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e3c3cb3u:
+ {
+ if (name == BuiltInName::radians)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e3c8e91u:
+ {
+ if (name == BuiltInName::reflect)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e3d784cu:
+ {
+ if (name == BuiltInName::degrees)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e403a20u:
+ {
+ if (name == BuiltInName::lessThan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e413f93u:
+ {
+ if (name == BuiltInName::notEqual)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4161fau:
+ {
+ if (name == BuiltInName::distance)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e4e7aa5u:
+ {
+ if (name == BuiltInName::normalize)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e54a2cfu:
+ {
+ if (name == BuiltInName::smoothstep)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e582ffcu:
+ {
+ if (name == BuiltInName::greaterThan)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5ae14bu:
+ {
+ if (name == BuiltInName::faceforward)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e5f4d0fu:
+ {
+ if (name == BuiltInName::inversesqrt)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e683586u:
+ {
+ if (name == BuiltInName::lessThanEqual)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e76bea7u:
+ {
+ if (name == BuiltInName::matrixCompMult)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ case 0x7e876cccu:
+ {
+ if (name == BuiltInName::greaterThanEqual)
+ {
+ return &UnmangledBuiltIns::UNDEFINED;
+ }
+ break;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h
new file mode 100644
index 0000000000..2168743e29
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h
@@ -0,0 +1,78 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_builtin_symbols.py using data from builtin_variables.json and
+// builtin_function_declarations.txt.
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SymbolTable_autogen.h:
+// Autogenerated member variables of TSymbolTable.
+
+#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_
+#define COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_
+
+namespace sh
+{
+
+class TSymbolTableBase
+{
+ protected:
+ TSymbolTableBase() = default;
+ TStructure *mVar_gl_DepthRangeParameters = nullptr;
+ TVariable *mVar_gl_DepthRange = nullptr;
+ TVariable *mVar_gl_MaxVertexAttribs = nullptr;
+ TVariable *mVar_gl_MaxVertexUniformVectors = nullptr;
+ TVariable *mVar_gl_MaxVertexTextureImageUnits = nullptr;
+ TVariable *mVar_gl_MaxCombinedTextureImageUnits = nullptr;
+ TVariable *mVar_gl_MaxTextureImageUnits = nullptr;
+ TVariable *mVar_gl_MaxFragmentUniformVectors = nullptr;
+ TVariable *mVar_gl_MaxVaryingVectors = nullptr;
+ TVariable *mVar_gl_MaxDrawBuffers = nullptr;
+ TVariable *mVar_gl_MaxDualSourceDrawBuffersEXT = nullptr;
+ TVariable *mVar_gl_MaxVertexOutputVectors = nullptr;
+ TVariable *mVar_gl_MaxFragmentInputVectors = nullptr;
+ TVariable *mVar_gl_MinProgramTexelOffset = nullptr;
+ TVariable *mVar_gl_MaxProgramTexelOffset = nullptr;
+ TVariable *mVar_gl_MaxImageUnits = nullptr;
+ TVariable *mVar_gl_MaxVertexImageUniforms = nullptr;
+ TVariable *mVar_gl_MaxFragmentImageUniforms = nullptr;
+ TVariable *mVar_gl_MaxComputeImageUniforms = nullptr;
+ TVariable *mVar_gl_MaxCombinedImageUniforms = nullptr;
+ TVariable *mVar_gl_MaxCombinedShaderOutputResources = nullptr;
+ TVariable *mVar_gl_MaxComputeWorkGroupCount = nullptr;
+ TVariable *mVar_gl_MaxComputeWorkGroupSize = nullptr;
+ TVariable *mVar_gl_MaxComputeUniformComponents = nullptr;
+ TVariable *mVar_gl_MaxComputeTextureImageUnits = nullptr;
+ TVariable *mVar_gl_MaxComputeAtomicCounters = nullptr;
+ TVariable *mVar_gl_MaxComputeAtomicCounterBuffers = nullptr;
+ TVariable *mVar_gl_MaxVertexAtomicCounters = nullptr;
+ TVariable *mVar_gl_MaxFragmentAtomicCounters = nullptr;
+ TVariable *mVar_gl_MaxCombinedAtomicCounters = nullptr;
+ TVariable *mVar_gl_MaxAtomicCounterBindings = nullptr;
+ TVariable *mVar_gl_MaxVertexAtomicCounterBuffers = nullptr;
+ TVariable *mVar_gl_MaxFragmentAtomicCounterBuffers = nullptr;
+ TVariable *mVar_gl_MaxCombinedAtomicCounterBuffers = nullptr;
+ TVariable *mVar_gl_MaxAtomicCounterBufferSize = nullptr;
+ TVariable *mVar_gl_MaxGeometryInputComponents = nullptr;
+ TVariable *mVar_gl_MaxGeometryOutputComponents = nullptr;
+ TVariable *mVar_gl_MaxGeometryImageUniforms = nullptr;
+ TVariable *mVar_gl_MaxGeometryTextureImageUnits = nullptr;
+ TVariable *mVar_gl_MaxGeometryOutputVertices = nullptr;
+ TVariable *mVar_gl_MaxGeometryTotalOutputComponents = nullptr;
+ TVariable *mVar_gl_MaxGeometryUniformComponents = nullptr;
+ TVariable *mVar_gl_MaxGeometryAtomicCounters = nullptr;
+ TVariable *mVar_gl_MaxGeometryAtomicCounterBuffers = nullptr;
+ TVariable *mVar_gl_FragData = nullptr;
+ TVariable *mVar_gl_SecondaryFragDataEXT = nullptr;
+ TVariable *mVar_gl_FragDepthEXT = nullptr;
+ TVariable *mVar_gl_LastFragData = nullptr;
+ TVariable *mVar_gl_LastFragDataNV = nullptr;
+ TInterfaceBlock *mVar_gl_PerVertex = nullptr;
+ TVariable *mVar_gl_in = nullptr;
+ TVariable *mVar_gl_PositionGS = nullptr;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp
new file mode 100644
index 0000000000..3aeb80b708
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SymbolUniqueId.cpp: Encapsulates a unique id for a symbol.
+
+#include "compiler/translator/SymbolUniqueId.h"
+
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+TSymbolUniqueId::TSymbolUniqueId(TSymbolTable *symbolTable) : mId(symbolTable->nextUniqueIdValue())
+{}
+
+TSymbolUniqueId::TSymbolUniqueId(const TSymbol &symbol) : mId(symbol.uniqueId().get()) {}
+
+TSymbolUniqueId &TSymbolUniqueId::operator=(const TSymbolUniqueId &) = default;
+
+bool TSymbolUniqueId::operator==(const TSymbolUniqueId &other) const
+{
+ return mId == other.mId;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h
new file mode 100644
index 0000000000..7d0979e266
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SymbolUniqueId.h: Encapsulates a unique id for a symbol.
+
+#ifndef COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_
+#define COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_
+
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+
+class TSymbolTable;
+class TSymbol;
+
+class TSymbolUniqueId
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ explicit TSymbolUniqueId(const TSymbol &symbol);
+ constexpr TSymbolUniqueId(const TSymbolUniqueId &) = default;
+ TSymbolUniqueId &operator =(const TSymbolUniqueId &);
+ bool operator==(const TSymbolUniqueId &) const;
+
+ constexpr int get() const { return mId; }
+
+ private:
+ friend class TSymbolTable;
+ explicit TSymbolUniqueId(TSymbolTable *symbolTable);
+
+ friend class BuiltInId;
+ constexpr TSymbolUniqueId(int staticId) : mId(staticId) {}
+
+ int mId;
+};
+
+enum class SymbolType
+{
+ BuiltIn,
+ UserDefined,
+ AngleInternal,
+ Empty // Meaning symbol without a name.
+};
+
+enum class SymbolClass
+{
+ Function,
+ Variable,
+ Struct,
+ InterfaceBlock
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp
new file mode 100644
index 0000000000..6ef502587c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -0,0 +1,1554 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL
+// output. Some of the implementations are straightforward and just call the HLSL equivalent of the
+// ESSL texture function, others do more work to emulate ESSL texture sampling or size query
+// behavior.
+//
+
+#include "compiler/translator/TextureFunctionHLSL.h"
+
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/UtilsHLSL.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void OutputIntTexCoordWrap(TInfoSinkBase &out,
+ const char *wrapMode,
+ const char *size,
+ const ImmutableString &texCoord,
+ const char *texCoordOffset,
+ const char *texCoordOutName)
+{
+ // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim
+ // but rather use equivalent formulas that map better to HLSL.
+ out << "int " << texCoordOutName << ";\n";
+ out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset
+ << ") / " << size << ";\n";
+ out << "bool " << texCoordOutName << "UseBorderColor = false;\n";
+
+ // CLAMP_TO_EDGE
+ out << "if (" << wrapMode << " == 0)\n";
+ out << "{\n";
+ out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
+ << "Offset)), 0, int(" << size << ") - 1);\n";
+ out << "}\n";
+
+ // CLAMP_TO_BORDER
+ out << "else if (" << wrapMode << " == 3)\n";
+ out << "{\n";
+ out << " int texCoordInt = int(floor(" << size << " * " << texCoordOutName << "Offset));\n";
+ out << " " << texCoordOutName << " = clamp(texCoordInt, 0, int(" << size << ") - 1);\n";
+ out << " " << texCoordOutName << "UseBorderColor = (texCoordInt != " << texCoordOutName
+ << ");\n";
+ out << "}\n";
+
+ // MIRRORED_REPEAT
+ out << "else if (" << wrapMode << " == 2)\n";
+ out << "{\n";
+ out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
+ << "Offset) * 0.5) * 2.0 - 1.0);\n";
+ out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
+ out << "}\n";
+
+ // REPEAT
+ out << "else\n";
+ out << "{\n";
+ out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
+ << "Offset)));\n";
+ out << "}\n";
+}
+
+void OutputIntTexCoordWraps(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ ImmutableString *texCoordX,
+ ImmutableString *texCoordY,
+ ImmutableString *texCoordZ)
+{
+ // Convert from normalized floating-point to integer
+ out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
+ if (textureFunction.offset)
+ {
+ OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
+ }
+ else
+ {
+ OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
+ }
+ *texCoordX = ImmutableString("tix");
+ out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
+ if (textureFunction.offset)
+ {
+ OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
+ }
+ else
+ {
+ OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
+ }
+ *texCoordY = ImmutableString("tiy");
+
+ bool tizAvailable = false;
+
+ if (IsSamplerArray(textureFunction.sampler))
+ {
+ *texCoordZ = ImmutableString("int(max(0, min(layers - 1, floor(0.5 + t.z))))");
+ }
+ else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
+ {
+ out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
+ if (textureFunction.offset)
+ {
+ OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
+ }
+ else
+ {
+ OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
+ }
+ *texCoordZ = ImmutableString("tiz");
+ tizAvailable = true;
+ }
+
+ out << "bool useBorderColor = tixUseBorderColor || tiyUseBorderColor"
+ << (tizAvailable ? " || tizUseBorderColor" : "") << ";\n";
+}
+
+void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ImmutableString &textureReference,
+ const ImmutableString &samplerReference)
+{
+ out << textureReference;
+ if (IsIntegerSampler(textureFunction.sampler) ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ out << ".Load(";
+ return;
+ }
+
+ if (IsShadowSampler(textureFunction.sampler))
+ {
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ out << ".SampleCmp(";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ case TextureFunctionHLSL::TextureFunction::GRAD:
+ out << ".SampleCmpLevelZero(";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ out << ".Sample(";
+ break;
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ out << ".SampleBias(";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ out << ".SampleLevel(";
+ break;
+ case TextureFunctionHLSL::TextureFunction::GRAD:
+ out << ".SampleGrad(";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ out << samplerReference << ", ";
+}
+
+const char *GetSamplerCoordinateTypeString(
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ int hlslCoords)
+{
+ // Gather[Red|Green|Blue|Alpha] accepts float texture coordinates on textures in integer or
+ // unsigned integer formats.
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-to-gather
+ if ((IsIntegerSampler(textureFunction.sampler) &&
+ textureFunction.method != TextureFunctionHLSL::TextureFunction::GATHER) ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ switch (hlslCoords)
+ {
+ case 2:
+ if (IsSampler2DMS(textureFunction.sampler))
+ {
+ return "int2";
+ }
+ else
+ {
+ return "int3";
+ }
+ case 3:
+ if (IsSampler2DMSArray(textureFunction.sampler))
+ {
+ return "int3";
+ }
+ else
+ {
+ return "int4";
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ switch (hlslCoords)
+ {
+ case 2:
+ return "float2";
+ case 3:
+ return "float3";
+ case 4:
+ return "float4";
+ default:
+ UNREACHABLE();
+ }
+ }
+ return "";
+}
+
+int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
+ ShShaderOutput outputType)
+{
+ if (outputType == SH_HLSL_3_0_OUTPUT)
+ {
+ int hlslCoords = 2;
+ switch (textureFunction.sampler)
+ {
+ case EbtSampler2D:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DMS:
+ hlslCoords = 2;
+ break;
+ case EbtSamplerCube:
+ hlslCoords = 3;
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ case TextureFunctionHLSL::TextureFunction::GRAD:
+ return hlslCoords;
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ return 4;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
+ IsSamplerCube(textureFunction.sampler))
+ {
+ return 3;
+ }
+ ASSERT(IsSampler2D(textureFunction.sampler));
+ return 2;
+ }
+ return 0;
+}
+
+void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType)
+{
+ if (outputType == SH_HLSL_3_0_OUTPUT)
+ {
+ switch (textureFunction.sampler)
+ {
+ case EbtSampler2D:
+ case EbtSamplerExternalOES:
+ out << "sampler2D s";
+ break;
+ case EbtSamplerCube:
+ out << "samplerCUBE s";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ out << TextureString(textureFunction.sampler) << " x, "
+ << SamplerString(textureFunction.sampler) << " s";
+ }
+ else
+ {
+ ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
+ // A bug in the D3D compiler causes some nested sampling operations to fail.
+ // See http://anglebug.com/1923
+ // TODO(jmadill): Reinstate the const keyword when possible.
+ out << /*"const"*/ "uint samplerIndex";
+ }
+ }
+
+ if (textureFunction.method ==
+ TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
+ {
+ switch (textureFunction.coords)
+ {
+ case 2:
+ out << ", int2 t";
+ break;
+ case 3:
+ out << ", int3 t";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else // Floating-point coordinates (except textureSize)
+ {
+ switch (textureFunction.coords)
+ {
+ case 0:
+ break; // textureSize(gSampler2DMS sampler)
+ case 1:
+ out << ", int lod";
+ break; // textureSize()
+ case 2:
+ out << ", float2 t";
+ break;
+ case 3:
+ out << ", float3 t";
+ break;
+ case 4:
+ out << ", float4 t";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ switch (textureFunction.sampler)
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ case EbtSamplerExternalOES:
+ out << ", float2 ddx, float2 ddy";
+ break;
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCubeShadow:
+ out << ", float3 ddx, float3 ddy";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ break;
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ break; // Comes after the offset parameter
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ out << ", float lod";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ break; // Comes after the offset parameter
+ case TextureFunctionHLSL::TextureFunction::SIZE:
+ break;
+ case TextureFunctionHLSL::TextureFunction::FETCH:
+ if (IsSampler2DMS(textureFunction.sampler) ||
+ IsSampler2DMSArray(textureFunction.sampler))
+ out << ", int index";
+ else
+ out << ", int mip";
+ break;
+ case TextureFunctionHLSL::TextureFunction::GRAD:
+ break;
+ case TextureFunctionHLSL::TextureFunction::GATHER:
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
+ IsShadowSampler(textureFunction.sampler))
+ {
+ out << ", float refZ";
+ }
+
+ if (textureFunction.offset)
+ {
+ switch (textureFunction.sampler)
+ {
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ out << ", int3 offset";
+ break;
+ case EbtSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2D:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ case EbtSamplerExternalOES:
+ out << ", int2 offset";
+ break;
+ default:
+ // Offset is not supported for multisampled textures.
+ UNREACHABLE();
+ }
+ }
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
+ {
+ out << ", float bias";
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
+ !IsShadowSampler(textureFunction.sampler))
+ {
+ out << ", int comp = 0";
+ }
+}
+
+void GetTextureReference(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType,
+ ImmutableString *textureReference,
+ ImmutableString *samplerReference)
+{
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ static const ImmutableString kTexturesStr("textures");
+ static const ImmutableString kSamplersStr("samplers");
+ static const ImmutableString kSamplerIndexStr("[samplerIndex]");
+ static const ImmutableString kTextureIndexStr("[textureIndex]");
+ static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
+ ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
+
+ if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
+ {
+ ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+ kSamplerIndexStr.length());
+ textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
+ *textureReference = textureRefBuilder;
+ ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+ kSamplerIndexStr.length());
+ samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
+ *samplerReference = samplerRefBuilder;
+ }
+ else
+ {
+ out << " const uint textureIndex = samplerIndex - textureIndexOffset"
+ << suffix.data() << ";\n";
+ ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+ kTextureIndexStr.length());
+ textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
+ *textureReference = textureRefBuilder;
+
+ out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
+ << suffix.data() << ";\n";
+ ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+ kSamplerArrayIndexStr.length());
+ samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
+ *samplerReference = samplerRefBuilder;
+ }
+ }
+ else
+ {
+ *textureReference = ImmutableString("x");
+ *samplerReference = ImmutableString("s");
+ }
+}
+
+void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ImmutableString &textureReference,
+ bool getDimensionsIgnoresBaseLevel)
+{
+ if (IsSampler2DMS(textureFunction.sampler))
+ {
+ out << " uint width; uint height; uint samples;\n"
+ << " " << textureReference << ".GetDimensions(width, height, samples);\n";
+ }
+ else if (IsSampler2DMSArray(textureFunction.sampler))
+ {
+ out << " uint width; uint height; uint depth; uint samples;\n"
+ << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
+ }
+ else
+ {
+ if (getDimensionsIgnoresBaseLevel)
+ {
+ out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
+ }
+ else
+ {
+ out << " int baseLevel = 0;\n";
+ }
+
+ if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
+ (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
+ {
+ // "depth" stores either the number of layers in an array texture or 3D depth
+ out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
+ << " " << textureReference
+ << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
+ << " width = max(width >> lod, 1);\n"
+ << " height = max(height >> lod, 1);\n";
+
+ if (!IsSamplerArray(textureFunction.sampler))
+ {
+ out << " depth = max(depth >> lod, 1);\n";
+ }
+ }
+ else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
+ {
+ out << " uint width; uint height; uint numberOfLevels;\n"
+ << " " << textureReference
+ << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
+ << " width = max(width >> lod, 1);\n"
+ << " height = max(height >> lod, 1);\n";
+ }
+ else
+ UNREACHABLE();
+ }
+
+ if (strcmp(textureFunction.getReturnType(), "int3") == 0)
+ {
+ out << " return int3(width, height, depth);\n";
+ }
+ else
+ {
+ out << " return int2(width, height);\n";
+ }
+}
+
+void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
+ ImmutableString *texCoordX,
+ ImmutableString *texCoordY,
+ ImmutableString *texCoordZ)
+{
+ if (textureFunction.proj)
+ {
+ ImmutableString proj("");
+ switch (textureFunction.coords)
+ {
+ case 3:
+ proj = ImmutableString(" / t.z");
+ break;
+ case 4:
+ proj = ImmutableString(" / t.w");
+ break;
+ default:
+ UNREACHABLE();
+ }
+ ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
+ texCoordXBuilder << '(' << *texCoordX << proj << ')';
+ *texCoordX = texCoordXBuilder;
+ ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
+ texCoordYBuilder << '(' << *texCoordY << proj << ')';
+ *texCoordY = texCoordYBuilder;
+ ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
+ texCoordZBuilder << '(' << *texCoordZ << proj << ')';
+ *texCoordZ = texCoordZBuilder;
+ }
+}
+
+void OutputIntegerTextureSampleFunctionComputations(
+ TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType,
+ const ImmutableString &textureReference,
+ ImmutableString *texCoordX,
+ ImmutableString *texCoordY,
+ ImmutableString *texCoordZ,
+ bool getDimensionsIgnoresBaseLevel)
+{
+ if (!IsIntegerSampler(textureFunction.sampler))
+ {
+ return;
+ }
+
+ if (getDimensionsIgnoresBaseLevel)
+ {
+ out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
+ }
+ else
+ {
+ out << " int baseLevel = 0;\n";
+ }
+
+ if (IsSamplerCube(textureFunction.sampler))
+ {
+ out << " float width; float height; float layers; float levels;\n";
+
+ out << " uint mip = 0;\n";
+
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
+
+ out << " bool xMajor = abs(t.x) >= abs(t.y) && abs(t.x) >= abs(t.z);\n";
+ out << " bool yMajor = abs(t.y) >= abs(t.z) && abs(t.y) > abs(t.x);\n";
+ out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
+ out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
+ "(zMajor && t.z < 0.0f);\n";
+
+ // FACE_POSITIVE_X = 000b
+ // FACE_NEGATIVE_X = 001b
+ // FACE_POSITIVE_Y = 010b
+ // FACE_NEGATIVE_Y = 011b
+ // FACE_POSITIVE_Z = 100b
+ // FACE_NEGATIVE_Z = 101b
+ out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
+
+ out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
+ out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
+ out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
+
+ out << " float3 r = any(t) ? t : float3(1, 0, 0);\n";
+ out << " t.x = (u * 0.5f / m) + 0.5f;\n";
+ out << " t.y = (v * 0.5f / m) + 0.5f;\n";
+
+ // Mip level computation.
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
+ {
+ // We would like to calculate tha maximum of how many texels we move in the major
+ // face's texture as we move across the screen in any direction. Namely, we want the
+ // length of the directional derivative of the function p (defined below), maximized
+ // over screen space directions. (For short: we want the norm of Dp.) For
+ // simplicity, assume that z-axis is the major axis. By symmetry, we can assume that
+ // the positive z direction is major. (The calculated value will be the same even if
+ // this is false.) Let r denote the function from screen position to cube texture
+ // coordinates. Then p can be written as p = s . P . r, where P(r) = (r.x, r.y)/r.z
+ // is the projection onto the major cube face, and s = diag(width, height)/2. (s
+ // linearly maps from the cube face into texture space, so that p(r) is in units of
+ // texels.) The derivative is
+ // Dp(r) = s |1 0 -r.x/r.z|
+ // |0 1 -r.y/r.z| |ddx(r) ddy(r)| / r.z
+ // = |dot(a, ddx(r)) dot(a, ddy(r))|
+ // |dot(b, ddx(r)) dot(b, ddy(r))| / (2 r.z)
+ // where a = w * vec3(1, 0, -r.x/r.z)
+ // b = h * vec3(0, 1, -r.y/r.z)
+ // We would like to know max(L(x)) over unit vectors x, where L(x) = |Dp(r) x|^2.
+ // Since ddx(r) and ddy(r) are unknown, the best we can do is to sample L in some
+ // directions and take the maximum across the samples.
+ //
+ // Some implementations use max(L(n1), L(n2)) where n1 = vec2(1,0) and n2 =
+ // vec2(0,1).
+ //
+ // Some implementations use max(L(n1), L(n2), L(n3), L(n4)),
+ // where n3 = (n1 + n2) / |n1 + n2| = (n1 + n2)/sqrt(2)
+ // n4 = (n1 - n2) / |n1 - n2| = (n1 - n2)/sqrt(2).
+ // In other words, two samples along the diagonal screen space directions have been
+ // added, giving a strictly better estimate of the true maximum.
+ //
+ // It turns out we can get twice the sample count very cheaply.
+ // We can use the linearity of Dp(r) to get these extra samples of L cheaply in
+ // terms of the already taken samples, L(n1) and L(n2):
+ // Denoting
+ // dpx = Dp(r)n1
+ // dpy = Dp(r)n2
+ // dpxx = dot(dpx, dpx)
+ // dpyy = dot(dpy, dpy)
+ // dpxy = dot(dpx, dpy)
+ // we obtain
+ // L(n3) = |Dp(r)n1 + Dp(r)n2|^2/2 = (dpxx + dpyy)/2 + dpxy
+ // L(n4) = |Dp(r)n1 - Dp(r)n2|^2/2 = (dpxx + dpyy)/2 - dpxy
+ // max(L(n1), L(n2), L(n3), L(n4))
+ // = max(max(L(n1), L(n2)), max(L(n3), L(n4)))
+ // = max(max(dpxx, dpyy), (dpxx + dpyy)/2 + abs(dpxy))
+ // So the extra cost is: one dot, one abs, one add, one multiply-add and one max.
+ // (All scalar.)
+ //
+ // In section 3.8.10.1, the OpenGL ES 3 specification defines the "scale factor",
+ // rho. In our terminology, this definition works out to taking sqrt(max(L(n1),
+ // L(n2))). Some implementations will use this estimate, here we use the strictly
+ // better sqrt(max(L(n1), L(n2), L(n3), L(n4))), since it's not much more expensive
+ // to calculate.
+
+ // Swap coordinates such that we can assume that the positive z-axis is major, in
+ // what follows.
+ out << " float3 ddxr = xMajor ? ddx(r).yzx : yMajor ? ddx(r).zxy : ddx(r).xyz;\n"
+ " float3 ddyr = xMajor ? ddy(r).yzx : yMajor ? ddy(r).zxy : ddy(r).xyz;\n"
+ " r = xMajor ? r.yzx : yMajor ? r.zxy : r.xyz;\n";
+
+ out << " float2 s = 0.5*float2(width, height);\n"
+ " float2 dpx = s * (ddxr.xy - ddxr.z*r.xy/r.z)/r.z;\n"
+ " float2 dpy = s * (ddyr.xy - ddyr.z*r.xy/r.z)/r.z;\n"
+ " float dpxx = dot(dpx, dpx);\n;"
+ " float dpyy = dot(dpy, dpy);\n;"
+ " float dpxy = dot(dpx, dpy);\n"
+ " float ma = max(dpxx, dpyy);\n"
+ " float mb = 0.5 * (dpxx + dpyy) + abs(dpxy);\n"
+ " float mab = max(ma, mb);\n"
+ " float lod = 0.5f * log2(mab);\n";
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
+ // derivatives of P are assumed to be in the coordinate system used before
+ // texture coordinates are projected onto the appropriate cube face."
+ // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
+ // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
+ // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
+ // Determine the derivatives of u, v and m
+ out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
+ ": ddx[0]);\n"
+ " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
+ ": ddy[0]);\n"
+ " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
+ " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
+ " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
+ " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
+ // Now determine the derivatives of the face coordinates, using the
+ // derivatives calculated above.
+ // d / dx (u(x) * 0.5 / m(x) + 0.5)
+ // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
+ out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
+ " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
+ " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
+ " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
+ " float2 sizeVec = float2(width, height);\n"
+ " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
+ " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
+ // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
+ // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
+ out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
+ " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
+ " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
+ }
+ out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
+ << " " << textureReference
+ << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
+ }
+
+ // Convert from normalized floating-point to integer
+ static const ImmutableString kXPrefix("int(floor(width * frac(");
+ static const ImmutableString kYPrefix("int(floor(height * frac(");
+ static const ImmutableString kSuffix(")))");
+ ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
+ kSuffix.length());
+ texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
+ *texCoordX = texCoordXBuilder;
+ ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
+ kSuffix.length());
+ texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
+ *texCoordY = texCoordYBuilder;
+ *texCoordZ = ImmutableString("face");
+ }
+ else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ if (IsSamplerArray(textureFunction.sampler))
+ {
+ out << " float width; float height; float layers; float levels;\n";
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
+ {
+ out << " uint mip = 0;\n";
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
+ {
+ out << " uint mip = bias;\n";
+ }
+ else
+ {
+
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel, width, height, layers, levels);\n";
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
+ {
+ out << " float2 tSized = float2(t.x * width, t.y * height);\n"
+ " float dx = length(ddx(tSized));\n"
+ " float dy = length(ddy(tSized));\n"
+ " float lod = log2(max(dx, dy));\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
+ {
+ out << " lod += bias;\n";
+ }
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ out << " float2 sizeVec = float2(width, height);\n"
+ " float2 sizeDdx = ddx * sizeVec;\n"
+ " float2 sizeDdy = ddy * sizeVec;\n"
+ " float lod = log2(max(dot(sizeDdx, sizeDdx), "
+ "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
+ }
+
+ out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
+ }
+
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
+ }
+ else if (IsSampler2D(textureFunction.sampler))
+ {
+ out << " float width; float height; float levels;\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
+ {
+ out << " uint mip = 0;\n";
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
+ {
+ out << " uint mip = bias;\n";
+ }
+ else
+ {
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel, width, height, levels);\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
+ {
+ out << " float2 tSized = float2(t.x * width, t.y * height);\n"
+ " float dx = length(ddx(tSized));\n"
+ " float dy = length(ddy(tSized));\n"
+ " float lod = log2(max(dx, dy));\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
+ {
+ out << " lod += bias;\n";
+ }
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ out << " float2 sizeVec = float2(width, height);\n"
+ " float2 sizeDdx = ddx * sizeVec;\n"
+ " float2 sizeDdy = ddy * sizeVec;\n"
+ " float lod = log2(max(dot(sizeDdx, sizeDdx), "
+ "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
+ }
+
+ out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
+ }
+
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel + mip, width, height, levels);\n";
+ }
+ else if (IsSampler3D(textureFunction.sampler))
+ {
+ out << " float width; float height; float depth; float levels;\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
+ {
+ out << " uint mip = 0;\n";
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
+ {
+ out << " uint mip = bias;\n";
+ }
+ else
+ {
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel, width, height, depth, levels);\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
+ {
+ out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
+ " float dx = length(ddx(tSized));\n"
+ " float dy = length(ddy(tSized));\n"
+ " float lod = log2(max(dx, dy));\n";
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
+ {
+ out << " lod += bias;\n";
+ }
+ }
+ else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ out << " float3 sizeVec = float3(width, height, depth);\n"
+ " float3 sizeDdx = ddx * sizeVec;\n"
+ " float3 sizeDdy = ddy * sizeVec;\n"
+ " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
+ "sizeDdy))) * 0.5f;\n";
+ }
+
+ out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
+ }
+
+ out << " " << textureReference
+ << ".GetDimensions(baseLevel + mip, width, height, depth, levels);\n";
+ }
+ else
+ UNREACHABLE();
+
+ OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
+ }
+}
+
+void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ ShShaderOutput outputType,
+ const ImmutableString &textureReference,
+ const ImmutableString &samplerReference,
+ const ImmutableString &texCoordX,
+ const ImmutableString &texCoordY,
+ const ImmutableString &texCoordZ)
+{
+ const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
+ ImmutableString samplerCoordTypeString(
+ GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
+ ImmutableStringBuilder samplerCoordBuilder(
+ samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
+ texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
+
+ samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
+ if (hlslCoords >= 3)
+ {
+ if (textureFunction.coords < 3)
+ {
+ samplerCoordBuilder << ", 0";
+ }
+ else
+ {
+ samplerCoordBuilder << ", " << texCoordZ;
+ }
+ }
+ samplerCoordBuilder << ")";
+
+ ImmutableString samplerCoordString(samplerCoordBuilder);
+
+ if (IsShadowSampler(textureFunction.sampler))
+ {
+ out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", "
+ << samplerCoordString << ", refZ";
+ if (textureFunction.offset)
+ {
+ out << ", offset";
+ }
+ out << ");\n";
+ return;
+ }
+
+ constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
+ {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
+
+ out << " switch(comp)\n"
+ " {\n";
+ for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
+ {
+ out << " case " << component << ":\n"
+ << " return " << textureReference << "." << kHLSLGatherFunctions[component]
+ << "(" << samplerReference << ", " << samplerCoordString;
+ if (textureFunction.offset)
+ {
+ out << ", offset";
+ }
+ out << ");\n";
+ }
+
+ out << " default:\n"
+ " return float4(0.0, 0.0, 0.0, 1.0);\n"
+ " }\n";
+}
+
+void OutputTextureSampleFunctionReturnStatement(
+ TInfoSinkBase &out,
+ const TextureFunctionHLSL::TextureFunction &textureFunction,
+ const ShShaderOutput outputType,
+ const ImmutableString &textureReference,
+ const ImmutableString &samplerReference,
+ const ImmutableString &texCoordX,
+ const ImmutableString &texCoordY,
+ const ImmutableString &texCoordZ)
+{
+ out << " return ";
+
+ if (IsIntegerSampler(textureFunction.sampler) && !IsSamplerCube(textureFunction.sampler) &&
+ textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ out << " useBorderColor ? ";
+ if (IsIntegerSamplerUnsigned(textureFunction.sampler))
+ {
+ out << "asuint";
+ }
+ out << "(samplerMetadata[samplerIndex].intBorderColor) : ";
+ }
+
+ // HLSL intrinsic
+ if (outputType == SH_HLSL_3_0_OUTPUT)
+ {
+ switch (textureFunction.sampler)
+ {
+ case EbtSampler2D:
+ case EbtSamplerExternalOES:
+ out << "tex2D";
+ break;
+ case EbtSamplerCube:
+ out << "texCUBE";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ out << "(" << samplerReference << ", ";
+ break;
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ out << "bias(" << samplerReference << ", ";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ out << "lod(" << samplerReference << ", ";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ out << "lod(" << samplerReference << ", ";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ out << "lod(" << samplerReference << ", ";
+ break;
+ case TextureFunctionHLSL::TextureFunction::GRAD:
+ out << "grad(" << samplerReference << ", ";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
+ }
+ else
+ UNREACHABLE();
+
+ const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
+
+ out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
+ << texCoordY;
+
+ if (outputType == SH_HLSL_3_0_OUTPUT)
+ {
+ if (hlslCoords >= 3)
+ {
+ if (textureFunction.coords < 3)
+ {
+ out << ", 0";
+ }
+ else
+ {
+ out << ", " << texCoordZ;
+ }
+ }
+
+ if (hlslCoords == 4)
+ {
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ out << ", bias";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ out << ", lod";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ out << ", 0";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ out << ", bias";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ out << ")";
+ }
+ else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ if (hlslCoords >= 3)
+ {
+ ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
+ !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
+ out << ", " << texCoordZ;
+ }
+
+ if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
+ {
+ if (IsIntegerSampler(textureFunction.sampler))
+ {
+ out << ", mip)";
+ }
+ else if (IsShadowSampler(textureFunction.sampler))
+ {
+ // Compare value
+ if (textureFunction.proj)
+ {
+ // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
+ // The resulting third component of P' in the shadow forms is used as
+ // Dref
+ out << "), " << texCoordZ;
+ }
+ else
+ {
+ switch (textureFunction.coords)
+ {
+ case 3:
+ out << "), t.z";
+ break;
+ case 4:
+ out << "), t.w";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+ else
+ {
+ out << "), ddx, ddy";
+ }
+ }
+ else if (IsIntegerSampler(textureFunction.sampler) ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
+ {
+ if (IsSampler2DMS(textureFunction.sampler) ||
+ IsSampler2DMSArray(textureFunction.sampler))
+ out << "), index";
+ else
+ out << ", mip)";
+ }
+ else if (IsShadowSampler(textureFunction.sampler))
+ {
+ // Compare value
+ if (textureFunction.proj)
+ {
+ // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
+ // The resulting third component of P' in the shadow forms is used as Dref
+ out << "), " << texCoordZ;
+ }
+ else
+ {
+ switch (textureFunction.coords)
+ {
+ case 3:
+ out << "), t.z";
+ break;
+ case 4:
+ out << "), t.w";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+ else
+ {
+ switch (textureFunction.method)
+ {
+ case TextureFunctionHLSL::TextureFunction::IMPLICIT:
+ out << ")";
+ break;
+ case TextureFunctionHLSL::TextureFunction::BIAS:
+ out << "), bias";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD:
+ out << "), lod";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0:
+ out << "), 0";
+ break;
+ case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
+ out << "), bias";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ if (textureFunction.offset &&
+ (!IsIntegerSampler(textureFunction.sampler) ||
+ textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
+ {
+ out << ", offset";
+ }
+ }
+ else
+ UNREACHABLE();
+
+ out << ");\n"; // Close the sample function call and return statement
+}
+
+} // Anonymous namespace
+
+ImmutableString TextureFunctionHLSL::TextureFunction::name() const
+{
+ static const ImmutableString kGlTextureName("gl_texture");
+
+ ImmutableString suffix(TextureTypeSuffix(this->sampler));
+
+ ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
+
+ name << kGlTextureName;
+
+ // We need to include full the sampler type in the function name to make the signature unique
+ // on D3D11, where samplers are passed to texture functions as indices.
+ name << suffix;
+
+ if (proj)
+ {
+ name << "Proj";
+ }
+
+ if (offset)
+ {
+ name << "Offset";
+ }
+
+ switch (method)
+ {
+ case IMPLICIT:
+ break;
+ case BIAS:
+ break; // Extra parameter makes the signature unique
+ case LOD:
+ name << "Lod";
+ break;
+ case LOD0:
+ name << "Lod0";
+ break;
+ case LOD0BIAS:
+ name << "Lod0";
+ break; // Extra parameter makes the signature unique
+ case SIZE:
+ name << "Size";
+ break;
+ case FETCH:
+ name << "Fetch";
+ break;
+ case GRAD:
+ name << "Grad";
+ break;
+ case GATHER:
+ name << "Gather";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return name;
+}
+
+const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
+{
+ if (method == TextureFunction::SIZE)
+ {
+ switch (sampler)
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DShadow:
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCubeShadow:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DMS:
+ case EbtISampler2DMS:
+ case EbtUSampler2DMS:
+ return "int2";
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DMSArray:
+ case EbtISampler2DMSArray:
+ case EbtUSampler2DMSArray:
+ case EbtSampler2DArrayShadow:
+ return "int3";
+ default:
+ UNREACHABLE();
+ }
+ }
+ else // Sampling function
+ {
+ switch (sampler)
+ {
+ case EbtSampler2D:
+ case EbtSampler2DMS:
+ case EbtSampler2DMSArray:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSampler2DArray:
+ case EbtSamplerExternalOES:
+ return "float4";
+ case EbtISampler2D:
+ case EbtISampler2DMS:
+ case EbtISampler2DMSArray:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ return "int4";
+ case EbtUSampler2D:
+ case EbtUSampler2DMS:
+ case EbtUSampler2DMSArray:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ return "uint4";
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ if (method == TextureFunctionHLSL::TextureFunction::GATHER)
+ {
+ return "float4";
+ }
+ else
+ {
+ return "float";
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ return "";
+}
+
+bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
+{
+ return std::tie(sampler, coords, proj, offset, method) <
+ std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
+}
+
+ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
+ TBasicType samplerType,
+ int coords,
+ size_t argumentCount,
+ bool lod0,
+ sh::GLenum shaderType)
+{
+ TextureFunction textureFunction;
+ textureFunction.sampler = samplerType;
+ textureFunction.coords = coords;
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.proj = false;
+ textureFunction.offset = false;
+
+ if (name == "texture2D" || name == "textureCube" || name == "texture")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ }
+ else if (name == "texture2DProj" || name == "textureProj")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.proj = true;
+ }
+ else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
+ name == "texture2DLodEXT" || name == "textureCubeLodEXT")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ }
+ else if (name == "texture2DProjLod" || name == "textureProjLod" ||
+ name == "texture2DProjLodEXT")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ textureFunction.proj = true;
+ }
+ else if (name == "textureSize")
+ {
+ textureFunction.method = TextureFunction::SIZE;
+ }
+ else if (name == "textureOffset")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureProjOffset")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.offset = true;
+ textureFunction.proj = true;
+ }
+ else if (name == "textureLodOffset")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureProjLodOffset")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ textureFunction.proj = true;
+ textureFunction.offset = true;
+ }
+ else if (name == "texelFetch")
+ {
+ textureFunction.method = TextureFunction::FETCH;
+ }
+ else if (name == "texelFetchOffset")
+ {
+ textureFunction.method = TextureFunction::FETCH;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureGrad" || name == "texture2DGradEXT")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ }
+ else if (name == "textureGradOffset")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
+ name == "textureCubeGradEXT")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ textureFunction.proj = true;
+ }
+ else if (name == "textureProjGradOffset")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ textureFunction.proj = true;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureGather")
+ {
+ textureFunction.method = TextureFunction::GATHER;
+ }
+ else if (name == "textureGatherOffset")
+ {
+ textureFunction.method = TextureFunction::GATHER;
+ textureFunction.offset = true;
+ }
+ else
+ UNREACHABLE();
+
+ if (textureFunction.method ==
+ TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
+ {
+ size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
+
+ if (textureFunction.offset)
+ {
+ mandatoryArgumentCount++;
+ }
+
+ bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
+
+ if (lod0 || shaderType == GL_VERTEX_SHADER || shaderType == GL_COMPUTE_SHADER)
+ {
+ if (bias)
+ {
+ textureFunction.method = TextureFunction::LOD0BIAS;
+ }
+ else
+ {
+ textureFunction.method = TextureFunction::LOD0;
+ }
+ }
+ else if (bias)
+ {
+ textureFunction.method = TextureFunction::BIAS;
+ }
+ }
+
+ mUsesTexture.insert(textureFunction);
+ return textureFunction.name();
+}
+
+void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
+ const ShShaderOutput outputType,
+ bool getDimensionsIgnoresBaseLevel)
+{
+ for (const TextureFunction &textureFunction : mUsesTexture)
+ {
+ // Function header
+ out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
+
+ OutputTextureFunctionArgumentList(out, textureFunction, outputType);
+
+ out << ")\n"
+ "{\n";
+
+ // In some cases we use a variable to store the texture/sampler objects, but to work around
+ // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
+ // sampling we need to call the function directly on references to the texture and sampler
+ // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
+ // tests.
+ ImmutableString textureReference("");
+ ImmutableString samplerReference("");
+ GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
+
+ if (textureFunction.method == TextureFunction::SIZE)
+ {
+ OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
+ getDimensionsIgnoresBaseLevel);
+ }
+ else
+ {
+ ImmutableString texCoordX("t.x");
+ ImmutableString texCoordY("t.y");
+ ImmutableString texCoordZ("t.z");
+ if (textureFunction.method == TextureFunction::GATHER)
+ {
+ OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
+ samplerReference, texCoordX, texCoordY, texCoordZ);
+ }
+ else
+ {
+ ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
+ OutputIntegerTextureSampleFunctionComputations(
+ out, textureFunction, outputType, textureReference, &texCoordX, &texCoordY,
+ &texCoordZ, getDimensionsIgnoresBaseLevel);
+ OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
+ textureReference, samplerReference,
+ texCoordX, texCoordY, texCoordZ);
+ }
+ }
+
+ out << "}\n"
+ "\n";
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h
new file mode 100644
index 0000000000..98de98fff5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL
+// output. Some of the implementations are straightforward and just call the HLSL equivalent of the
+// ESSL texture function, others do more work to emulate ESSL texture sampling or size query
+// behavior.
+//
+
+#ifndef COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_
+#define COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_
+
+#include <set>
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/InfoSink.h"
+
+namespace sh
+{
+
+class TextureFunctionHLSL final : angle::NonCopyable
+{
+ public:
+ struct TextureFunction
+ {
+ // See ESSL 3.00.6 section 8.8 for reference about what the different methods below do.
+ enum Method
+ {
+ IMPLICIT, // Mipmap LOD determined implicitly (standard lookup)
+ BIAS,
+ LOD,
+ LOD0,
+ LOD0BIAS,
+ SIZE, // textureSize()
+ FETCH,
+ GRAD,
+ GATHER
+ };
+
+ ImmutableString name() const;
+
+ bool operator<(const TextureFunction &rhs) const;
+
+ const char *getReturnType() const;
+
+ TBasicType sampler;
+ int coords;
+ bool proj;
+ bool offset;
+ Method method;
+ };
+
+ // Returns the name of the texture function implementation to call.
+ // The name that's passed in is the name of the GLSL texture function that it should implement.
+ ImmutableString useTextureFunction(const ImmutableString &name,
+ TBasicType samplerType,
+ int coords,
+ size_t argumentCount,
+ bool lod0,
+ sh::GLenum shaderType);
+
+ void textureFunctionHeader(TInfoSinkBase &out,
+ const ShShaderOutput outputType,
+ bool getDimensionsIgnoresBaseLevel);
+
+ private:
+ typedef std::set<TextureFunction> TextureFunctionSet;
+ TextureFunctionSet mUsesTexture;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp
new file mode 100644
index 0000000000..9631a32cb6
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp
@@ -0,0 +1,184 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorESSL.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+#include "compiler/translator/OutputESSL.h"
+#include "compiler/translator/tree_ops/EmulatePrecision.h"
+#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
+
+namespace sh
+{
+
+TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
+ : TCompiler(type, spec, SH_ESSL_OUTPUT)
+{}
+
+void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions)
+{
+ if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
+ {
+ InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
+ }
+}
+
+void TranslatorESSL::translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics * /*perfDiagnostics*/)
+{
+ TInfoSinkBase &sink = getInfoSink().obj;
+
+ int shaderVer = getShaderVersion();
+ if (shaderVer > 100)
+ {
+ sink << "#version " << shaderVer << " es\n";
+ }
+
+ // Write built-in extension behaviors.
+ writeExtensionBehavior(compileOptions);
+
+ // Write pragmas after extensions because some drivers consider pragmas
+ // like non-preprocessor tokens.
+ writePragma(compileOptions);
+
+ bool precisionEmulation =
+ getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
+
+ if (precisionEmulation)
+ {
+ EmulatePrecision emulatePrecision(&getSymbolTable());
+ root->traverse(&emulatePrecision);
+ emulatePrecision.updateTree();
+ emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT);
+ }
+
+ RecordConstantPrecision(root, &getSymbolTable());
+
+ // Write emulated built-in functions if needed.
+ if (!getBuiltInFunctionEmulator().isOutputEmpty())
+ {
+ sink << "// BEGIN: Generated code for built-in function emulation\n\n";
+ if (getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
+ << "#define emu_precision highp\n"
+ << "#else\n"
+ << "#define emu_precision mediump\n"
+ << "#endif\n\n";
+ }
+ else
+ {
+ sink << "#define emu_precision highp\n";
+ }
+
+ getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
+ sink << "// END: Generated code for built-in function emulation\n\n";
+ }
+
+ // Write array bounds clamping emulation if needed.
+ getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
+ if (getShaderType() == GL_COMPUTE_SHADER)
+ {
+ EmitWorkGroupSizeGLSL(*this, sink);
+ }
+
+ if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
+ {
+ WriteGeometryShaderLayoutQualifiers(
+ sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
+ getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
+ }
+
+ // Write translated shader.
+ TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
+ &getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
+ compileOptions);
+
+ root->traverse(&outputESSL);
+}
+
+bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // If following the spec to the letter, we should not flatten this pragma.
+ // However, the spec's wording means that the pragma applies only to outputs.
+ // This contradicts the spirit of using the pragma,
+ // because if the pragma is used in a vertex shader,
+ // the only way to be able to link it to a fragment shader
+ // is to manually qualify each of fragment shader's inputs as invariant.
+ // Which defeats the purpose of this pragma - temporarily make all varyings
+ // invariant for debugging.
+ // Thus, we should be non-conformant to spec's letter here and flatten.
+ return true;
+}
+
+void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
+{
+ TInfoSinkBase &sink = getInfoSink().obj;
+ const TExtensionBehavior &extBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
+ ++iter)
+ {
+ if (iter->second != EBhUndefined)
+ {
+ const bool isMultiview = (iter->first == TExtension::OVR_multiview) ||
+ (iter->first == TExtension::OVR_multiview2);
+ if (getResources().NV_shader_framebuffer_fetch &&
+ iter->first == TExtension::EXT_shader_framebuffer_fetch)
+ {
+ sink << "#extension GL_NV_shader_framebuffer_fetch : "
+ << GetBehaviorString(iter->second) << "\n";
+ }
+ else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers)
+ {
+ sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second)
+ << "\n";
+ }
+ else if (isMultiview)
+ {
+ EmitMultiviewGLSL(*this, compileOptions, iter->second, sink);
+ }
+ else if (iter->first == TExtension::EXT_geometry_shader)
+ {
+ sink << "#ifdef GL_EXT_geometry_shader\n"
+ << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second)
+ << "\n"
+ << "#elif defined GL_OES_geometry_shader\n"
+ << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second)
+ << "\n";
+ if (iter->second == EBhRequire)
+ {
+ sink << "#else\n"
+ << "#error \"No geometry shader extensions available.\" // Only generate "
+ "this if the extension is \"required\"\n";
+ }
+ sink << "#endif\n";
+ }
+ else if (iter->first == TExtension::ANGLE_multi_draw)
+ {
+ // Don't emit anything. This extension is emulated
+ ASSERT((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0);
+ continue;
+ }
+ else if (iter->first == TExtension::ANGLE_base_vertex_base_instance)
+ {
+ // Don't emit anything. This extension is emulated
+ ASSERT((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0);
+ continue;
+ }
+ else
+ {
+ sink << "#extension " << GetExtensionNameString(iter->first) << " : "
+ << GetBehaviorString(iter->second) << "\n";
+ }
+ }
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h
new file mode 100644
index 0000000000..24dc738513
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TRANSLATORESSL_H_
+#define COMPILER_TRANSLATOR_TRANSLATORESSL_H_
+
+#include "compiler/translator/Compiler.h"
+
+namespace sh
+{
+
+class TranslatorESSL : public TCompiler
+{
+ public:
+ TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
+
+ protected:
+ void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions) override;
+
+ void translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics *perfDiagnostics) override;
+ bool shouldFlattenPragmaStdglInvariantAll() override;
+
+ private:
+ void writeExtensionBehavior(ShCompileOptions compileOptions);
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORESSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp
new file mode 100644
index 0000000000..81b43b8245
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp
@@ -0,0 +1,334 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorGLSL.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+#include "compiler/translator/ExtensionGLSL.h"
+#include "compiler/translator/OutputGLSL.h"
+#include "compiler/translator/VersionGLSL.h"
+#include "compiler/translator/tree_ops/EmulatePrecision.h"
+#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
+#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h"
+
+namespace sh
+{
+
+TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec, output)
+{}
+
+void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions)
+{
+ if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION)
+ {
+ InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
+ }
+
+ if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION)
+ {
+ InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
+ }
+
+ if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION)
+ {
+ InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu);
+ }
+
+ int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
+ InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
+}
+
+void TranslatorGLSL::translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics * /*perfDiagnostics*/)
+{
+ TInfoSinkBase &sink = getInfoSink().obj;
+
+ // Write GLSL version.
+ writeVersion(root);
+
+ // Write extension behaviour as needed
+ writeExtensionBehavior(root, compileOptions);
+
+ // Write pragmas after extensions because some drivers consider pragmas
+ // like non-preprocessor tokens.
+ writePragma(compileOptions);
+
+ // If flattening the global invariant pragma, write invariant declarations for built-in
+ // variables. It should be harmless to do this twice in the case that the shader also explicitly
+ // did this. However, it's important to emit invariant qualifiers only for those built-in
+ // variables that are actually used, to avoid affecting the behavior of the shader.
+ if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 &&
+ getPragma().stdgl.invariantAll &&
+ !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions))
+ {
+ ASSERT(wereVariablesCollected());
+
+ switch (getShaderType())
+ {
+ case GL_VERTEX_SHADER:
+ sink << "invariant gl_Position;\n";
+
+ // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment
+ // shaders if it's statically referenced.
+ conditionallyOutputInvariantDeclaration("gl_PointSize");
+ break;
+ case GL_FRAGMENT_SHADER:
+ // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment
+ // shaders, so we can use simple logic to determine whether to declare these
+ // variables invariant.
+ conditionallyOutputInvariantDeclaration("gl_FragCoord");
+ conditionallyOutputInvariantDeclaration("gl_PointCoord");
+ break;
+ default:
+ // Currently not reached, but leave this in for future expansion.
+ ASSERT(false);
+ break;
+ }
+ }
+
+ if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
+ {
+ sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion());
+ }
+
+ if ((compileOptions & SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR) != 0)
+ {
+ sh::RewriteUnaryMinusOperatorFloat(root);
+ }
+
+ bool precisionEmulation =
+ getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
+
+ if (precisionEmulation)
+ {
+ EmulatePrecision emulatePrecision(&getSymbolTable());
+ root->traverse(&emulatePrecision);
+ emulatePrecision.updateTree();
+ emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType());
+ }
+
+ // Write emulated built-in functions if needed.
+ if (!getBuiltInFunctionEmulator().isOutputEmpty())
+ {
+ sink << "// BEGIN: Generated code for built-in function emulation\n\n";
+ sink << "#define emu_precision\n\n";
+ getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
+ sink << "// END: Generated code for built-in function emulation\n\n";
+ }
+
+ // Write array bounds clamping emulation if needed.
+ getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
+ // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
+ // if it's core profile shaders and they are used.
+ if (getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ const bool mayHaveESSL1SecondaryOutputs =
+ IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) &&
+ getShaderVersion() == 100;
+ const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
+
+ bool hasGLFragColor = false;
+ bool hasGLFragData = false;
+ bool hasGLSecondaryFragColor = false;
+ bool hasGLSecondaryFragData = false;
+
+ for (const auto &outputVar : mOutputVariables)
+ {
+ if (declareGLFragmentOutputs)
+ {
+ if (outputVar.name == "gl_FragColor")
+ {
+ ASSERT(!hasGLFragColor);
+ hasGLFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_FragData")
+ {
+ ASSERT(!hasGLFragData);
+ hasGLFragData = true;
+ continue;
+ }
+ }
+ if (mayHaveESSL1SecondaryOutputs)
+ {
+ if (outputVar.name == "gl_SecondaryFragColorEXT")
+ {
+ ASSERT(!hasGLSecondaryFragColor);
+ hasGLSecondaryFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_SecondaryFragDataEXT")
+ {
+ ASSERT(!hasGLSecondaryFragData);
+ hasGLSecondaryFragData = true;
+ continue;
+ }
+ }
+ }
+ ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
+ (hasGLFragData || hasGLSecondaryFragData)));
+ if (hasGLFragColor)
+ {
+ sink << "out vec4 webgl_FragColor;\n";
+ }
+ if (hasGLFragData)
+ {
+ sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
+ }
+ if (hasGLSecondaryFragColor)
+ {
+ sink << "out vec4 angle_SecondaryFragColor;\n";
+ }
+ if (hasGLSecondaryFragData)
+ {
+ sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
+ << "];\n";
+ }
+ }
+
+ if (getShaderType() == GL_COMPUTE_SHADER)
+ {
+ EmitWorkGroupSizeGLSL(*this, sink);
+ }
+
+ if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
+ {
+ WriteGeometryShaderLayoutQualifiers(
+ sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
+ getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
+ }
+
+ // Write translated shader.
+ TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
+ &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
+ compileOptions);
+
+ root->traverse(&outputGLSL);
+}
+
+bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
+ // translate to that version, return true for the next higher version.
+ return IsGLSL130OrNewer(getOutputType());
+}
+
+bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions)
+{
+ return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) ||
+ TCompiler::shouldCollectVariables(compileOptions);
+}
+
+void TranslatorGLSL::writeVersion(TIntermNode *root)
+{
+ TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
+ root->traverse(&versionGLSL);
+ int version = versionGLSL.getVersion();
+ // We need to write version directive only if it is greater than 110.
+ // If there is no version directive in the shader, 110 is implied.
+ if (version > 110)
+ {
+ TInfoSinkBase &sink = getInfoSink().obj;
+ sink << "#version " << version << "\n";
+ }
+}
+
+void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
+{
+ TInfoSinkBase &sink = getInfoSink().obj;
+ const TExtensionBehavior &extBehavior = getExtensionBehavior();
+ for (const auto &iter : extBehavior)
+ {
+ if (iter.second == EBhUndefined)
+ {
+ continue;
+ }
+
+ if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT)
+ {
+ // For GLSL output, we don't need to emit most extensions explicitly,
+ // but some we need to translate in GL compatibility profile.
+ if (iter.first == TExtension::EXT_shader_texture_lod)
+ {
+ sink << "#extension GL_ARB_shader_texture_lod : " << GetBehaviorString(iter.second)
+ << "\n";
+ }
+
+ if (iter.first == TExtension::EXT_draw_buffers)
+ {
+ sink << "#extension GL_ARB_draw_buffers : " << GetBehaviorString(iter.second)
+ << "\n";
+ }
+
+ if (iter.first == TExtension::EXT_geometry_shader)
+ {
+ sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second)
+ << "\n";
+ }
+ }
+
+ const bool isMultiview =
+ (iter.first == TExtension::OVR_multiview) || (iter.first == TExtension::OVR_multiview2);
+ if (isMultiview)
+ {
+ EmitMultiviewGLSL(*this, compileOptions, iter.second, sink);
+ }
+
+ // Support ANGLE_texture_multisample extension on GLSL300
+ if (getShaderVersion() >= 300 && iter.first == TExtension::ANGLE_texture_multisample &&
+ getOutputType() < SH_GLSL_330_CORE_OUTPUT)
+ {
+ sink << "#extension GL_ARB_texture_multisample : " << GetBehaviorString(iter.second)
+ << "\n";
+ }
+ }
+
+ // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
+ if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT &&
+ getShaderType() != GL_COMPUTE_SHADER)
+ {
+ sink << "#extension GL_ARB_explicit_attrib_location : require\n";
+ }
+
+ // Need to enable gpu_shader5 to have index constant sampler array indexing
+ if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT &&
+ getShaderVersion() == 100)
+ {
+ // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
+ // support index constant sampler array indexing, but don't have the extension or
+ // on drivers that don't have the extension at all as it would break WebGL 1 for
+ // some users.
+ sink << "#extension GL_ARB_gpu_shader5 : enable\n";
+ }
+
+ TExtensionGLSL extensionGLSL(getOutputType());
+ root->traverse(&extensionGLSL);
+
+ for (const auto &ext : extensionGLSL.getEnabledExtensions())
+ {
+ sink << "#extension " << ext << " : enable\n";
+ }
+ for (const auto &ext : extensionGLSL.getRequiredExtensions())
+ {
+ sink << "#extension " << ext << " : require\n";
+ }
+}
+
+void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName)
+{
+ if (isVaryingDefined(builtinVaryingName))
+ {
+ TInfoSinkBase &sink = getInfoSink().obj;
+ sink << "invariant " << builtinVaryingName << ";\n";
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h
new file mode 100644
index 0000000000..982d0e5ddc
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TRANSLATORGLSL_H_
+#define COMPILER_TRANSLATOR_TRANSLATORGLSL_H_
+
+#include "compiler/translator/Compiler.h"
+
+namespace sh
+{
+
+class TranslatorGLSL : public TCompiler
+{
+ public:
+ TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+
+ protected:
+ void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions) override;
+
+ void translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics *perfDiagnostics) override;
+ bool shouldFlattenPragmaStdglInvariantAll() override;
+ bool shouldCollectVariables(ShCompileOptions compileOptions) override;
+
+ private:
+ void writeVersion(TIntermNode *root);
+ void writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions);
+ void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName);
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp
new file mode 100644
index 0000000000..c4be3b027c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp
@@ -0,0 +1,204 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorHLSL.h"
+
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/tree_ops/AddDefaultReturnStatements.h"
+#include "compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h"
+#include "compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h"
+#include "compiler/translator/tree_ops/EmulatePrecision.h"
+#include "compiler/translator/tree_ops/ExpandIntegerPowExpressions.h"
+#include "compiler/translator/tree_ops/PruneEmptyCases.h"
+#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
+#include "compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h"
+#include "compiler/translator/tree_ops/RewriteElseBlocks.h"
+#include "compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h"
+#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
+#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h"
+#include "compiler/translator/tree_ops/SeparateArrayConstructorStatements.h"
+#include "compiler/translator/tree_ops/SeparateArrayInitialization.h"
+#include "compiler/translator/tree_ops/SeparateDeclarations.h"
+#include "compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h"
+#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
+#include "compiler/translator/tree_ops/SplitSequenceOperator.h"
+#include "compiler/translator/tree_ops/UnfoldShortCircuitToIf.h"
+#include "compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+
+namespace sh
+{
+
+TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec, output)
+{}
+
+void TranslatorHLSL::translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics *perfDiagnostics)
+{
+ const ShBuiltInResources &resources = getResources();
+ int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
+ int maxDualSourceDrawBuffers =
+ resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0;
+
+ sh::AddDefaultReturnStatements(root);
+
+ // 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.
+ // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl().
+ SimplifyLoopConditions(root,
+ IntermNodePatternMatcher::kExpressionReturningArray |
+ IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
+ &getSymbolTable());
+
+ SplitSequenceOperator(root,
+ IntermNodePatternMatcher::kExpressionReturningArray |
+ IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
+ &getSymbolTable());
+
+ // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
+ UnfoldShortCircuitToIf(root, &getSymbolTable());
+
+ SeparateArrayConstructorStatements(root);
+
+ SeparateExpressionsReturningArrays(root, &getSymbolTable());
+
+ // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
+ SeparateArrayInitialization(root);
+
+ // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
+ // as a return value to use an out parameter to transfer the array data instead.
+ ArrayReturnValueToOutParameter(root, &getSymbolTable());
+
+ if (!shouldRunLoopAndIndexingValidation(compileOptions))
+ {
+ // HLSL doesn't support dynamic indexing of vectors and matrices.
+ RemoveDynamicIndexing(root, &getSymbolTable(), perfDiagnostics);
+ }
+
+ // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
+ // use a vertex attribute as a condition, and some related computation in the else block.
+ if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
+ {
+ sh::RewriteElseBlocks(root, &getSymbolTable());
+ }
+
+ // Work around an HLSL compiler frontend aliasing optimization bug.
+ // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
+ // in the next release of d3dcompiler.dll, it would be nice to detect the DLL
+ // version and only apply the workaround if it is too old.
+ sh::BreakVariableAliasingInInnerLoops(root);
+
+ // WrapSwitchStatementsInBlocks should be called after any AST transformations that might
+ // introduce variable declarations inside the main scope of any switch statement. It cannot
+ // result in no-op cases at the end of switch statements, because unreferenced variables
+ // have already been pruned.
+ WrapSwitchStatementsInBlocks(root);
+
+ bool precisionEmulation =
+ getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
+
+ if (precisionEmulation)
+ {
+ EmulatePrecision emulatePrecision(&getSymbolTable());
+ root->traverse(&emulatePrecision);
+ emulatePrecision.updateTree();
+ emulatePrecision.writeEmulationHelpers(getInfoSink().obj, getShaderVersion(),
+ getOutputType());
+ }
+
+ if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0)
+ {
+ sh::ExpandIntegerPowExpressions(root, &getSymbolTable());
+ }
+
+ if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
+ {
+ sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion());
+ }
+
+ if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) &&
+ getShaderType() == GL_VERTEX_SHADER)
+ {
+ sh::RewriteUnaryMinusOperatorInt(root);
+ }
+
+ if (getShaderVersion() >= 310)
+ {
+ // Due to ssbo also can be used as the argument of atomic memory functions, we should put
+ // RewriteExpressionsWithShaderStorageBlock before RewriteAtomicFunctionExpressions.
+ sh::RewriteExpressionsWithShaderStorageBlock(root, &getSymbolTable());
+ sh::RewriteAtomicFunctionExpressions(root, &getSymbolTable(), getShaderVersion());
+ }
+
+ sh::OutputHLSL outputHLSL(
+ getShaderType(), getShaderVersion(), getExtensionBehavior(), getSourcePath(),
+ getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(), compileOptions,
+ getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics, mShaderStorageBlocks);
+
+ outputHLSL.output(root, getInfoSink().obj);
+
+ mShaderStorageBlockRegisterMap = outputHLSL.getShaderStorageBlockRegisterMap();
+ mUniformBlockRegisterMap = outputHLSL.getUniformBlockRegisterMap();
+ mUniformRegisterMap = outputHLSL.getUniformRegisterMap();
+ mReadonlyImage2DRegisterIndex = outputHLSL.getReadonlyImage2DRegisterIndex();
+ mImage2DRegisterIndex = outputHLSL.getImage2DRegisterIndex();
+ mUsedImage2DFunctionNames = outputHLSL.getUsedImage2DFunctionNames();
+}
+
+bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Not necessary when translating to HLSL.
+ return false;
+}
+
+bool TranslatorHLSL::hasShaderStorageBlock(const std::string &uniformBlockName) const
+{
+ return (mShaderStorageBlockRegisterMap.count(uniformBlockName) > 0);
+}
+
+unsigned int TranslatorHLSL::getShaderStorageBlockRegister(
+ const std::string &shaderStorageBlockName) const
+{
+ ASSERT(hasShaderStorageBlock(shaderStorageBlockName));
+ return mShaderStorageBlockRegisterMap.find(shaderStorageBlockName)->second;
+}
+
+bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const
+{
+ return (mUniformBlockRegisterMap.count(uniformBlockName) > 0);
+}
+
+unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const
+{
+ ASSERT(hasUniformBlock(uniformBlockName));
+ return mUniformBlockRegisterMap.find(uniformBlockName)->second;
+}
+
+const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
+{
+ return &mUniformRegisterMap;
+}
+
+unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const
+{
+ return mReadonlyImage2DRegisterIndex;
+}
+
+unsigned int TranslatorHLSL::getImage2DRegisterIndex() const
+{
+ return mImage2DRegisterIndex;
+}
+
+const std::set<std::string> *TranslatorHLSL::getUsedImage2DFunctionNames() const
+{
+ return &mUsedImage2DFunctionNames;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h
new file mode 100644
index 0000000000..bb8b7f2855
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TRANSLATORHLSL_H_
+#define COMPILER_TRANSLATOR_TRANSLATORHLSL_H_
+
+#include "compiler/translator/Compiler.h"
+
+namespace sh
+{
+
+class TranslatorHLSL : public TCompiler
+{
+ public:
+ TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+ TranslatorHLSL *getAsTranslatorHLSL() override { return this; }
+
+ bool hasShaderStorageBlock(const std::string &interfaceBlockName) const;
+ unsigned int getShaderStorageBlockRegister(const std::string &interfaceBlockName) const;
+
+ bool hasUniformBlock(const std::string &interfaceBlockName) const;
+ unsigned int getUniformBlockRegister(const std::string &interfaceBlockName) const;
+
+ const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
+ unsigned int getReadonlyImage2DRegisterIndex() const;
+ unsigned int getImage2DRegisterIndex() const;
+ const std::set<std::string> *getUsedImage2DFunctionNames() const;
+
+ protected:
+ void translate(TIntermBlock *root,
+ ShCompileOptions compileOptions,
+ PerformanceDiagnostics *perfDiagnostics) override;
+ bool shouldFlattenPragmaStdglInvariantAll() override;
+
+ // collectVariables needs to be run always so registers can be assigned.
+ bool shouldCollectVariables(ShCompileOptions compileOptions) override { return true; }
+
+ std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap;
+ std::map<std::string, unsigned int> mUniformBlockRegisterMap;
+ std::map<std::string, unsigned int> mUniformRegisterMap;
+ unsigned int mReadonlyImage2DRegisterIndex;
+ unsigned int mImage2DRegisterIndex;
+ std::set<std::string> mUsedImage2DFunctionNames;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/Types.cpp b/gfx/angle/checkout/src/compiler/translator/Types.cpp
new file mode 100644
index 0000000000..9d0374b170
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Types.cpp
@@ -0,0 +1,970 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#if defined(_MSC_VER)
+# pragma warning(disable : 4718)
+#endif
+
+#include "compiler/translator/Types.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+
+#include <algorithm>
+#include <climits>
+
+namespace sh
+{
+
+const char *getBasicString(TBasicType t)
+{
+ switch (t)
+ {
+ case EbtVoid:
+ return "void";
+ case EbtFloat:
+ return "float";
+ case EbtInt:
+ return "int";
+ case EbtUInt:
+ return "uint";
+ case EbtBool:
+ return "bool";
+ case EbtYuvCscStandardEXT:
+ return "yuvCscStandardEXT";
+ case EbtSampler2D:
+ return "sampler2D";
+ case EbtSampler3D:
+ return "sampler3D";
+ case EbtSamplerCube:
+ return "samplerCube";
+ case EbtSamplerExternalOES:
+ return "samplerExternalOES";
+ case EbtSamplerExternal2DY2YEXT:
+ return "__samplerExternal2DY2YEXT";
+ case EbtSampler2DRect:
+ return "sampler2DRect";
+ case EbtSampler2DArray:
+ return "sampler2DArray";
+ case EbtSampler2DMS:
+ return "sampler2DMS";
+ case EbtSampler2DMSArray:
+ return "sampler2DMSArray";
+ case EbtISampler2D:
+ return "isampler2D";
+ case EbtISampler3D:
+ return "isampler3D";
+ case EbtISamplerCube:
+ return "isamplerCube";
+ case EbtISampler2DArray:
+ return "isampler2DArray";
+ case EbtISampler2DMS:
+ return "isampler2DMS";
+ case EbtISampler2DMSArray:
+ return "isampler2DMSArray";
+ case EbtUSampler2D:
+ return "usampler2D";
+ case EbtUSampler3D:
+ return "usampler3D";
+ case EbtUSamplerCube:
+ return "usamplerCube";
+ case EbtUSampler2DArray:
+ return "usampler2DArray";
+ case EbtUSampler2DMS:
+ return "usampler2DMS";
+ case EbtUSampler2DMSArray:
+ return "usampler2DMSArray";
+ case EbtSampler2DShadow:
+ return "sampler2DShadow";
+ case EbtSamplerCubeShadow:
+ return "samplerCubeShadow";
+ case EbtSampler2DArrayShadow:
+ return "sampler2DArrayShadow";
+ case EbtStruct:
+ return "structure";
+ case EbtInterfaceBlock:
+ return "interface block";
+ case EbtImage2D:
+ return "image2D";
+ case EbtIImage2D:
+ return "iimage2D";
+ case EbtUImage2D:
+ return "uimage2D";
+ case EbtImage3D:
+ return "image3D";
+ case EbtIImage3D:
+ return "iimage3D";
+ case EbtUImage3D:
+ return "uimage3D";
+ case EbtImage2DArray:
+ return "image2DArray";
+ case EbtIImage2DArray:
+ return "iimage2DArray";
+ case EbtUImage2DArray:
+ return "uimage2DArray";
+ case EbtImageCube:
+ return "imageCube";
+ case EbtIImageCube:
+ return "iimageCube";
+ case EbtUImageCube:
+ return "uimageCube";
+ case EbtAtomicCounter:
+ return "atomic_uint";
+ default:
+ UNREACHABLE();
+ return "unknown type";
+ }
+}
+
+// TType implementation.
+TType::TType()
+ : type(EbtVoid),
+ precision(EbpUndefined),
+ qualifier(EvqGlobal),
+ invariant(false),
+ memoryQualifier(TMemoryQualifier::Create()),
+ layoutQualifier(TLayoutQualifier::Create()),
+ primarySize(0),
+ secondarySize(0),
+ mArraySizes(nullptr),
+ mInterfaceBlock(nullptr),
+ mStructure(nullptr),
+ mIsStructSpecifier(false),
+ mMangledName(nullptr)
+{}
+
+TType::TType(TBasicType t, unsigned char ps, unsigned char ss)
+ : type(t),
+ precision(EbpUndefined),
+ qualifier(EvqGlobal),
+ invariant(false),
+ memoryQualifier(TMemoryQualifier::Create()),
+ layoutQualifier(TLayoutQualifier::Create()),
+ primarySize(ps),
+ secondarySize(ss),
+ mArraySizes(nullptr),
+ mInterfaceBlock(nullptr),
+ mStructure(nullptr),
+ mIsStructSpecifier(false),
+ mMangledName(nullptr)
+{}
+
+TType::TType(TBasicType t, TPrecision p, TQualifier q, unsigned char ps, unsigned char ss)
+ : type(t),
+ precision(p),
+ qualifier(q),
+ invariant(false),
+ memoryQualifier(TMemoryQualifier::Create()),
+ layoutQualifier(TLayoutQualifier::Create()),
+ primarySize(ps),
+ secondarySize(ss),
+ mArraySizes(nullptr),
+ mInterfaceBlock(nullptr),
+ mStructure(nullptr),
+ mIsStructSpecifier(false),
+ mMangledName(nullptr)
+{}
+
+TType::TType(const TPublicType &p)
+ : type(p.getBasicType()),
+ precision(p.precision),
+ qualifier(p.qualifier),
+ invariant(p.invariant),
+ memoryQualifier(p.memoryQualifier),
+ layoutQualifier(p.layoutQualifier),
+ primarySize(p.getPrimarySize()),
+ secondarySize(p.getSecondarySize()),
+ mArraySizes(nullptr),
+ mInterfaceBlock(nullptr),
+ mStructure(nullptr),
+ mIsStructSpecifier(false),
+ mMangledName(nullptr)
+{
+ ASSERT(primarySize <= 4);
+ ASSERT(secondarySize <= 4);
+ if (p.isArray())
+ {
+ mArraySizes = new TVector<unsigned int>(*p.arraySizes);
+ }
+ if (p.getUserDef())
+ {
+ mStructure = p.getUserDef();
+ mIsStructSpecifier = p.isStructSpecifier();
+ }
+}
+
+TType::TType(const TStructure *userDef, bool isStructSpecifier)
+ : type(EbtStruct),
+ precision(EbpUndefined),
+ qualifier(EvqTemporary),
+ invariant(false),
+ memoryQualifier(TMemoryQualifier::Create()),
+ layoutQualifier(TLayoutQualifier::Create()),
+ primarySize(1),
+ secondarySize(1),
+ mArraySizes(nullptr),
+ mInterfaceBlock(nullptr),
+ mStructure(userDef),
+ mIsStructSpecifier(isStructSpecifier),
+ mMangledName(nullptr)
+{}
+
+TType::TType(const TInterfaceBlock *interfaceBlockIn,
+ TQualifier qualifierIn,
+ TLayoutQualifier layoutQualifierIn)
+ : type(EbtInterfaceBlock),
+ precision(EbpUndefined),
+ qualifier(qualifierIn),
+ invariant(false),
+ memoryQualifier(TMemoryQualifier::Create()),
+ layoutQualifier(layoutQualifierIn),
+ primarySize(1),
+ secondarySize(1),
+ mArraySizes(nullptr),
+ mInterfaceBlock(interfaceBlockIn),
+ mStructure(0),
+ mIsStructSpecifier(false),
+ mMangledName(nullptr)
+{}
+
+TType::TType(const TType &t)
+ : type(t.type),
+ precision(t.precision),
+ qualifier(t.qualifier),
+ invariant(t.invariant),
+ memoryQualifier(t.memoryQualifier),
+ layoutQualifier(t.layoutQualifier),
+ primarySize(t.primarySize),
+ secondarySize(t.secondarySize),
+ mArraySizes(t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr),
+ mInterfaceBlock(t.mInterfaceBlock),
+ mStructure(t.mStructure),
+ mIsStructSpecifier(t.mIsStructSpecifier),
+ mMangledName(t.mMangledName)
+{}
+
+TType &TType::operator=(const TType &t)
+{
+ type = t.type;
+ precision = t.precision;
+ qualifier = t.qualifier;
+ invariant = t.invariant;
+ memoryQualifier = t.memoryQualifier;
+ layoutQualifier = t.layoutQualifier;
+ primarySize = t.primarySize;
+ secondarySize = t.secondarySize;
+ mArraySizes = t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr;
+ mInterfaceBlock = t.mInterfaceBlock;
+ mStructure = t.mStructure;
+ mIsStructSpecifier = t.mIsStructSpecifier;
+ mMangledName = t.mMangledName;
+ return *this;
+}
+
+bool TType::canBeConstructed() const
+{
+ switch (type)
+ {
+ case EbtFloat:
+ case EbtInt:
+ case EbtUInt:
+ case EbtBool:
+ case EbtStruct:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const char *TType::getBuiltInTypeNameString() const
+{
+ if (isMatrix())
+ {
+ switch (getCols())
+ {
+ case 2:
+ switch (getRows())
+ {
+ case 2:
+ return "mat2";
+ case 3:
+ return "mat2x3";
+ case 4:
+ return "mat2x4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ case 3:
+ switch (getRows())
+ {
+ case 2:
+ return "mat3x2";
+ case 3:
+ return "mat3";
+ case 4:
+ return "mat3x4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ case 4:
+ switch (getRows())
+ {
+ case 2:
+ return "mat4x2";
+ case 3:
+ return "mat4x3";
+ case 4:
+ return "mat4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ }
+ if (isVector())
+ {
+ switch (getBasicType())
+ {
+ case EbtFloat:
+ switch (getNominalSize())
+ {
+ case 2:
+ return "vec2";
+ case 3:
+ return "vec3";
+ case 4:
+ return "vec4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ case EbtInt:
+ switch (getNominalSize())
+ {
+ case 2:
+ return "ivec2";
+ case 3:
+ return "ivec3";
+ case 4:
+ return "ivec4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ case EbtBool:
+ switch (getNominalSize())
+ {
+ case 2:
+ return "bvec2";
+ case 3:
+ return "bvec3";
+ case 4:
+ return "bvec4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ case EbtUInt:
+ switch (getNominalSize())
+ {
+ case 2:
+ return "uvec2";
+ case 3:
+ return "uvec3";
+ case 4:
+ return "uvec4";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ }
+ ASSERT(getBasicType() != EbtStruct);
+ ASSERT(getBasicType() != EbtInterfaceBlock);
+ return getBasicString();
+}
+
+int TType::getDeepestStructNesting() const
+{
+ return mStructure ? mStructure->deepestNesting() : 0;
+}
+
+bool TType::isNamelessStruct() const
+{
+ return mStructure && mStructure->symbolType() == SymbolType::Empty;
+}
+
+bool TType::isStructureContainingArrays() const
+{
+ return mStructure ? mStructure->containsArrays() : false;
+}
+
+bool TType::isStructureContainingMatrices() const
+{
+ return mStructure ? mStructure->containsMatrices() : false;
+}
+
+bool TType::isStructureContainingType(TBasicType t) const
+{
+ return mStructure ? mStructure->containsType(t) : false;
+}
+
+bool TType::isStructureContainingSamplers() const
+{
+ return mStructure ? mStructure->containsSamplers() : false;
+}
+
+bool TType::canReplaceWithConstantUnion() const
+{
+ if (isArray())
+ {
+ return false;
+ }
+ if (!mStructure)
+ {
+ return true;
+ }
+ if (isStructureContainingArrays())
+ {
+ return false;
+ }
+ if (getObjectSize() > 16)
+ {
+ return false;
+ }
+ return true;
+}
+
+//
+// Recursively generate mangled names.
+//
+const char *TType::buildMangledName() const
+{
+ TString mangledName(1, GetSizeMangledName(primarySize, secondarySize));
+
+ char basicMangledName = GetBasicMangledName(type);
+ if (basicMangledName != '{')
+ {
+ mangledName += basicMangledName;
+ }
+ else
+ {
+ ASSERT(type == EbtStruct || type == EbtInterfaceBlock);
+ switch (type)
+ {
+ case EbtStruct:
+ mangledName += "{s";
+ if (mStructure->symbolType() != SymbolType::Empty)
+ {
+ mangledName += mStructure->name().data();
+ }
+ mangledName += mStructure->mangledFieldList();
+ mangledName += '}';
+ break;
+ case EbtInterfaceBlock:
+ mangledName += "{i";
+ mangledName += mInterfaceBlock->name().data();
+ mangledName += mInterfaceBlock->mangledFieldList();
+ mangledName += '}';
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+
+ if (mArraySizes)
+ {
+ for (unsigned int arraySize : *mArraySizes)
+ {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", arraySize);
+ mangledName += '[';
+ mangledName += buf;
+ mangledName += ']';
+ }
+ }
+
+ // Copy string contents into a pool-allocated buffer, so we never need to call delete.
+ return AllocatePoolCharArray(mangledName.c_str(), mangledName.size());
+}
+
+size_t TType::getObjectSize() const
+{
+ size_t totalSize;
+
+ if (getBasicType() == EbtStruct)
+ totalSize = mStructure->objectSize();
+ else
+ totalSize = primarySize * secondarySize;
+
+ if (totalSize == 0)
+ return 0;
+
+ if (mArraySizes)
+ {
+ for (size_t arraySize : *mArraySizes)
+ {
+ if (arraySize > INT_MAX / totalSize)
+ totalSize = INT_MAX;
+ else
+ totalSize *= arraySize;
+ }
+ }
+
+ return totalSize;
+}
+
+int TType::getLocationCount() const
+{
+ int count = 1;
+
+ if (getBasicType() == EbtStruct)
+ {
+ count = mStructure->getLocationCount();
+ }
+
+ if (count == 0)
+ {
+ return 0;
+ }
+
+ if (mArraySizes)
+ {
+ for (unsigned int arraySize : *mArraySizes)
+ {
+ if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
+ {
+ count = std::numeric_limits<int>::max();
+ }
+ else
+ {
+ count *= static_cast<int>(arraySize);
+ }
+ }
+ }
+
+ return count;
+}
+
+unsigned int TType::getArraySizeProduct() const
+{
+ if (!mArraySizes)
+ return 1u;
+
+ unsigned int product = 1u;
+
+ for (unsigned int arraySize : *mArraySizes)
+ {
+ product *= arraySize;
+ }
+ return product;
+}
+
+bool TType::isUnsizedArray() const
+{
+ if (!mArraySizes)
+ return false;
+
+ for (unsigned int arraySize : *mArraySizes)
+ {
+ if (arraySize == 0u)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TType::sameNonArrayType(const TType &right) const
+{
+ return (type == right.type && primarySize == right.primarySize &&
+ secondarySize == right.secondarySize && mStructure == right.mStructure);
+}
+
+bool TType::isElementTypeOf(const TType &arrayType) const
+{
+ if (!sameNonArrayType(arrayType))
+ {
+ return false;
+ }
+ if (arrayType.getNumArraySizes() != getNumArraySizes() + 1u)
+ {
+ return false;
+ }
+ if (isArray())
+ {
+ for (size_t i = 0; i < mArraySizes->size(); ++i)
+ {
+ if ((*mArraySizes)[i] != (*arrayType.mArraySizes)[i])
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes)
+{
+ size_t newArraySizesSize = newArraySizes ? newArraySizes->size() : 0;
+ for (size_t i = 0u; i < getNumArraySizes(); ++i)
+ {
+ if ((*mArraySizes)[i] == 0)
+ {
+ if (i < newArraySizesSize)
+ {
+ ASSERT(newArraySizes != nullptr);
+ (*mArraySizes)[i] = (*newArraySizes)[i];
+ }
+ else
+ {
+ (*mArraySizes)[i] = 1u;
+ }
+ }
+ }
+ invalidateMangledName();
+}
+
+void TType::sizeOutermostUnsizedArray(unsigned int arraySize)
+{
+ ASSERT(isArray());
+ ASSERT(mArraySizes->back() == 0u);
+ mArraySizes->back() = arraySize;
+}
+
+void TType::setBasicType(TBasicType t)
+{
+ if (type != t)
+ {
+ type = t;
+ invalidateMangledName();
+ }
+}
+
+void TType::setPrimarySize(unsigned char ps)
+{
+ if (primarySize != ps)
+ {
+ ASSERT(ps <= 4);
+ primarySize = ps;
+ invalidateMangledName();
+ }
+}
+
+void TType::setSecondarySize(unsigned char ss)
+{
+ if (secondarySize != ss)
+ {
+ ASSERT(ss <= 4);
+ secondarySize = ss;
+ invalidateMangledName();
+ }
+}
+
+void TType::makeArray(unsigned int s)
+{
+ if (!mArraySizes)
+ mArraySizes = new TVector<unsigned int>();
+
+ mArraySizes->push_back(s);
+ invalidateMangledName();
+}
+
+void TType::makeArrays(const TVector<unsigned int> &sizes)
+{
+ if (!mArraySizes)
+ mArraySizes = new TVector<unsigned int>();
+
+ mArraySizes->insert(mArraySizes->end(), sizes.begin(), sizes.end());
+ invalidateMangledName();
+}
+
+void TType::setArraySize(size_t arrayDimension, unsigned int s)
+{
+ ASSERT(mArraySizes != nullptr);
+ ASSERT(arrayDimension < mArraySizes->size());
+ if (mArraySizes->at(arrayDimension) != s)
+ {
+ (*mArraySizes)[arrayDimension] = s;
+ invalidateMangledName();
+ }
+}
+
+void TType::toArrayElementType()
+{
+ ASSERT(mArraySizes != nullptr);
+ if (mArraySizes->size() > 0)
+ {
+ mArraySizes->pop_back();
+ invalidateMangledName();
+ }
+}
+
+void TType::setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn)
+{
+ if (mInterfaceBlock != interfaceBlockIn)
+ {
+ mInterfaceBlock = interfaceBlockIn;
+ invalidateMangledName();
+ }
+}
+
+const char *TType::getMangledName() const
+{
+ if (mMangledName == nullptr)
+ {
+ mMangledName = buildMangledName();
+ }
+
+ return mMangledName;
+}
+
+void TType::realize()
+{
+ getMangledName();
+}
+
+void TType::invalidateMangledName()
+{
+ mMangledName = nullptr;
+}
+
+void TType::createSamplerSymbols(const ImmutableString &namePrefix,
+ const TString &apiNamePrefix,
+ TVector<const TVariable *> *outputSymbols,
+ TMap<const TVariable *, TString> *outputSymbolsToAPINames,
+ TSymbolTable *symbolTable) const
+{
+ if (isStructureContainingSamplers())
+ {
+ if (isArray())
+ {
+ TType elementType(*this);
+ elementType.toArrayElementType();
+ for (unsigned int arrayIndex = 0u; arrayIndex < getOutermostArraySize(); ++arrayIndex)
+ {
+ std::stringstream elementName = sh::InitializeStream<std::stringstream>();
+ elementName << namePrefix << "_" << arrayIndex;
+ TStringStream elementApiName;
+ elementApiName << apiNamePrefix << "[" << arrayIndex << "]";
+ elementType.createSamplerSymbols(ImmutableString(elementName.str()),
+ elementApiName.str(), outputSymbols,
+ outputSymbolsToAPINames, symbolTable);
+ }
+ }
+ else
+ {
+ mStructure->createSamplerSymbols(namePrefix.data(), apiNamePrefix, outputSymbols,
+ outputSymbolsToAPINames, symbolTable);
+ }
+ return;
+ }
+
+ ASSERT(IsSampler(type));
+ TVariable *variable =
+ new TVariable(symbolTable, namePrefix, new TType(*this), SymbolType::AngleInternal);
+ outputSymbols->push_back(variable);
+ if (outputSymbolsToAPINames)
+ {
+ (*outputSymbolsToAPINames)[variable] = apiNamePrefix;
+ }
+}
+
+TFieldListCollection::TFieldListCollection(const TFieldList *fields)
+ : mFields(fields), mObjectSize(0), mDeepestNesting(0)
+{}
+
+bool TFieldListCollection::containsArrays() const
+{
+ for (const auto *field : *mFields)
+ {
+ const TType *fieldType = field->type();
+ if (fieldType->isArray() || fieldType->isStructureContainingArrays())
+ return true;
+ }
+ return false;
+}
+
+bool TFieldListCollection::containsMatrices() const
+{
+ for (const auto *field : *mFields)
+ {
+ const TType *fieldType = field->type();
+ if (fieldType->isMatrix() || fieldType->isStructureContainingMatrices())
+ return true;
+ }
+ return false;
+}
+
+bool TFieldListCollection::containsType(TBasicType type) const
+{
+ for (const auto *field : *mFields)
+ {
+ const TType *fieldType = field->type();
+ if (fieldType->getBasicType() == type || fieldType->isStructureContainingType(type))
+ return true;
+ }
+ return false;
+}
+
+bool TFieldListCollection::containsSamplers() const
+{
+ for (const auto *field : *mFields)
+ {
+ const TType *fieldType = field->type();
+ if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers())
+ return true;
+ }
+ return false;
+}
+
+TString TFieldListCollection::buildMangledFieldList() const
+{
+ TString mangledName;
+ for (const auto *field : *mFields)
+ {
+ mangledName += field->type()->getMangledName();
+ }
+ return mangledName;
+}
+
+size_t TFieldListCollection::calculateObjectSize() const
+{
+ size_t size = 0;
+ for (const TField *field : *mFields)
+ {
+ size_t fieldSize = field->type()->getObjectSize();
+ if (fieldSize > INT_MAX - size)
+ size = INT_MAX;
+ else
+ size += fieldSize;
+ }
+ return size;
+}
+
+size_t TFieldListCollection::objectSize() const
+{
+ if (mObjectSize == 0)
+ mObjectSize = calculateObjectSize();
+ return mObjectSize;
+}
+
+int TFieldListCollection::getLocationCount() const
+{
+ int count = 0;
+ for (const TField *field : *mFields)
+ {
+ int fieldCount = field->type()->getLocationCount();
+ if (fieldCount > std::numeric_limits<int>::max() - count)
+ {
+ count = std::numeric_limits<int>::max();
+ }
+ else
+ {
+ count += fieldCount;
+ }
+ }
+ return count;
+}
+
+int TFieldListCollection::deepestNesting() const
+{
+ if (mDeepestNesting == 0)
+ mDeepestNesting = calculateDeepestNesting();
+ return mDeepestNesting;
+}
+
+const TString &TFieldListCollection::mangledFieldList() const
+{
+ if (mMangledFieldList.empty())
+ mMangledFieldList = buildMangledFieldList();
+ return mMangledFieldList;
+}
+
+int TFieldListCollection::calculateDeepestNesting() const
+{
+ int maxNesting = 0;
+ for (size_t i = 0; i < mFields->size(); ++i)
+ maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting());
+ return 1 + maxNesting;
+}
+
+// TPublicType implementation.
+void TPublicType::initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q)
+{
+ typeSpecifierNonArray = typeSpecifier;
+ layoutQualifier = TLayoutQualifier::Create();
+ memoryQualifier = TMemoryQualifier::Create();
+ qualifier = q;
+ invariant = false;
+ precision = EbpUndefined;
+ arraySizes = nullptr;
+}
+
+void TPublicType::initializeBasicType(TBasicType basicType)
+{
+ typeSpecifierNonArray.type = basicType;
+ typeSpecifierNonArray.primarySize = 1;
+ typeSpecifierNonArray.secondarySize = 1;
+ layoutQualifier = TLayoutQualifier::Create();
+ memoryQualifier = TMemoryQualifier::Create();
+ qualifier = EvqTemporary;
+ invariant = false;
+ precision = EbpUndefined;
+ arraySizes = nullptr;
+}
+
+bool TPublicType::isStructureContainingArrays() const
+{
+ if (!typeSpecifierNonArray.userDef)
+ {
+ return false;
+ }
+
+ return typeSpecifierNonArray.userDef->containsArrays();
+}
+
+bool TPublicType::isStructureContainingType(TBasicType t) const
+{
+ if (!typeSpecifierNonArray.userDef)
+ {
+ return false;
+ }
+
+ return typeSpecifierNonArray.userDef->containsType(t);
+}
+
+void TPublicType::setArraySizes(TVector<unsigned int> *sizes)
+{
+ arraySizes = sizes;
+}
+
+bool TPublicType::isArray() const
+{
+ return arraySizes && !arraySizes->empty();
+}
+
+void TPublicType::clearArrayness()
+{
+ arraySizes = nullptr;
+}
+
+bool TPublicType::isAggregate() const
+{
+ return isArray() || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/Types.h b/gfx/angle/checkout/src/compiler/translator/Types.h
new file mode 100644
index 0000000000..2a78d1e114
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/Types.h
@@ -0,0 +1,464 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TYPES_H_
+#define COMPILER_TRANSLATOR_TYPES_H_
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/SymbolUniqueId.h"
+
+namespace sh
+{
+
+struct TPublicType;
+class TType;
+class TInterfaceBlock;
+class TStructure;
+class TSymbol;
+class TVariable;
+class TIntermSymbol;
+class TSymbolTable;
+
+class TField : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TField(TType *type, const ImmutableString &name, const TSourceLoc &line, SymbolType symbolType)
+ : mType(type), mName(name), mLine(line), mSymbolType(symbolType)
+ {
+ ASSERT(mSymbolType != SymbolType::Empty);
+ }
+
+ // TODO(alokp): We should only return const type.
+ // Fix it by tweaking grammar.
+ TType *type() { return mType; }
+ const TType *type() const { return mType; }
+ const ImmutableString &name() const { return mName; }
+ const TSourceLoc &line() const { return mLine; }
+ SymbolType symbolType() const { return mSymbolType; }
+
+ private:
+ TType *mType;
+ const ImmutableString mName;
+ const TSourceLoc mLine;
+ const SymbolType mSymbolType;
+};
+
+typedef TVector<TField *> TFieldList;
+
+class TFieldListCollection : angle::NonCopyable
+{
+ public:
+ const TFieldList &fields() const { return *mFields; }
+
+ bool containsArrays() const;
+ bool containsMatrices() const;
+ bool containsType(TBasicType t) const;
+ bool containsSamplers() const;
+
+ size_t objectSize() const;
+ // How many locations the field list consumes as a uniform.
+ int getLocationCount() const;
+ int deepestNesting() const;
+ const TString &mangledFieldList() const;
+
+ protected:
+ TFieldListCollection(const TFieldList *fields);
+
+ const TFieldList *mFields;
+
+ private:
+ size_t calculateObjectSize() const;
+ int calculateDeepestNesting() const;
+ TString buildMangledFieldList() const;
+
+ mutable size_t mObjectSize;
+ mutable int mDeepestNesting;
+ mutable TString mMangledFieldList;
+};
+
+//
+// Base class for things that have a type.
+//
+class TType
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TType();
+ explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1);
+ TType(TBasicType t,
+ TPrecision p,
+ TQualifier q = EvqTemporary,
+ unsigned char ps = 1,
+ unsigned char ss = 1);
+ explicit TType(const TPublicType &p);
+ TType(const TStructure *userDef, bool isStructSpecifier);
+ TType(const TInterfaceBlock *interfaceBlockIn,
+ TQualifier qualifierIn,
+ TLayoutQualifier layoutQualifierIn);
+ TType(const TType &t);
+ TType &operator=(const TType &t);
+
+ constexpr TType(TBasicType t,
+ TPrecision p,
+ TQualifier q,
+ unsigned char ps,
+ unsigned char ss,
+ const char *mangledName)
+ : type(t),
+ precision(p),
+ qualifier(q),
+ invariant(false),
+ memoryQualifier(TMemoryQualifier::Create()),
+ layoutQualifier(TLayoutQualifier::Create()),
+ primarySize(ps),
+ secondarySize(ss),
+ mArraySizes(nullptr),
+ mInterfaceBlock(nullptr),
+ mStructure(nullptr),
+ mIsStructSpecifier(false),
+ mMangledName(mangledName)
+ {}
+
+ constexpr TType(TType &&t)
+ : type(t.type),
+ precision(t.precision),
+ qualifier(t.qualifier),
+ invariant(t.invariant),
+ memoryQualifier(t.memoryQualifier),
+ layoutQualifier(t.layoutQualifier),
+ primarySize(t.primarySize),
+ secondarySize(t.secondarySize),
+ mArraySizes(t.mArraySizes),
+ mInterfaceBlock(t.mInterfaceBlock),
+ mStructure(t.mStructure),
+ mIsStructSpecifier(t.mIsStructSpecifier),
+ mMangledName(t.mMangledName)
+ {}
+
+ constexpr TBasicType getBasicType() const { return type; }
+ void setBasicType(TBasicType t);
+
+ TPrecision getPrecision() const { return precision; }
+ void setPrecision(TPrecision p) { precision = p; }
+
+ constexpr TQualifier getQualifier() const { return qualifier; }
+ void setQualifier(TQualifier q) { qualifier = q; }
+
+ bool isInvariant() const { return invariant; }
+
+ void setInvariant(bool i) { invariant = i; }
+
+ TMemoryQualifier getMemoryQualifier() const { return memoryQualifier; }
+ void setMemoryQualifier(const TMemoryQualifier &mq) { memoryQualifier = mq; }
+
+ TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; }
+ void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; }
+
+ int getNominalSize() const { return primarySize; }
+ int getSecondarySize() const { return secondarySize; }
+ int getCols() const
+ {
+ ASSERT(isMatrix());
+ return primarySize;
+ }
+ int getRows() const
+ {
+ ASSERT(isMatrix());
+ return secondarySize;
+ }
+ void setPrimarySize(unsigned char ps);
+ void setSecondarySize(unsigned char ss);
+
+ // Full size of single instance of type
+ size_t getObjectSize() const;
+
+ // Get how many locations this type consumes as a uniform.
+ int getLocationCount() const;
+
+ bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
+ bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; }
+ bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); }
+ bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; }
+ size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; }
+ const TVector<unsigned int> *getArraySizes() const { return mArraySizes; }
+ unsigned int getArraySizeProduct() const;
+ bool isUnsizedArray() const;
+ unsigned int getOutermostArraySize() const
+ {
+ ASSERT(isArray());
+ return mArraySizes->back();
+ }
+ void makeArray(unsigned int s);
+
+ // sizes contain new outermost array sizes.
+ void makeArrays(const TVector<unsigned int> &sizes);
+ // Here, the array dimension value 0 corresponds to the innermost array.
+ void setArraySize(size_t arrayDimension, unsigned int s);
+
+ // Will set unsized array sizes according to newArraySizes. In case there are more
+ // unsized arrays than there are sizes in newArraySizes, defaults to setting any
+ // remaining array sizes to 1.
+ void sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes);
+
+ // Will size the outermost array according to arraySize.
+ void sizeOutermostUnsizedArray(unsigned int arraySize);
+
+ // Note that the array element type might still be an array type in GLSL ES version >= 3.10.
+ void toArrayElementType();
+
+ const TInterfaceBlock *getInterfaceBlock() const { return mInterfaceBlock; }
+ void setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn);
+ bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
+
+ bool isVector() const { return primarySize > 1 && secondarySize == 1; }
+ bool isScalar() const
+ {
+ return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray();
+ }
+ bool isScalarFloat() const { return isScalar() && type == EbtFloat; }
+ bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); }
+
+ bool canBeConstructed() const;
+
+ const TStructure *getStruct() const { return mStructure; }
+
+ static constexpr char GetSizeMangledName(unsigned char primarySize, unsigned char secondarySize)
+ {
+ unsigned int sizeKey = (secondarySize - 1u) * 4u + primarySize - 1u;
+ if (sizeKey < 10u)
+ {
+ return static_cast<char>('0' + sizeKey);
+ }
+ return static_cast<char>('A' + sizeKey - 10);
+ }
+ const char *getMangledName() const;
+
+ bool sameNonArrayType(const TType &right) const;
+
+ // Returns true if arrayType is an array made of this type.
+ bool isElementTypeOf(const TType &arrayType) const;
+
+ bool operator==(const TType &right) const
+ {
+ size_t numArraySizesL = getNumArraySizes();
+ size_t numArraySizesR = right.getNumArraySizes();
+ bool arraySizesEqual = numArraySizesL == numArraySizesR &&
+ (numArraySizesL == 0 || *mArraySizes == *right.mArraySizes);
+ return type == right.type && primarySize == right.primarySize &&
+ secondarySize == right.secondarySize && arraySizesEqual &&
+ mStructure == right.mStructure;
+ // don't check the qualifier, it's not ever what's being sought after
+ }
+ bool operator!=(const TType &right) const { return !operator==(right); }
+ bool operator<(const TType &right) const
+ {
+ if (type != right.type)
+ return type < right.type;
+ if (primarySize != right.primarySize)
+ return primarySize < right.primarySize;
+ if (secondarySize != right.secondarySize)
+ return secondarySize < right.secondarySize;
+ size_t numArraySizesL = getNumArraySizes();
+ size_t numArraySizesR = right.getNumArraySizes();
+ if (numArraySizesL != numArraySizesR)
+ return numArraySizesL < numArraySizesR;
+ for (size_t i = 0; i < numArraySizesL; ++i)
+ {
+ if ((*mArraySizes)[i] != (*right.mArraySizes)[i])
+ return (*mArraySizes)[i] < (*right.mArraySizes)[i];
+ }
+ if (mStructure != right.mStructure)
+ return mStructure < right.mStructure;
+
+ return false;
+ }
+
+ const char *getBasicString() const { return sh::getBasicString(type); }
+
+ const char *getPrecisionString() const { return sh::getPrecisionString(precision); }
+ const char *getQualifierString() const { return sh::getQualifierString(qualifier); }
+
+ const char *getBuiltInTypeNameString() const;
+
+ // If this type is a struct, returns the deepest struct nesting of
+ // any field in the struct. For example:
+ // struct nesting1 {
+ // vec4 position;
+ // };
+ // struct nesting2 {
+ // nesting1 field1;
+ // vec4 field2;
+ // };
+ // For type "nesting2", this method would return 2 -- the number
+ // of structures through which indirection must occur to reach the
+ // deepest field (nesting2.field1.position).
+ int getDeepestStructNesting() const;
+
+ bool isNamelessStruct() const;
+
+ bool isStructureContainingArrays() const;
+ bool isStructureContainingMatrices() const;
+ bool isStructureContainingType(TBasicType t) const;
+ bool isStructureContainingSamplers() const;
+
+ bool isStructSpecifier() const { return mIsStructSpecifier; }
+
+ // Return true if variables of this type should be replaced with an inline constant value if
+ // such is available. False will be returned in cases where output doesn't support
+ // TIntermConstantUnion nodes of the type, or if the type contains a lot of fields and creating
+ // several copies of it in the output code is undesirable for performance.
+ bool canReplaceWithConstantUnion() const;
+
+ // The char arrays passed in must be pool allocated or static.
+ void createSamplerSymbols(const ImmutableString &namePrefix,
+ const TString &apiNamePrefix,
+ TVector<const TVariable *> *outputSymbols,
+ TMap<const TVariable *, TString> *outputSymbolsToAPINames,
+ TSymbolTable *symbolTable) const;
+
+ // Initializes all lazily-initialized members.
+ void realize();
+
+ bool isSampler() const { return IsSampler(type); }
+ bool isAtomicCounter() const { return IsAtomicCounter(type); }
+
+ private:
+ void invalidateMangledName();
+ const char *buildMangledName() const;
+
+ TBasicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ bool invariant;
+ TMemoryQualifier memoryQualifier;
+ TLayoutQualifier layoutQualifier;
+ unsigned char primarySize; // size of vector or cols matrix
+ unsigned char secondarySize; // rows of a matrix
+
+ // Used to make an array type. Outermost array size is stored at the end of the vector. Having 0
+ // in this vector means an unsized array.
+ TVector<unsigned int> *mArraySizes;
+
+ // This is set only in the following two cases:
+ // 1) Represents an interface block.
+ // 2) Represents the member variable of an unnamed interface block.
+ // It's nullptr also for members of named interface blocks.
+ const TInterfaceBlock *mInterfaceBlock;
+
+ // nullptr unless this is a struct
+ const TStructure *mStructure;
+ bool mIsStructSpecifier;
+
+ mutable const char *mMangledName;
+};
+
+// TTypeSpecifierNonArray stores all of the necessary fields for type_specifier_nonarray from the
+// grammar
+struct TTypeSpecifierNonArray
+{
+ TBasicType type;
+ unsigned char primarySize; // size of vector or cols of matrix
+ unsigned char secondarySize; // rows of matrix
+ const TStructure *userDef;
+ TSourceLoc line;
+
+ // true if the type was defined by a struct specifier rather than a reference to a type name.
+ bool isStructSpecifier;
+
+ void initialize(TBasicType aType, const TSourceLoc &aLine)
+ {
+ ASSERT(aType != EbtStruct);
+ type = aType;
+ primarySize = 1;
+ secondarySize = 1;
+ userDef = nullptr;
+ line = aLine;
+ isStructSpecifier = false;
+ }
+
+ void initializeStruct(const TStructure *aUserDef,
+ bool aIsStructSpecifier,
+ const TSourceLoc &aLine)
+ {
+ type = EbtStruct;
+ primarySize = 1;
+ secondarySize = 1;
+ userDef = aUserDef;
+ line = aLine;
+ isStructSpecifier = aIsStructSpecifier;
+ }
+
+ void setAggregate(unsigned char size) { primarySize = size; }
+
+ void setMatrix(unsigned char columns, unsigned char rows)
+ {
+ ASSERT(columns > 1 && rows > 1 && columns <= 4 && rows <= 4);
+ primarySize = columns;
+ secondarySize = rows;
+ }
+
+ bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
+
+ bool isVector() const { return primarySize > 1 && secondarySize == 1; }
+};
+
+//
+// This is a workaround for a problem with the yacc stack, It can't have
+// types that it thinks have non-trivial constructors. It should
+// just be used while recognizing the grammar, not anything else. Pointers
+// could be used, but also trying to avoid lots of memory management overhead.
+//
+// Not as bad as it looks, there is no actual assumption that the fields
+// match up or are name the same or anything like that.
+//
+struct TPublicType
+{
+ // Must have a trivial default constructor since it is used in YYSTYPE.
+ TPublicType() = default;
+
+ void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q);
+ void initializeBasicType(TBasicType basicType);
+
+ TBasicType getBasicType() const { return typeSpecifierNonArray.type; }
+ void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; }
+
+ unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; }
+ unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; }
+
+ const TStructure *getUserDef() const { return typeSpecifierNonArray.userDef; }
+ const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
+
+ bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
+
+ bool isStructureContainingArrays() const;
+ bool isStructureContainingType(TBasicType t) const;
+ void setArraySizes(TVector<unsigned int> *sizes);
+ bool isArray() const;
+ void clearArrayness();
+ bool isAggregate() const;
+
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TLayoutQualifier layoutQualifier;
+ TMemoryQualifier memoryQualifier;
+ TQualifier qualifier;
+ bool invariant;
+ TPrecision precision;
+
+ // Either nullptr or empty in case the type is not an array. The last element is the outermost
+ // array size. Note that due to bison restrictions, copies of the public type created by the
+ // copy constructor share the same arraySizes pointer.
+ const TVector<unsigned int> *arraySizes;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TYPES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp
new file mode 100644
index 0000000000..11e337dabd
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp
@@ -0,0 +1,1108 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UtilsHLSL.cpp:
+// Utility methods for GLSL to HLSL translation.
+//
+
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/StructureHLSL.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void DisambiguateFunctionNameForParameterType(const TType &paramType,
+ TString *disambiguatingStringOut)
+{
+ // Parameter types are only added to function names if they are ambiguous according to the
+ // native HLSL compiler. Other parameter types are not added to function names to avoid
+ // making function names longer.
+ if (paramType.getObjectSize() == 4 && paramType.getBasicType() == EbtFloat)
+ {
+ // Disambiguation is needed for float2x2 and float4 parameters. These are the only
+ // built-in types that HLSL thinks are identical. float2x3 and float3x2 are different
+ // types, for example.
+ *disambiguatingStringOut += "_" + TypeString(paramType);
+ }
+ else if (paramType.getBasicType() == EbtStruct)
+ {
+ // Disambiguation is needed for struct parameters, since HLSL thinks that structs with
+ // the same fields but a different name are identical.
+ ASSERT(paramType.getStruct()->symbolType() != SymbolType::Empty);
+ *disambiguatingStringOut += "_" + TypeString(paramType);
+ }
+}
+
+} // anonymous namespace
+
+const char *SamplerString(const TBasicType type)
+{
+ if (IsShadowSampler(type))
+ {
+ return "SamplerComparisonState";
+ }
+ else
+ {
+ return "SamplerState";
+ }
+}
+
+const char *SamplerString(HLSLTextureGroup type)
+{
+ if (type >= HLSL_COMPARISON_SAMPLER_GROUP_BEGIN && type <= HLSL_COMPARISON_SAMPLER_GROUP_END)
+ {
+ return "SamplerComparisonState";
+ }
+ else
+ {
+ return "SamplerState";
+ }
+}
+
+HLSLTextureGroup TextureGroup(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
+
+{
+ switch (type)
+ {
+ case EbtSampler2D:
+ return HLSL_TEXTURE_2D;
+ case EbtSamplerCube:
+ return HLSL_TEXTURE_CUBE;
+ case EbtSamplerExternalOES:
+ return HLSL_TEXTURE_2D;
+ case EbtSampler2DArray:
+ return HLSL_TEXTURE_2D_ARRAY;
+ case EbtSampler3D:
+ return HLSL_TEXTURE_3D;
+ case EbtSampler2DMS:
+ return HLSL_TEXTURE_2D_MS;
+ case EbtSampler2DMSArray:
+ return HLSL_TEXTURE_2D_MS_ARRAY;
+ case EbtISampler2D:
+ return HLSL_TEXTURE_2D_INT4;
+ case EbtISampler3D:
+ return HLSL_TEXTURE_3D_INT4;
+ case EbtISamplerCube:
+ return HLSL_TEXTURE_2D_ARRAY_INT4;
+ case EbtISampler2DArray:
+ return HLSL_TEXTURE_2D_ARRAY_INT4;
+ case EbtISampler2DMS:
+ return HLSL_TEXTURE_2D_MS_INT4;
+ case EbtISampler2DMSArray:
+ return HLSL_TEXTURE_2D_MS_ARRAY_INT4;
+ case EbtUSampler2D:
+ return HLSL_TEXTURE_2D_UINT4;
+ case EbtUSampler3D:
+ return HLSL_TEXTURE_3D_UINT4;
+ case EbtUSamplerCube:
+ return HLSL_TEXTURE_2D_ARRAY_UINT4;
+ case EbtUSampler2DArray:
+ return HLSL_TEXTURE_2D_ARRAY_UINT4;
+ case EbtUSampler2DMS:
+ return HLSL_TEXTURE_2D_MS_UINT4;
+ case EbtUSampler2DMSArray:
+ return HLSL_TEXTURE_2D_MS_ARRAY_UINT4;
+ case EbtSampler2DShadow:
+ return HLSL_TEXTURE_2D_COMPARISON;
+ case EbtSamplerCubeShadow:
+ return HLSL_TEXTURE_CUBE_COMPARISON;
+ case EbtSampler2DArrayShadow:
+ return HLSL_TEXTURE_2D_ARRAY_COMPARISON;
+ case EbtImage2D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return HLSL_TEXTURE_2D;
+ case EiifRGBA8:
+ return HLSL_TEXTURE_2D_UNORM;
+ case EiifRGBA8_SNORM:
+ return HLSL_TEXTURE_2D_SNORM;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtIImage2D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return HLSL_TEXTURE_2D_INT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtUImage2D:
+ {
+ switch (imageInternalFormat)
+ {
+
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return HLSL_TEXTURE_2D_UINT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtImage3D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return HLSL_TEXTURE_3D;
+ case EiifRGBA8:
+ return HLSL_TEXTURE_3D_UNORM;
+ case EiifRGBA8_SNORM:
+ return HLSL_TEXTURE_3D_SNORM;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtIImage3D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return HLSL_TEXTURE_3D_INT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtUImage3D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return HLSL_TEXTURE_3D_UINT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtImage2DArray:
+ case EbtImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return HLSL_TEXTURE_2D_ARRAY;
+ case EiifRGBA8:
+ return HLSL_TEXTURE_2D_ARRAY_UNORN;
+ case EiifRGBA8_SNORM:
+ return HLSL_TEXTURE_2D_ARRAY_SNORM;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtIImage2DArray:
+ case EbtIImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return HLSL_TEXTURE_2D_ARRAY_INT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ case EbtUImage2DArray:
+ case EbtUImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return HLSL_TEXTURE_2D_ARRAY_UINT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+ }
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return HLSL_TEXTURE_UNKNOWN;
+#endif
+ }
+}
+
+const char *TextureString(const HLSLTextureGroup textureGroup)
+{
+ switch (textureGroup)
+ {
+ case HLSL_TEXTURE_2D:
+ return "Texture2D<float4>";
+ case HLSL_TEXTURE_CUBE:
+ return "TextureCube<float4>";
+ case HLSL_TEXTURE_2D_ARRAY:
+ return "Texture2DArray<float4>";
+ case HLSL_TEXTURE_3D:
+ return "Texture3D<float4>";
+ case HLSL_TEXTURE_2D_UNORM:
+ return "Texture2D<unorm float4>";
+ case HLSL_TEXTURE_CUBE_UNORM:
+ return "TextureCube<unorm float4>";
+ case HLSL_TEXTURE_2D_ARRAY_UNORN:
+ return "Texture2DArray<unorm float4>";
+ case HLSL_TEXTURE_3D_UNORM:
+ return "Texture3D<unorm float4>";
+ case HLSL_TEXTURE_2D_SNORM:
+ return "Texture2D<snorm float4>";
+ case HLSL_TEXTURE_CUBE_SNORM:
+ return "TextureCube<snorm float4>";
+ case HLSL_TEXTURE_2D_ARRAY_SNORM:
+ return "Texture2DArray<snorm float4>";
+ case HLSL_TEXTURE_3D_SNORM:
+ return "Texture3D<snorm float4>";
+ case HLSL_TEXTURE_2D_MS:
+ return "Texture2DMS<float4>";
+ case HLSL_TEXTURE_2D_MS_ARRAY:
+ return "Texture2DMSArray<float4>";
+ case HLSL_TEXTURE_2D_INT4:
+ return "Texture2D<int4>";
+ case HLSL_TEXTURE_3D_INT4:
+ return "Texture3D<int4>";
+ case HLSL_TEXTURE_2D_ARRAY_INT4:
+ return "Texture2DArray<int4>";
+ case HLSL_TEXTURE_2D_MS_INT4:
+ return "Texture2DMS<int4>";
+ case HLSL_TEXTURE_2D_MS_ARRAY_INT4:
+ return "Texture2DMSArray<int4>";
+ case HLSL_TEXTURE_2D_UINT4:
+ return "Texture2D<uint4>";
+ case HLSL_TEXTURE_3D_UINT4:
+ return "Texture3D<uint4>";
+ case HLSL_TEXTURE_2D_ARRAY_UINT4:
+ return "Texture2DArray<uint4>";
+ case HLSL_TEXTURE_2D_MS_UINT4:
+ return "Texture2DMS<uint4>";
+ case HLSL_TEXTURE_2D_MS_ARRAY_UINT4:
+ return "Texture2DMSArray<uint4>";
+ case HLSL_TEXTURE_2D_COMPARISON:
+ return "Texture2D";
+ case HLSL_TEXTURE_CUBE_COMPARISON:
+ return "TextureCube";
+ case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
+ return "Texture2DArray";
+ default:
+ UNREACHABLE();
+ }
+
+ return "<unknown read texture type>";
+}
+
+const char *TextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
+{
+ return TextureString(TextureGroup(type, imageInternalFormat));
+}
+
+const char *TextureGroupSuffix(const HLSLTextureGroup type)
+{
+ switch (type)
+ {
+ case HLSL_TEXTURE_2D:
+ return "2D";
+ case HLSL_TEXTURE_CUBE:
+ return "Cube";
+ case HLSL_TEXTURE_2D_ARRAY:
+ return "2DArray";
+ case HLSL_TEXTURE_3D:
+ return "3D";
+ case HLSL_TEXTURE_2D_UNORM:
+ return "2D_unorm_float4_";
+ case HLSL_TEXTURE_CUBE_UNORM:
+ return "Cube_unorm_float4_";
+ case HLSL_TEXTURE_2D_ARRAY_UNORN:
+ return "2DArray_unorm_float4_";
+ case HLSL_TEXTURE_3D_UNORM:
+ return "3D_unorm_float4_";
+ case HLSL_TEXTURE_2D_SNORM:
+ return "2D_snorm_float4_";
+ case HLSL_TEXTURE_CUBE_SNORM:
+ return "Cube_snorm_float4_";
+ case HLSL_TEXTURE_2D_ARRAY_SNORM:
+ return "2DArray_snorm_float4_";
+ case HLSL_TEXTURE_3D_SNORM:
+ return "3D_snorm_float4_";
+ case HLSL_TEXTURE_2D_MS:
+ return "2DMS";
+ case HLSL_TEXTURE_2D_MS_ARRAY:
+ return "2DMSArray";
+ case HLSL_TEXTURE_2D_INT4:
+ return "2D_int4_";
+ case HLSL_TEXTURE_3D_INT4:
+ return "3D_int4_";
+ case HLSL_TEXTURE_2D_ARRAY_INT4:
+ return "2DArray_int4_";
+ case HLSL_TEXTURE_2D_MS_INT4:
+ return "2DMS_int4_";
+ case HLSL_TEXTURE_2D_MS_ARRAY_INT4:
+ return "2DMSArray_int4_";
+ case HLSL_TEXTURE_2D_UINT4:
+ return "2D_uint4_";
+ case HLSL_TEXTURE_3D_UINT4:
+ return "3D_uint4_";
+ case HLSL_TEXTURE_2D_ARRAY_UINT4:
+ return "2DArray_uint4_";
+ case HLSL_TEXTURE_2D_MS_UINT4:
+ return "2DMS_uint4_";
+ case HLSL_TEXTURE_2D_MS_ARRAY_UINT4:
+ return "2DMSArray_uint4_";
+ case HLSL_TEXTURE_2D_COMPARISON:
+ return "2D_comparison";
+ case HLSL_TEXTURE_CUBE_COMPARISON:
+ return "Cube_comparison";
+ case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
+ return "2DArray_comparison";
+ default:
+ UNREACHABLE();
+ }
+
+ return "<unknown texture type>";
+}
+
+const char *TextureGroupSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat)
+{
+ return TextureGroupSuffix(TextureGroup(type, imageInternalFormat));
+}
+
+const char *TextureTypeSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
+{
+ switch (type)
+ {
+ case EbtISamplerCube:
+ return "Cube_int4_";
+ case EbtUSamplerCube:
+ return "Cube_uint4_";
+ case EbtSamplerExternalOES:
+ return "_External";
+ case EbtImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return "Cube_float4_";
+ case EiifRGBA8:
+ return "Cube_unorm_float4_";
+ case EiifRGBA8_SNORM:
+ return "Cube_snorm_float4_";
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtIImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return "Cube_int4_";
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtUImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return "Cube_uint4_";
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ default:
+ // All other types are identified by their group suffix
+ return TextureGroupSuffix(type, imageInternalFormat);
+ }
+#if !UNREACHABLE_IS_NORETURN
+ UNREACHABLE();
+ return "_TTS_invalid_";
+#endif
+}
+
+HLSLRWTextureGroup RWTextureGroup(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat)
+
+{
+ switch (type)
+ {
+ case EbtImage2D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return HLSL_RWTEXTURE_2D_FLOAT4;
+ case EiifRGBA8:
+ return HLSL_RWTEXTURE_2D_UNORM;
+ case EiifRGBA8_SNORM:
+ return HLSL_RWTEXTURE_2D_SNORM;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtIImage2D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return HLSL_RWTEXTURE_2D_INT4;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtUImage2D:
+ {
+ switch (imageInternalFormat)
+ {
+
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return HLSL_RWTEXTURE_2D_UINT4;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtImage3D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return HLSL_RWTEXTURE_3D_FLOAT4;
+ case EiifRGBA8:
+ return HLSL_RWTEXTURE_3D_UNORM;
+ case EiifRGBA8_SNORM:
+ return HLSL_RWTEXTURE_3D_SNORM;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtIImage3D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return HLSL_RWTEXTURE_3D_INT4;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtUImage3D:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return HLSL_RWTEXTURE_3D_UINT4;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtImage2DArray:
+ case EbtImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return HLSL_RWTEXTURE_2D_ARRAY_FLOAT4;
+ case EiifRGBA8:
+ return HLSL_RWTEXTURE_2D_ARRAY_UNORN;
+ case EiifRGBA8_SNORM:
+ return HLSL_RWTEXTURE_2D_ARRAY_SNORM;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtIImage2DArray:
+ case EbtIImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return HLSL_RWTEXTURE_2D_ARRAY_INT4;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtUImage2DArray:
+ case EbtUImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return HLSL_RWTEXTURE_2D_ARRAY_UINT4;
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ default:
+ UNREACHABLE();
+ }
+ return HLSL_RWTEXTURE_UNKNOWN;
+}
+
+const char *RWTextureString(const HLSLRWTextureGroup RWTextureGroup)
+{
+ switch (RWTextureGroup)
+ {
+ case HLSL_RWTEXTURE_2D_FLOAT4:
+ return "RWTexture2D<float4>";
+ case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4:
+ return "RWTexture2DArray<float4>";
+ case HLSL_RWTEXTURE_3D_FLOAT4:
+ return "RWTexture3D<float4>";
+ case HLSL_RWTEXTURE_2D_UNORM:
+ return "RWTexture2D<unorm float4>";
+ case HLSL_RWTEXTURE_2D_ARRAY_UNORN:
+ return "RWTexture2DArray<unorm float4>";
+ case HLSL_RWTEXTURE_3D_UNORM:
+ return "RWTexture3D<unorm float4>";
+ case HLSL_RWTEXTURE_2D_SNORM:
+ return "RWTexture2D<snorm float4>";
+ case HLSL_RWTEXTURE_2D_ARRAY_SNORM:
+ return "RWTexture2DArray<snorm float4>";
+ case HLSL_RWTEXTURE_3D_SNORM:
+ return "RWTexture3D<snorm float4>";
+ case HLSL_RWTEXTURE_2D_UINT4:
+ return "RWTexture2D<uint4>";
+ case HLSL_RWTEXTURE_2D_ARRAY_UINT4:
+ return "RWTexture2DArray<uint4>";
+ case HLSL_RWTEXTURE_3D_UINT4:
+ return "RWTexture3D<uint4>";
+ case HLSL_RWTEXTURE_2D_INT4:
+ return "RWTexture2D<int4>";
+ case HLSL_RWTEXTURE_2D_ARRAY_INT4:
+ return "RWTexture2DArray<int4>";
+ case HLSL_RWTEXTURE_3D_INT4:
+ return "RWTexture3D<int4>";
+ default:
+ UNREACHABLE();
+ }
+
+ return "<unknown read and write texture type>";
+}
+
+const char *RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
+{
+ return RWTextureString(RWTextureGroup(type, imageInternalFormat));
+}
+
+const char *RWTextureGroupSuffix(const HLSLRWTextureGroup type)
+{
+ switch (type)
+ {
+ case HLSL_RWTEXTURE_2D_FLOAT4:
+ return "RW2D_float4_";
+ case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4:
+ return "RW2DArray_float4_";
+ case HLSL_RWTEXTURE_3D_FLOAT4:
+ return "RW3D_float4_";
+ case HLSL_RWTEXTURE_2D_UNORM:
+ return "RW2D_unorm_float4_";
+ case HLSL_RWTEXTURE_2D_ARRAY_UNORN:
+ return "RW2DArray_unorm_float4_";
+ case HLSL_RWTEXTURE_3D_UNORM:
+ return "RW3D_unorm_float4_";
+ case HLSL_RWTEXTURE_2D_SNORM:
+ return "RW2D_snorm_float4_";
+ case HLSL_RWTEXTURE_2D_ARRAY_SNORM:
+ return "RW2DArray_snorm_float4_";
+ case HLSL_RWTEXTURE_3D_SNORM:
+ return "RW3D_snorm_float4_";
+ case HLSL_RWTEXTURE_2D_UINT4:
+ return "RW2D_uint4_";
+ case HLSL_RWTEXTURE_2D_ARRAY_UINT4:
+ return "RW2DArray_uint4_";
+ case HLSL_RWTEXTURE_3D_UINT4:
+ return "RW3D_uint4_";
+ case HLSL_RWTEXTURE_2D_INT4:
+ return "RW2D_int4_";
+ case HLSL_RWTEXTURE_2D_ARRAY_INT4:
+ return "RW2DArray_int4_";
+ case HLSL_RWTEXTURE_3D_INT4:
+ return "RW3D_int4_";
+ default:
+ UNREACHABLE();
+ }
+
+ return "<unknown read and write resource>";
+}
+
+const char *RWTextureGroupSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat)
+{
+ return RWTextureGroupSuffix(RWTextureGroup(type, imageInternalFormat));
+}
+
+const char *RWTextureTypeSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat)
+{
+ switch (type)
+ {
+ case EbtImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32F:
+ case EiifRGBA16F:
+ case EiifR32F:
+ return "RWCube_float4_";
+ case EiifRGBA8:
+ return "RWCube_unorm_float4_";
+ case EiifRGBA8_SNORM:
+ return "RWCube_unorm_float4_";
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtIImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32I:
+ case EiifRGBA16I:
+ case EiifRGBA8I:
+ case EiifR32I:
+ return "RWCube_int4_";
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ case EbtUImageCube:
+ {
+ switch (imageInternalFormat)
+ {
+ case EiifRGBA32UI:
+ case EiifRGBA16UI:
+ case EiifRGBA8UI:
+ case EiifR32UI:
+ return "RWCube_uint4_";
+ default:
+ UNREACHABLE();
+ }
+#if !UNREACHABLE_IS_NORETURN
+ break;
+#endif
+ }
+ default:
+ // All other types are identified by their group suffix
+ return RWTextureGroupSuffix(type, imageInternalFormat);
+ }
+#if !UNREACHABLE_IS_NORETURN
+ UNREACHABLE();
+ return "_RWTS_invalid_";
+#endif
+}
+
+TString DecorateField(const ImmutableString &string, const TStructure &structure)
+{
+ if (structure.symbolType() != SymbolType::BuiltIn)
+ {
+ return Decorate(string);
+ }
+
+ return TString(string.data());
+}
+
+TString DecoratePrivate(const ImmutableString &privateText)
+{
+ return "dx_" + TString(privateText.data());
+}
+
+TString Decorate(const ImmutableString &string)
+{
+ if (!string.beginsWith("gl_"))
+ {
+ return "_" + TString(string.data());
+ }
+
+ return TString(string.data());
+}
+
+TString DecorateVariableIfNeeded(const TVariable &variable)
+{
+ if (variable.symbolType() == SymbolType::AngleInternal ||
+ variable.symbolType() == SymbolType::Empty)
+ {
+ // Besides handling internal variables, we generate names for nameless parameters here.
+ const ImmutableString &name = variable.name();
+ // The name should not have a prefix reserved for user-defined variables or functions.
+ ASSERT(!name.beginsWith("f_"));
+ ASSERT(!name.beginsWith("_"));
+ return TString(name.data());
+ }
+ // For user defined variables, combine variable name with unique id
+ // so variables of the same name in different scopes do not get overwritten.
+ else if (variable.symbolType() == SymbolType::UserDefined &&
+ variable.getType().getQualifier() == EvqTemporary)
+ {
+ return Decorate(variable.name()) + str(variable.uniqueId().get());
+ }
+ else
+ {
+ return Decorate(variable.name());
+ }
+}
+
+TString DecorateFunctionIfNeeded(const TFunction *func)
+{
+ if (func->symbolType() == SymbolType::AngleInternal)
+ {
+ // The name should not have a prefix reserved for user-defined variables or functions.
+ ASSERT(!func->name().beginsWith("f_"));
+ ASSERT(!func->name().beginsWith("_"));
+ return TString(func->name().data());
+ }
+ ASSERT(!func->name().beginsWith("gl_"));
+ // Add an additional f prefix to functions so that they're always disambiguated from variables.
+ // This is necessary in the corner case where a variable declaration hides a function that it
+ // uses in its initializer.
+ return "f_" + TString(func->name().data());
+}
+
+TString TypeString(const TType &type)
+{
+ const TStructure *structure = type.getStruct();
+ if (structure)
+ {
+ if (structure->symbolType() != SymbolType::Empty)
+ {
+ return StructNameString(*structure);
+ }
+ else // Nameless structure, define in place
+ {
+ return StructureHLSL::defineNameless(*structure);
+ }
+ }
+ else if (type.isMatrix())
+ {
+ int cols = type.getCols();
+ int rows = type.getRows();
+ return "float" + str(cols) + "x" + str(rows);
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "float";
+ case 2:
+ return "float2";
+ case 3:
+ return "float3";
+ case 4:
+ return "float4";
+ }
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "int";
+ case 2:
+ return "int2";
+ case 3:
+ return "int3";
+ case 4:
+ return "int4";
+ }
+ case EbtUInt:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "uint";
+ case 2:
+ return "uint2";
+ case 3:
+ return "uint3";
+ case 4:
+ return "uint4";
+ }
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "bool";
+ case 2:
+ return "bool2";
+ case 3:
+ return "bool3";
+ case 4:
+ return "bool4";
+ }
+ case EbtVoid:
+ return "void";
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ return "sampler2D";
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ return "samplerCUBE";
+ case EbtSamplerExternalOES:
+ return "sampler2D";
+ case EbtAtomicCounter:
+ // Multiple atomic_uints will be implemented as a single RWByteAddressBuffer
+ return "RWByteAddressBuffer";
+ default:
+ break;
+ }
+ }
+
+ UNREACHABLE();
+ return "<unknown type>";
+}
+
+TString StructNameString(const TStructure &structure)
+{
+ if (structure.symbolType() == SymbolType::Empty)
+ {
+ return "";
+ }
+
+ // For structures at global scope we use a consistent
+ // translation so that we can link between shader stages.
+ if (structure.atGlobalScope())
+ {
+ return Decorate(structure.name());
+ }
+
+ return "ss" + str(structure.uniqueId().get()) + "_" + TString(structure.name().data());
+}
+
+TString QualifiedStructNameString(const TStructure &structure,
+ bool useHLSLRowMajorPacking,
+ bool useStd140Packing)
+{
+ if (structure.symbolType() == SymbolType::Empty)
+ {
+ return "";
+ }
+
+ TString prefix = "";
+
+ // Structs packed with row-major matrices in HLSL are prefixed with "rm"
+ // GLSL column-major maps to HLSL row-major, and the converse is true
+
+ if (useStd140Packing)
+ {
+ prefix += "std_";
+ }
+
+ if (useHLSLRowMajorPacking)
+ {
+ prefix += "rm_";
+ }
+
+ return prefix + StructNameString(structure);
+}
+
+const char *InterpolationString(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqVaryingIn:
+ return "";
+ case EvqFragmentIn:
+ return "";
+ case EvqSmoothIn:
+ return "linear";
+ case EvqFlatIn:
+ return "nointerpolation";
+ case EvqCentroidIn:
+ return "centroid";
+ case EvqVaryingOut:
+ return "";
+ case EvqVertexOut:
+ return "";
+ case EvqSmoothOut:
+ return "linear";
+ case EvqFlatOut:
+ return "nointerpolation";
+ case EvqCentroidOut:
+ return "centroid";
+ default:
+ UNREACHABLE();
+ }
+
+ return "";
+}
+
+const char *QualifierString(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqIn:
+ return "in";
+ case EvqOut:
+ return "inout"; // 'out' results in an HLSL error if not all fields are written, for
+ // GLSL it's undefined
+ case EvqInOut:
+ return "inout";
+ case EvqConstReadOnly:
+ return "const";
+ default:
+ UNREACHABLE();
+ }
+
+ return "";
+}
+
+TString DisambiguateFunctionName(const TFunction *func)
+{
+ TString disambiguatingString;
+ size_t paramCount = func->getParamCount();
+ for (size_t i = 0; i < paramCount; ++i)
+ {
+ DisambiguateFunctionNameForParameterType(func->getParam(i)->getType(),
+ &disambiguatingString);
+ }
+ return disambiguatingString;
+}
+
+TString DisambiguateFunctionName(const TIntermSequence *args)
+{
+ TString disambiguatingString;
+ for (TIntermNode *arg : *args)
+ {
+ ASSERT(arg->getAsTyped());
+ DisambiguateFunctionNameForParameterType(arg->getAsTyped()->getType(),
+ &disambiguatingString);
+ }
+ return disambiguatingString;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h
new file mode 100644
index 0000000000..ebd7ab3dc0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h
@@ -0,0 +1,135 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UtilsHLSL.h:
+// Utility methods for GLSL to HLSL translation.
+//
+
+#ifndef COMPILER_TRANSLATOR_UTILSHLSL_H_
+#define COMPILER_TRANSLATOR_UTILSHLSL_H_
+
+#include <vector>
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Types.h"
+
+#include "angle_gl.h"
+
+namespace sh
+{
+
+class TFunction;
+
+// HLSL Texture type for GLSL sampler type and readonly image type.
+enum HLSLTextureGroup
+{
+ // read resources
+ HLSL_TEXTURE_2D,
+ HLSL_TEXTURE_MIN = HLSL_TEXTURE_2D,
+
+ HLSL_TEXTURE_CUBE,
+ HLSL_TEXTURE_2D_ARRAY,
+ HLSL_TEXTURE_3D,
+ HLSL_TEXTURE_2D_UNORM,
+ HLSL_TEXTURE_CUBE_UNORM,
+ HLSL_TEXTURE_2D_ARRAY_UNORN,
+ HLSL_TEXTURE_3D_UNORM,
+ HLSL_TEXTURE_2D_SNORM,
+ HLSL_TEXTURE_CUBE_SNORM,
+ HLSL_TEXTURE_2D_ARRAY_SNORM,
+ HLSL_TEXTURE_3D_SNORM,
+ HLSL_TEXTURE_2D_MS,
+ HLSL_TEXTURE_2D_MS_ARRAY,
+ HLSL_TEXTURE_2D_INT4,
+ HLSL_TEXTURE_3D_INT4,
+ HLSL_TEXTURE_2D_ARRAY_INT4,
+ HLSL_TEXTURE_2D_MS_INT4,
+ HLSL_TEXTURE_2D_MS_ARRAY_INT4,
+ HLSL_TEXTURE_2D_UINT4,
+ HLSL_TEXTURE_3D_UINT4,
+ HLSL_TEXTURE_2D_ARRAY_UINT4,
+ HLSL_TEXTURE_2D_MS_UINT4,
+ HLSL_TEXTURE_2D_MS_ARRAY_UINT4,
+
+ // Comparison samplers
+
+ HLSL_TEXTURE_2D_COMPARISON,
+ HLSL_TEXTURE_CUBE_COMPARISON,
+ HLSL_TEXTURE_2D_ARRAY_COMPARISON,
+
+ HLSL_COMPARISON_SAMPLER_GROUP_BEGIN = HLSL_TEXTURE_2D_COMPARISON,
+ HLSL_COMPARISON_SAMPLER_GROUP_END = HLSL_TEXTURE_2D_ARRAY_COMPARISON,
+
+ HLSL_TEXTURE_UNKNOWN,
+ HLSL_TEXTURE_MAX = HLSL_TEXTURE_UNKNOWN
+};
+
+// HLSL RWTexture type for GLSL read and write image type.
+enum HLSLRWTextureGroup
+{
+ // read/write resource
+ HLSL_RWTEXTURE_2D_FLOAT4,
+ HLSL_RWTEXTURE_MIN = HLSL_RWTEXTURE_2D_FLOAT4,
+ HLSL_RWTEXTURE_2D_ARRAY_FLOAT4,
+ HLSL_RWTEXTURE_3D_FLOAT4,
+ HLSL_RWTEXTURE_2D_UNORM,
+ HLSL_RWTEXTURE_2D_ARRAY_UNORN,
+ HLSL_RWTEXTURE_3D_UNORM,
+ HLSL_RWTEXTURE_2D_SNORM,
+ HLSL_RWTEXTURE_2D_ARRAY_SNORM,
+ HLSL_RWTEXTURE_3D_SNORM,
+ HLSL_RWTEXTURE_2D_UINT4,
+ HLSL_RWTEXTURE_2D_ARRAY_UINT4,
+ HLSL_RWTEXTURE_3D_UINT4,
+ HLSL_RWTEXTURE_2D_INT4,
+ HLSL_RWTEXTURE_2D_ARRAY_INT4,
+ HLSL_RWTEXTURE_3D_INT4,
+
+ HLSL_RWTEXTURE_UNKNOWN,
+ HLSL_RWTEXTURE_MAX = HLSL_RWTEXTURE_UNKNOWN
+};
+
+HLSLTextureGroup TextureGroup(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
+const char *TextureString(const HLSLTextureGroup textureGroup);
+const char *TextureString(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
+const char *TextureGroupSuffix(const HLSLTextureGroup type);
+const char *TextureGroupSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
+const char *TextureTypeSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
+HLSLRWTextureGroup RWTextureGroup(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat);
+const char *RWTextureString(const HLSLRWTextureGroup textureGroup);
+const char *RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat);
+const char *RWTextureGroupSuffix(const HLSLRWTextureGroup type);
+const char *RWTextureGroupSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat);
+const char *RWTextureTypeSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat);
+
+const char *SamplerString(const TBasicType type);
+const char *SamplerString(HLSLTextureGroup type);
+
+// Adds a prefix to user-defined names to avoid naming clashes.
+TString Decorate(const ImmutableString &string);
+TString DecorateVariableIfNeeded(const TVariable &variable);
+TString DecorateFunctionIfNeeded(const TFunction *func);
+TString DecorateField(const ImmutableString &string, const TStructure &structure);
+TString DecoratePrivate(const ImmutableString &privateText);
+TString TypeString(const TType &type);
+TString StructNameString(const TStructure &structure);
+TString QualifiedStructNameString(const TStructure &structure,
+ bool useHLSLRowMajorPacking,
+ bool useStd140Packing);
+const char *InterpolationString(TQualifier qualifier);
+const char *QualifierString(TQualifier qualifier);
+// Parameters may need to be included in function names to disambiguate between overloaded
+// functions.
+TString DisambiguateFunctionName(const TFunction *func);
+TString DisambiguateFunctionName(const TIntermSequence *args);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp
new file mode 100644
index 0000000000..c0ec114741
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp
@@ -0,0 +1,251 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateAST.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class ValidateAST : public TIntermTraverser
+{
+ public:
+ static bool validate(TIntermNode *root,
+ TDiagnostics *diagnostics,
+ const ValidateASTOptions &options);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+ bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+ bool visitIfElse(Visit visit, TIntermIfElse *node) override;
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+ bool visitCase(Visit visit, TIntermCase *node) override;
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *node) override;
+ bool visitBranch(Visit visit, TIntermBranch *node) override;
+ void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override;
+
+ private:
+ ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options);
+
+ // Visit as a generic node
+ void visitNode(Visit visit, TIntermNode *node);
+
+ void expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count);
+
+ bool validateInternal();
+
+ ValidateASTOptions mOptions;
+ TDiagnostics *mDiagnostics;
+
+ // For validateSingleParent:
+ std::map<TIntermNode *, TIntermNode *> mParent;
+ bool mSingleParentFailed = false;
+
+ // For validateNullNodes
+ bool mNullNodesFailed = false;
+};
+
+bool ValidateAST::validate(TIntermNode *root,
+ TDiagnostics *diagnostics,
+ const ValidateASTOptions &options)
+{
+ ValidateAST validate(root, diagnostics, options);
+ root->traverse(&validate);
+ return validate.validateInternal();
+}
+
+ValidateAST::ValidateAST(TIntermNode *root,
+ TDiagnostics *diagnostics,
+ const ValidateASTOptions &options)
+ : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
+{
+ if (mOptions.validateSingleParent)
+ {
+ mParent[root] = nullptr;
+ }
+}
+
+void ValidateAST::visitNode(Visit visit, TIntermNode *node)
+{
+ if (visit == PreVisit && mOptions.validateSingleParent)
+ {
+ size_t childCount = node->getChildCount();
+ for (size_t i = 0; i < childCount; ++i)
+ {
+ TIntermNode *child = node->getChildNode(i);
+ if (mParent.find(child) != mParent.end())
+ {
+ // If child is visited twice but through the same parent, the problem is in one of
+ // the ancestors.
+ if (mParent[child] != node)
+ {
+ mDiagnostics->error(node->getLine(), "Found child with two parents",
+ "<validateSingleParent>");
+ mSingleParentFailed = true;
+ }
+ }
+
+ mParent[child] = node;
+ }
+ }
+}
+
+void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
+{
+ if (visit == PreVisit && mOptions.validateNullNodes)
+ {
+ size_t childCount = node->getChildCount();
+ if (childCount < least_count)
+ {
+ mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
+ mNullNodesFailed = true;
+ }
+
+ for (size_t i = 0; i < childCount; ++i)
+ {
+ if (node->getChildNode(i) == nullptr)
+ {
+ mDiagnostics->error(node->getLine(), "Found nullptr child", "<validateNullNodes>");
+ mNullNodesFailed = true;
+ }
+ }
+ }
+}
+
+void ValidateAST::visitSymbol(TIntermSymbol *node)
+{
+ visitNode(PreVisit, node);
+}
+
+void ValidateAST::visitConstantUnion(TIntermConstantUnion *node)
+{
+ visitNode(PreVisit, node);
+}
+
+bool ValidateAST::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitBinary(Visit visit, TIntermBinary *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitUnary(Visit visit, TIntermUnary *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitTernary(Visit visit, TIntermTernary *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitCase(Visit visit, TIntermCase *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+void ValidateAST::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ visitNode(PreVisit, node);
+}
+
+bool ValidateAST::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ visitNode(visit, node);
+ expectNonNullChildren(visit, node, 0);
+ return true;
+}
+
+bool ValidateAST::visitBlock(Visit visit, TIntermBlock *node)
+{
+ visitNode(visit, node);
+ expectNonNullChildren(visit, node, 0);
+ return true;
+}
+
+bool ValidateAST::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ visitNode(visit, node);
+ expectNonNullChildren(visit, node, 0);
+ return true;
+}
+
+bool ValidateAST::visitLoop(Visit visit, TIntermLoop *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+bool ValidateAST::visitBranch(Visit visit, TIntermBranch *node)
+{
+ visitNode(visit, node);
+ return true;
+}
+
+void ValidateAST::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
+{
+ visitNode(PreVisit, node);
+}
+
+bool ValidateAST::validateInternal()
+{
+ return !mSingleParentFailed && !mNullNodesFailed;
+}
+
+} // anonymous namespace
+
+bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options)
+{
+ return ValidateAST::validate(root, diagnostics, options);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateAST.h b/gfx/angle/checkout/src/compiler/translator/ValidateAST.h
new file mode 100644
index 0000000000..7314f6e653
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateAST.h
@@ -0,0 +1,58 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEAST_H_
+#define COMPILER_TRANSLATOR_VALIDATEAST_H_
+
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+class TDiagnostics;
+class TIntermNode;
+
+// The following options (stored in Compiler) tell the validator what to validate. Some validations
+// are conditional to certain passes.
+struct ValidateASTOptions
+{
+ // TODO: add support for the flags marked with TODO. http://anglebug.com/2733
+
+ // Check that every node always has only one parent,
+ bool validateSingleParent = true;
+ // Check that all EOpCallFunctionInAST have their corresponding function definitions in the AST,
+ // with matching symbol ids. There should also be at least a prototype declaration before the
+ // function is called.
+ bool validateFunctionCall = true; // TODO
+ // Check that there are no null nodes where they are not allowed, for example as children of
+ // TIntermDeclaration or TIntermBlock.
+ bool validateNullNodes = true;
+ // Check that symbols that reference variables have consistent qualifiers and symbol ids with
+ // the variable declaration. For example, references to function out parameters should be
+ // EvqOut.
+ bool validateQualifiers = true; // TODO
+ // Check that variable declarations that can't have initializers don't have initializers
+ // (varyings, uniforms for example).
+ bool validateInitializers = true; // TODO
+ // Check that there is only one TFunction with each function name referenced in the nodes (no
+ // two TFunctions with the same name, taking internal/non-internal namespaces into account).
+ bool validateUniqueFunctions = true; // TODO
+ // Check that references to user-defined structs are matched with the corresponding struct
+ // declaration.
+ bool validateStructUsage = true; // TODO
+ // Check that expression nodes have the correct type considering their operand(s).
+ bool validateExpressionTypes = true; // TODO
+ // If SeparateDeclarations has been run, check for the absence of multi declarations as well.
+ bool validateMultiDeclarations = false; // TODO
+};
+
+// Check for errors and output error messages on the context.
+// Returns true if there are no errors.
+bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp
new file mode 100644
index 0000000000..4ffb832d99
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp
@@ -0,0 +1,141 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateGlobalInitializer.h"
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const int kMaxAllowedTraversalDepth = 256;
+
+class ValidateGlobalInitializerTraverser : public TIntermTraverser
+{
+ public:
+ ValidateGlobalInitializerTraverser(int shaderVersion);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+
+ bool isValid() const { return mIsValid && mMaxDepth < mMaxAllowedDepth; }
+ bool issueWarning() const { return mIssueWarning; }
+
+ private:
+ int mShaderVersion;
+ bool mIsValid;
+ bool mIssueWarning;
+};
+
+void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
+{
+ // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
+ // Global initializers must be constant expressions.
+ switch (node->getType().getQualifier())
+ {
+ case EvqConst:
+ break;
+ case EvqGlobal:
+ case EvqTemporary:
+ case EvqUniform:
+ // We allow these cases to be compatible with legacy ESSL 1.00 content.
+ // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal
+ // with.
+ if (mShaderVersion >= 300)
+ {
+ mIsValid = false;
+ }
+ else
+ {
+ mIssueWarning = true;
+ }
+ break;
+ default:
+ mIsValid = false;
+ }
+}
+
+void ValidateGlobalInitializerTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ // Constant unions that are not constant expressions may result from folding a ternary
+ // expression.
+ switch (node->getType().getQualifier())
+ {
+ case EvqConst:
+ break;
+ case EvqTemporary:
+ if (mShaderVersion >= 300)
+ {
+ mIsValid = false;
+ }
+ else
+ {
+ mIssueWarning = true;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ // Disallow calls to user-defined functions and texture lookup functions in global variable
+ // initializers.
+ // This is done simply by disabling all function calls - built-in math functions don't use
+ // the function call ops.
+ if (node->isFunctionCall())
+ {
+ mIsValid = false;
+ }
+ return true;
+}
+
+bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (node->isAssignment())
+ {
+ mIsValid = false;
+ }
+ return true;
+}
+
+bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (node->isAssignment())
+ {
+ mIsValid = false;
+ }
+ return true;
+}
+
+ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(int shaderVersion)
+ : TIntermTraverser(true, false, false, nullptr),
+ mShaderVersion(shaderVersion),
+ mIsValid(true),
+ mIssueWarning(false)
+{
+ setMaxAllowedDepth(kMaxAllowedTraversalDepth);
+}
+
+} // namespace
+
+bool ValidateGlobalInitializer(TIntermTyped *initializer, int shaderVersion, bool *warning)
+{
+ ValidateGlobalInitializerTraverser validate(shaderVersion);
+ initializer->traverse(&validate);
+ ASSERT(warning != nullptr);
+ *warning = validate.issueWarning();
+ return validate.isValid();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h
new file mode 100644
index 0000000000..b830760ca4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
+#define COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
+
+namespace sh
+{
+
+class TIntermTyped;
+
+// Returns true if the initializer is valid.
+bool ValidateGlobalInitializer(TIntermTyped *initializer, int shaderVersion, bool *warning);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp
new file mode 100644
index 0000000000..ac8d5c14ed
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp
@@ -0,0 +1,442 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateLimitations.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+int GetLoopSymbolId(TIntermLoop *loop)
+{
+ // Here we assume all the operations are valid, because the loop node is
+ // already validated before this call.
+ TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
+ TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+
+ return symbol->uniqueId().get();
+}
+
+// Traverses a node to check if it represents a constant index expression.
+// Definition:
+// constant-index-expressions are a superset of constant-expressions.
+// Constant-index-expressions can include loop indices as defined in
+// GLSL ES 1.0 spec, Appendix A, section 4.
+// The following are constant-index-expressions:
+// - Constant expressions
+// - Loop indices as defined in section 4
+// - Expressions composed of both of the above
+class ValidateConstIndexExpr : public TIntermTraverser
+{
+ public:
+ ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
+ : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
+ {}
+
+ // Returns true if the parsed node represents a constant index expression.
+ bool isValid() const { return mValid; }
+
+ void visitSymbol(TIntermSymbol *symbol) override
+ {
+ // Only constants and loop indices are allowed in a
+ // constant index expression.
+ if (mValid)
+ {
+ bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
+ symbol->uniqueId().get()) != mLoopSymbolIds.end();
+ mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
+ }
+ }
+
+ private:
+ bool mValid;
+ const std::vector<int> mLoopSymbolIds;
+};
+
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitationsTraverser : public TLValueTrackingTraverser
+{
+ public:
+ ValidateLimitationsTraverser(sh::GLenum shaderType,
+ TSymbolTable *symbolTable,
+ TDiagnostics *diagnostics);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitBinary(Visit, TIntermBinary *) override;
+ bool visitLoop(Visit, TIntermLoop *) override;
+
+ private:
+ void error(TSourceLoc loc, const char *reason, const char *token);
+ void error(TSourceLoc loc, const char *reason, const ImmutableString &token);
+
+ bool isLoopIndex(TIntermSymbol *symbol);
+ bool validateLoopType(TIntermLoop *node);
+
+ bool validateForLoopHeader(TIntermLoop *node);
+ // If valid, return the index symbol id; Otherwise, return -1.
+ int validateForLoopInit(TIntermLoop *node);
+ bool validateForLoopCond(TIntermLoop *node, int indexSymbolId);
+ bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId);
+
+ // Returns true if indexing does not exceed the minimum functionality
+ // mandated in GLSL 1.0 spec, Appendix A, Section 5.
+ bool isConstExpr(TIntermNode *node);
+ bool isConstIndexExpr(TIntermNode *node);
+ bool validateIndexing(TIntermBinary *node);
+
+ sh::GLenum mShaderType;
+ TDiagnostics *mDiagnostics;
+ std::vector<int> mLoopSymbolIds;
+};
+
+ValidateLimitationsTraverser::ValidateLimitationsTraverser(sh::GLenum shaderType,
+ TSymbolTable *symbolTable,
+ TDiagnostics *diagnostics)
+ : TLValueTrackingTraverser(true, false, false, symbolTable),
+ mShaderType(shaderType),
+ mDiagnostics(diagnostics)
+{
+ ASSERT(diagnostics);
+}
+
+void ValidateLimitationsTraverser::visitSymbol(TIntermSymbol *node)
+{
+ if (isLoopIndex(node) && isLValueRequiredHere())
+ {
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ node->getName());
+ }
+}
+
+bool ValidateLimitationsTraverser::visitBinary(Visit, TIntermBinary *node)
+{
+ // Check indexing.
+ switch (node->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ validateIndexing(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitationsTraverser::visitLoop(Visit, TIntermLoop *node)
+{
+ if (!validateLoopType(node))
+ return false;
+
+ if (!validateForLoopHeader(node))
+ return false;
+
+ TIntermNode *body = node->getBody();
+ if (body != nullptr)
+ {
+ mLoopSymbolIds.push_back(GetLoopSymbolId(node));
+ body->traverse(this);
+ mLoopSymbolIds.pop_back();
+ }
+
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ValidateLimitationsTraverser::error(TSourceLoc loc, const char *reason, const char *token)
+{
+ mDiagnostics->error(loc, reason, token);
+}
+
+void ValidateLimitationsTraverser::error(TSourceLoc loc,
+ const char *reason,
+ const ImmutableString &token)
+{
+ error(loc, reason, token.data());
+}
+
+bool ValidateLimitationsTraverser::isLoopIndex(TIntermSymbol *symbol)
+{
+ return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->uniqueId().get()) !=
+ mLoopSymbolIds.end();
+}
+
+bool ValidateLimitationsTraverser::validateLoopType(TIntermLoop *node)
+{
+ TLoopType type = node->getType();
+ if (type == ELoopFor)
+ return true;
+
+ // Reject while and do-while loops.
+ error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do");
+ return false;
+}
+
+bool ValidateLimitationsTraverser::validateForLoopHeader(TIntermLoop *node)
+{
+ ASSERT(node->getType() == ELoopFor);
+
+ //
+ // The for statement has the form:
+ // for ( init-declaration ; condition ; expression ) statement
+ //
+ int indexSymbolId = validateForLoopInit(node);
+ if (indexSymbolId < 0)
+ return false;
+ if (!validateForLoopCond(node, indexSymbolId))
+ return false;
+ if (!validateForLoopExpr(node, indexSymbolId))
+ return false;
+
+ return true;
+}
+
+int ValidateLimitationsTraverser::validateForLoopInit(TIntermLoop *node)
+{
+ TIntermNode *init = node->getInit();
+ if (init == nullptr)
+ {
+ error(node->getLine(), "Missing init declaration", "for");
+ return -1;
+ }
+
+ //
+ // init-declaration has the form:
+ // type-specifier identifier = constant-expression
+ //
+ TIntermDeclaration *decl = init->getAsDeclarationNode();
+ if (decl == nullptr)
+ {
+ error(init->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ // To keep things simple do not allow declaration list.
+ TIntermSequence *declSeq = decl->getSequence();
+ if (declSeq->size() != 1)
+ {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
+ if ((declInit == nullptr) || (declInit->getOp() != EOpInitialize))
+ {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+ if (symbol == nullptr)
+ {
+ error(declInit->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ // The loop index has type int or float.
+ TBasicType type = symbol->getBasicType();
+ if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat))
+ {
+ error(symbol->getLine(), "Invalid type for loop index", getBasicString(type));
+ return -1;
+ }
+ // The loop index is initialized with constant expression.
+ if (!isConstExpr(declInit->getRight()))
+ {
+ error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression",
+ symbol->getName());
+ return -1;
+ }
+
+ return symbol->uniqueId().get();
+}
+
+bool ValidateLimitationsTraverser::validateForLoopCond(TIntermLoop *node, int indexSymbolId)
+{
+ TIntermNode *cond = node->getCondition();
+ if (cond == nullptr)
+ {
+ error(node->getLine(), "Missing condition", "for");
+ return false;
+ }
+ //
+ // condition has the form:
+ // loop_index relational_operator constant_expression
+ //
+ TIntermBinary *binOp = cond->getAsBinaryNode();
+ if (binOp == nullptr)
+ {
+ error(node->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ // Loop index should be to the left of relational operator.
+ TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
+ if (symbol == nullptr)
+ {
+ error(binOp->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ if (symbol->uniqueId().get() != indexSymbolId)
+ {
+ error(symbol->getLine(), "Expected loop index", symbol->getName());
+ return false;
+ }
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (binOp->getOp())
+ {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ default:
+ error(binOp->getLine(), "Invalid relational operator",
+ GetOperatorString(binOp->getOp()));
+ break;
+ }
+ // Loop index must be compared with a constant.
+ if (!isConstExpr(binOp->getRight()))
+ {
+ error(binOp->getLine(), "Loop index cannot be compared with non-constant expression",
+ symbol->getName());
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateLimitationsTraverser::validateForLoopExpr(TIntermLoop *node, int indexSymbolId)
+{
+ TIntermNode *expr = node->getExpression();
+ if (expr == nullptr)
+ {
+ error(node->getLine(), "Missing expression", "for");
+ return false;
+ }
+
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary *unOp = expr->getAsUnaryNode();
+ TIntermBinary *binOp = unOp ? nullptr : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermSymbol *symbol = nullptr;
+ if (unOp != nullptr)
+ {
+ op = unOp->getOp();
+ symbol = unOp->getOperand()->getAsSymbolNode();
+ }
+ else if (binOp != nullptr)
+ {
+ op = binOp->getOp();
+ symbol = binOp->getLeft()->getAsSymbolNode();
+ }
+
+ // The operand must be loop index.
+ if (symbol == nullptr)
+ {
+ error(expr->getLine(), "Invalid expression", "for");
+ return false;
+ }
+ if (symbol->uniqueId().get() != indexSymbolId)
+ {
+ error(symbol->getLine(), "Expected loop index", symbol->getName());
+ return false;
+ }
+
+ // The operator is one of: ++ -- += -=.
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != nullptr) && (binOp == nullptr));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == nullptr) && (binOp != nullptr));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", GetOperatorString(op));
+ return false;
+ }
+
+ // Loop index must be incremented/decremented with a constant.
+ if (binOp != nullptr)
+ {
+ if (!isConstExpr(binOp->getRight()))
+ {
+ error(binOp->getLine(), "Loop index cannot be modified by non-constant expression",
+ symbol->getName());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateLimitationsTraverser::isConstExpr(TIntermNode *node)
+{
+ ASSERT(node != nullptr);
+ return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
+}
+
+bool ValidateLimitationsTraverser::isConstIndexExpr(TIntermNode *node)
+{
+ ASSERT(node != nullptr);
+
+ ValidateConstIndexExpr validate(mLoopSymbolIds);
+ node->traverse(&validate);
+ return validate.isValid();
+}
+
+bool ValidateLimitationsTraverser::validateIndexing(TIntermBinary *node)
+{
+ ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect));
+
+ bool valid = true;
+ TIntermTyped *index = node->getRight();
+ // The index expession must be a constant-index-expression unless
+ // the operand is a uniform in a vertex shader.
+ TIntermTyped *operand = node->getLeft();
+ bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform);
+ if (!skip && !isConstIndexExpr(index))
+ {
+ error(index->getLine(), "Index expression must be constant", "[]");
+ valid = false;
+ }
+ return valid;
+}
+
+} // namespace
+
+bool ValidateLimitations(TIntermNode *root,
+ GLenum shaderType,
+ TSymbolTable *symbolTable,
+ TDiagnostics *diagnostics)
+{
+ ValidateLimitationsTraverser validate(shaderType, symbolTable, diagnostics);
+ root->traverse(&validate);
+ return diagnostics->numErrors() == 0;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h
new file mode 100644
index 0000000000..d219ed680a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
+#define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+class TDiagnostics;
+
+// Returns true if the given shader does not exceed the minimum functionality mandated in GLSL ES
+// 1.00 spec Appendix A.
+bool ValidateLimitations(TIntermNode *root,
+ GLenum shaderType,
+ TSymbolTable *symbolTable,
+ TDiagnostics *diagnostics);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp
new file mode 100644
index 0000000000..a06babd3bd
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ValidateMaxParameters checks if function definitions have more than a set number of parameters.
+
+#include "compiler/translator/ValidateMaxParameters.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+bool ValidateMaxParameters(TIntermBlock *root, unsigned int maxParameters)
+{
+ for (TIntermNode *node : *root->getSequence())
+ {
+ TIntermFunctionDefinition *definition = node->getAsFunctionDefinition();
+ if (definition != nullptr &&
+ definition->getFunctionPrototype()->getFunction()->getParamCount() > maxParameters)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h
new file mode 100644
index 0000000000..dec7597da4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ValidateMaxParameters checks if function definitions have more than a set number of parameters.
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
+#define COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+
+// Return true if valid.
+bool ValidateMaxParameters(TIntermBlock *root, unsigned int maxParameters);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp
new file mode 100644
index 0000000000..98802554d6
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp
@@ -0,0 +1,184 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations,
+// out-of-range locations, that locations are specified when using multiple outputs, and YUV output
+// validity.
+
+#include "compiler/translator/ValidateOutputs.h"
+
+#include <set>
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
+{
+ diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
+}
+
+class ValidateOutputsTraverser : public TIntermTraverser
+{
+ public:
+ ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, int maxDrawBuffers);
+
+ void validate(TDiagnostics *diagnostics) const;
+
+ void visitSymbol(TIntermSymbol *) override;
+
+ private:
+ int mMaxDrawBuffers;
+ bool mAllowUnspecifiedOutputLocationResolution;
+ bool mUsesFragDepth;
+
+ typedef std::vector<TIntermSymbol *> OutputVector;
+ OutputVector mOutputs;
+ OutputVector mUnspecifiedLocationOutputs;
+ OutputVector mYuvOutputs;
+ std::set<int> mVisitedSymbols; // Visited symbol ids.
+};
+
+ValidateOutputsTraverser::ValidateOutputsTraverser(const TExtensionBehavior &extBehavior,
+ int maxDrawBuffers)
+ : TIntermTraverser(true, false, false),
+ mMaxDrawBuffers(maxDrawBuffers),
+ mAllowUnspecifiedOutputLocationResolution(
+ IsExtensionEnabled(extBehavior, TExtension::EXT_blend_func_extended)),
+ mUsesFragDepth(false)
+{}
+
+void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol)
+{
+ if (symbol->variable().symbolType() == SymbolType::Empty)
+ return;
+
+ if (mVisitedSymbols.count(symbol->uniqueId().get()) == 1)
+ return;
+
+ mVisitedSymbols.insert(symbol->uniqueId().get());
+
+ TQualifier qualifier = symbol->getQualifier();
+ if (qualifier == EvqFragmentOut)
+ {
+ if (symbol->getType().getLayoutQualifier().location != -1)
+ {
+ mOutputs.push_back(symbol);
+ }
+ else if (symbol->getType().getLayoutQualifier().yuv == true)
+ {
+ mYuvOutputs.push_back(symbol);
+ }
+ else
+ {
+ mUnspecifiedLocationOutputs.push_back(symbol);
+ }
+ }
+ else if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT)
+ {
+ mUsesFragDepth = true;
+ }
+}
+
+void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const
+{
+ ASSERT(diagnostics);
+ OutputVector validOutputs(mMaxDrawBuffers, nullptr);
+ OutputVector validSecondaryOutputs(mMaxDrawBuffers, nullptr);
+
+ for (const auto &symbol : mOutputs)
+ {
+ const TType &type = symbol->getType();
+ ASSERT(!type.isArrayOfArrays()); // Disallowed in GLSL ES 3.10 section 4.3.6.
+ const size_t elementCount =
+ static_cast<size_t>(type.isArray() ? type.getOutermostArraySize() : 1u);
+ const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
+
+ ASSERT(type.getLayoutQualifier().location != -1);
+
+ OutputVector *validOutputsToUse = &validOutputs;
+ // The default index is 0, so we only assign the output to secondary outputs in case the
+ // index is explicitly set to 1.
+ if (type.getLayoutQualifier().index == 1)
+ {
+ validOutputsToUse = &validSecondaryOutputs;
+ }
+
+ if (location + elementCount <= validOutputsToUse->size())
+ {
+ for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
+ {
+ const size_t offsetLocation = location + elementIndex;
+ if ((*validOutputsToUse)[offsetLocation])
+ {
+ std::stringstream strstr = sh::InitializeStream<std::stringstream>();
+ strstr << "conflicting output locations with previously defined output '"
+ << (*validOutputsToUse)[offsetLocation]->getName() << "'";
+ error(*symbol, strstr.str().c_str(), diagnostics);
+ }
+ else
+ {
+ (*validOutputsToUse)[offsetLocation] = symbol;
+ }
+ }
+ }
+ else
+ {
+ if (elementCount > 0)
+ {
+ error(*symbol,
+ elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
+ : "output location must be < MAX_DRAW_BUFFERS",
+ diagnostics);
+ }
+ }
+ }
+
+ if (!mAllowUnspecifiedOutputLocationResolution &&
+ ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
+ mUnspecifiedLocationOutputs.size() > 1))
+ {
+ for (const auto &symbol : mUnspecifiedLocationOutputs)
+ {
+ error(*symbol,
+ "must explicitly specify all locations when using multiple fragment outputs",
+ diagnostics);
+ }
+ }
+
+ if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() ||
+ !mUnspecifiedLocationOutputs.empty()))
+ {
+ for (const auto &symbol : mYuvOutputs)
+ {
+ error(*symbol,
+ "not allowed to specify yuv qualifier when using depth or multiple color "
+ "fragment outputs",
+ diagnostics);
+ }
+ }
+}
+
+} // anonymous namespace
+
+bool ValidateOutputs(TIntermBlock *root,
+ const TExtensionBehavior &extBehavior,
+ int maxDrawBuffers,
+ TDiagnostics *diagnostics)
+{
+ ValidateOutputsTraverser validateOutputs(extBehavior, maxDrawBuffers);
+ root->traverse(&validateOutputs);
+ int numErrorsBefore = diagnostics->numErrors();
+ validateOutputs.validate(diagnostics);
+ return (diagnostics->numErrors() == numErrorsBefore);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h
new file mode 100644
index 0000000000..e41ccd990c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations,
+// out-of-range locations, that locations are specified when using multiple outputs, and YUV output
+// validity.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
+#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
+
+#include "compiler/translator/ExtensionBehavior.h"
+
+namespace sh
+{
+
+class TIntermBlock;
+class TDiagnostics;
+
+// Returns true if the shader has no conflicting or otherwise erroneous fragment outputs.
+bool ValidateOutputs(TIntermBlock *root,
+ const TExtensionBehavior &extBehavior,
+ int maxDrawBuffers,
+ TDiagnostics *diagnostics);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp
new file mode 100644
index 0000000000..37c33a867c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp
@@ -0,0 +1,315 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateSwitch.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const int kMaxAllowedTraversalDepth = 256;
+
+class ValidateSwitch : public TIntermTraverser
+{
+ public:
+ static bool validate(TBasicType switchType,
+ TDiagnostics *diagnostics,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc);
+
+ void visitSymbol(TIntermSymbol *) override;
+ void visitConstantUnion(TIntermConstantUnion *) override;
+ bool visitDeclaration(Visit, TIntermDeclaration *) override;
+ bool visitBlock(Visit visit, TIntermBlock *) override;
+ bool visitBinary(Visit, TIntermBinary *) override;
+ bool visitUnary(Visit, TIntermUnary *) override;
+ bool visitTernary(Visit, TIntermTernary *) override;
+ bool visitSwizzle(Visit, TIntermSwizzle *) override;
+ bool visitIfElse(Visit visit, TIntermIfElse *) override;
+ bool visitSwitch(Visit, TIntermSwitch *) override;
+ bool visitCase(Visit, TIntermCase *node) override;
+ bool visitAggregate(Visit, TIntermAggregate *) override;
+ bool visitLoop(Visit visit, TIntermLoop *) override;
+ bool visitBranch(Visit, TIntermBranch *) override;
+
+ private:
+ ValidateSwitch(TBasicType switchType, TDiagnostics *context);
+
+ bool validateInternal(const TSourceLoc &loc);
+
+ TBasicType mSwitchType;
+ TDiagnostics *mDiagnostics;
+ bool mCaseTypeMismatch;
+ bool mFirstCaseFound;
+ bool mStatementBeforeCase;
+ bool mLastStatementWasCase;
+ int mControlFlowDepth;
+ bool mCaseInsideControlFlow;
+ int mDefaultCount;
+ std::set<int> mCasesSigned;
+ std::set<unsigned int> mCasesUnsigned;
+ bool mDuplicateCases;
+};
+
+bool ValidateSwitch::validate(TBasicType switchType,
+ TDiagnostics *diagnostics,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc)
+{
+ ValidateSwitch validate(switchType, diagnostics);
+ ASSERT(statementList);
+ statementList->traverse(&validate);
+ return validate.validateInternal(loc);
+}
+
+ValidateSwitch::ValidateSwitch(TBasicType switchType, TDiagnostics *diagnostics)
+ : TIntermTraverser(true, false, true, nullptr),
+ mSwitchType(switchType),
+ mDiagnostics(diagnostics),
+ mCaseTypeMismatch(false),
+ mFirstCaseFound(false),
+ mStatementBeforeCase(false),
+ mLastStatementWasCase(false),
+ mControlFlowDepth(0),
+ mCaseInsideControlFlow(false),
+ mDefaultCount(0),
+ mDuplicateCases(false)
+{
+ setMaxAllowedDepth(kMaxAllowedTraversalDepth);
+}
+
+void ValidateSwitch::visitSymbol(TIntermSymbol *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+}
+
+void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *)
+{
+ // Conditions of case labels are not traversed, so this is some other constant
+ // Could be just a statement like "0;"
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+}
+
+bool ValidateSwitch::visitDeclaration(Visit, TIntermDeclaration *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitBlock(Visit visit, TIntermBlock *)
+{
+ if (getParentNode() != nullptr)
+ {
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ if (visit == PreVisit)
+ ++mControlFlowDepth;
+ if (visit == PostVisit)
+ --mControlFlowDepth;
+ }
+ return true;
+}
+
+bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitTernary(Visit, TIntermTernary *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitSwizzle(Visit, TIntermSwizzle *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitIfElse(Visit visit, TIntermIfElse *)
+{
+ if (visit == PreVisit)
+ ++mControlFlowDepth;
+ if (visit == PostVisit)
+ --mControlFlowDepth;
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ // Don't go into nested switch statements
+ return false;
+}
+
+bool ValidateSwitch::visitCase(Visit, TIntermCase *node)
+{
+ const char *nodeStr = node->hasCondition() ? "case" : "default";
+ if (mControlFlowDepth > 0)
+ {
+ mDiagnostics->error(node->getLine(), "label statement nested inside control flow", nodeStr);
+ mCaseInsideControlFlow = true;
+ }
+ mFirstCaseFound = true;
+ mLastStatementWasCase = true;
+ if (!node->hasCondition())
+ {
+ ++mDefaultCount;
+ if (mDefaultCount > 1)
+ {
+ mDiagnostics->error(node->getLine(), "duplicate default label", nodeStr);
+ }
+ }
+ else
+ {
+ TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion();
+ if (condition == nullptr)
+ {
+ // This can happen in error cases.
+ return false;
+ }
+ TBasicType conditionType = condition->getBasicType();
+ if (conditionType != mSwitchType)
+ {
+ mDiagnostics->error(condition->getLine(),
+ "case label type does not match switch init-expression type",
+ nodeStr);
+ mCaseTypeMismatch = true;
+ }
+
+ if (conditionType == EbtInt)
+ {
+ int iConst = condition->getIConst(0);
+ if (mCasesSigned.find(iConst) != mCasesSigned.end())
+ {
+ mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr);
+ mDuplicateCases = true;
+ }
+ else
+ {
+ mCasesSigned.insert(iConst);
+ }
+ }
+ else if (conditionType == EbtUInt)
+ {
+ unsigned int uConst = condition->getUConst(0);
+ if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end())
+ {
+ mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr);
+ mDuplicateCases = true;
+ }
+ else
+ {
+ mCasesUnsigned.insert(uConst);
+ }
+ }
+ // Other types are possible only in error cases, where the error has already been generated
+ // when parsing the case statement.
+ }
+ // Don't traverse the condition of the case statement
+ return false;
+}
+
+bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *)
+{
+ if (getParentNode() != nullptr)
+ {
+ // This is not the statementList node, but some other node.
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ }
+ return true;
+}
+
+bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *)
+{
+ if (visit == PreVisit)
+ ++mControlFlowDepth;
+ if (visit == PostVisit)
+ --mControlFlowDepth;
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::visitBranch(Visit, TIntermBranch *)
+{
+ if (!mFirstCaseFound)
+ mStatementBeforeCase = true;
+ mLastStatementWasCase = false;
+ return true;
+}
+
+bool ValidateSwitch::validateInternal(const TSourceLoc &loc)
+{
+ if (mStatementBeforeCase)
+ {
+ mDiagnostics->error(loc, "statement before the first label", "switch");
+ }
+ if (mLastStatementWasCase)
+ {
+ // There have been some differences between versions of GLSL ES specs on whether this should
+ // be an error or not, but as of early 2018 the latest discussion is that this is an error
+ // also on GLSL ES versions newer than 3.00.
+ mDiagnostics->error(
+ loc, "no statement between the last label and the end of the switch statement",
+ "switch");
+ }
+ if (getMaxDepth() >= kMaxAllowedTraversalDepth)
+ {
+ mDiagnostics->error(loc, "too complex expressions inside a switch statement", "switch");
+ }
+ return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
+ !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases &&
+ getMaxDepth() < kMaxAllowedTraversalDepth;
+}
+
+} // anonymous namespace
+
+bool ValidateSwitchStatementList(TBasicType switchType,
+ TDiagnostics *diagnostics,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc)
+{
+ return ValidateSwitch::validate(switchType, diagnostics, statementList, loc);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h
new file mode 100644
index 0000000000..757820a164
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATESWITCH_H_
+#define COMPILER_TRANSLATOR_VALIDATESWITCH_H_
+
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+class TDiagnostics;
+class TIntermBlock;
+
+// Check for errors and output error messages on the context.
+// Returns true if there are no errors.
+bool ValidateSwitchStatementList(TBasicType switchType,
+ TDiagnostics *diagnostics,
+ TIntermBlock *statementList,
+ const TSourceLoc &loc);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp
new file mode 100644
index 0000000000..394e35c8d8
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp
@@ -0,0 +1,179 @@
+//
+// Copyright (c) 2002-2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The ValidateVaryingLocations function checks if there exists location conflicts on shader
+// varyings.
+//
+
+#include "ValidateVaryingLocations.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
+{
+ diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
+}
+
+int GetLocationCount(const TIntermSymbol *varying, bool ignoreVaryingArraySize)
+{
+ const auto &varyingType = varying->getType();
+ if (varyingType.getStruct() != nullptr)
+ {
+ ASSERT(!varyingType.isArray());
+ int totalLocation = 0;
+ for (const auto *field : varyingType.getStruct()->fields())
+ {
+ const auto *fieldType = field->type();
+ ASSERT(fieldType->getStruct() == nullptr && !fieldType->isArray());
+
+ totalLocation += fieldType->getSecondarySize();
+ }
+ return totalLocation;
+ }
+ // [GL_EXT_shader_io_blocks SPEC Chapter 4.4.1]
+ // Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation
+ // evaluation inputs all have an additional level of arrayness relative to other shader inputs
+ // and outputs. This outer array level is removed from the type before considering how many
+ // locations the type consumes.
+ else if (ignoreVaryingArraySize)
+ {
+ // Array-of-arrays cannot be inputs or outputs of a geometry shader.
+ // (GL_EXT_geometry_shader SPEC issues(5))
+ ASSERT(!varyingType.isArrayOfArrays());
+ return varyingType.getSecondarySize();
+ }
+ else
+ {
+ return varyingType.getSecondarySize() * static_cast<int>(varyingType.getArraySizeProduct());
+ }
+}
+
+using VaryingVector = std::vector<const TIntermSymbol *>;
+
+void ValidateShaderInterface(TDiagnostics *diagnostics,
+ VaryingVector &varyingVector,
+ bool ignoreVaryingArraySize)
+{
+ // Location conflicts can only happen when there are two or more varyings in varyingVector.
+ if (varyingVector.size() <= 1)
+ {
+ return;
+ }
+
+ std::map<int, const TIntermSymbol *> locationMap;
+ for (const TIntermSymbol *varying : varyingVector)
+ {
+ const int location = varying->getType().getLayoutQualifier().location;
+ ASSERT(location >= 0);
+
+ const int elementCount = GetLocationCount(varying, ignoreVaryingArraySize);
+ for (int elementIndex = 0; elementIndex < elementCount; ++elementIndex)
+ {
+ const int offsetLocation = location + elementIndex;
+ if (locationMap.find(offsetLocation) != locationMap.end())
+ {
+ std::stringstream strstr = sh::InitializeStream<std::stringstream>();
+ strstr << "'" << varying->getName()
+ << "' conflicting location with previously defined '"
+ << locationMap[offsetLocation]->getName() << "'";
+ error(*varying, strstr.str().c_str(), diagnostics);
+ }
+ else
+ {
+ locationMap[offsetLocation] = varying;
+ }
+ }
+ }
+}
+
+class ValidateVaryingLocationsTraverser : public TIntermTraverser
+{
+ public:
+ ValidateVaryingLocationsTraverser(GLenum shaderType);
+ void validate(TDiagnostics *diagnostics);
+
+ private:
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+
+ VaryingVector mInputVaryingsWithLocation;
+ VaryingVector mOutputVaryingsWithLocation;
+ GLenum mShaderType;
+};
+
+ValidateVaryingLocationsTraverser::ValidateVaryingLocationsTraverser(GLenum shaderType)
+ : TIntermTraverser(true, false, false), mShaderType(shaderType)
+{}
+
+bool ValidateVaryingLocationsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ const TIntermSequence &sequence = *(node->getSequence());
+ ASSERT(!sequence.empty());
+
+ const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
+ if (symbol == nullptr)
+ {
+ return false;
+ }
+
+ if (symbol->variable().symbolType() == SymbolType::Empty)
+ {
+ return false;
+ }
+
+ // Collect varyings that have explicit 'location' qualifiers.
+ const TQualifier qualifier = symbol->getQualifier();
+ if (symbol->getType().getLayoutQualifier().location != -1)
+ {
+ if (IsVaryingIn(qualifier))
+ {
+ mInputVaryingsWithLocation.push_back(symbol);
+ }
+ else if (IsVaryingOut(qualifier))
+ {
+ mOutputVaryingsWithLocation.push_back(symbol);
+ }
+ }
+
+ return false;
+}
+
+bool ValidateVaryingLocationsTraverser::visitFunctionDefinition(Visit visit,
+ TIntermFunctionDefinition *node)
+{
+ // We stop traversing function definitions because varyings cannot be defined in a function.
+ return false;
+}
+
+void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics)
+{
+ ASSERT(diagnostics);
+
+ ValidateShaderInterface(diagnostics, mInputVaryingsWithLocation,
+ mShaderType == GL_GEOMETRY_SHADER_EXT);
+ ValidateShaderInterface(diagnostics, mOutputVaryingsWithLocation, false);
+}
+
+} // anonymous namespace
+
+bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType)
+{
+ ValidateVaryingLocationsTraverser varyingValidator(shaderType);
+ root->traverse(&varyingValidator);
+ int numErrorsBefore = diagnostics->numErrors();
+ varyingValidator.validate(diagnostics);
+ return (diagnostics->numErrors() == numErrorsBefore);
+}
+
+} // namespace sh \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h
new file mode 100644
index 0000000000..1e53977c68
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2002-2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The ValidateVaryingLocations function checks if there exists location conflicts on shader
+// varyings.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_
+#define COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_
+
+#include "GLSLANG/ShaderVars.h"
+
+namespace sh
+{
+
+class TIntermBlock;
+class TDiagnostics;
+
+bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType);
+
+} // namespace sh
+
+#endif \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp b/gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp
new file mode 100644
index 0000000000..123da4b35e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp
@@ -0,0 +1,413 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Check whether variables fit within packing limits according to the packing rules from the GLSL ES
+// 1.00.17 spec, Appendix A, section 7.
+
+#include <algorithm>
+
+#include "angle_gl.h"
+
+#include "common/utilities.h"
+#include "compiler/translator/VariablePacker.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// Expand the variable so that struct variables are split into their individual fields.
+// Will not set the mappedName or staticUse fields on the expanded variables.
+void ExpandVariable(const ShaderVariable &variable,
+ const std::string &name,
+ std::vector<ShaderVariable> *expanded);
+
+void ExpandStructVariable(const ShaderVariable &variable,
+ const std::string &name,
+ std::vector<ShaderVariable> *expanded)
+{
+ ASSERT(variable.isStruct());
+
+ const std::vector<ShaderVariable> &fields = variable.fields;
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ const ShaderVariable &field = fields[fieldIndex];
+ ExpandVariable(field, name + "." + field.name, expanded);
+ }
+}
+
+void ExpandStructArrayVariable(const ShaderVariable &variable,
+ unsigned int arrayNestingIndex,
+ const std::string &name,
+ std::vector<ShaderVariable> *expanded)
+{
+ // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
+ // innermost.
+ const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
+ for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
+ {
+ const std::string elementName = name + ArrayString(arrayElement);
+ if (arrayNestingIndex + 1u < variable.arraySizes.size())
+ {
+ ExpandStructArrayVariable(variable, arrayNestingIndex + 1u, elementName, expanded);
+ }
+ else
+ {
+ ExpandStructVariable(variable, elementName, expanded);
+ }
+ }
+}
+
+void ExpandVariable(const ShaderVariable &variable,
+ const std::string &name,
+ std::vector<ShaderVariable> *expanded)
+{
+ if (variable.isStruct())
+ {
+ if (variable.isArray())
+ {
+ ExpandStructArrayVariable(variable, 0u, name, expanded);
+ }
+ else
+ {
+ ExpandStructVariable(variable, name, expanded);
+ }
+ }
+ else
+ {
+ ShaderVariable expandedVar = variable;
+ expandedVar.name = name;
+
+ expanded->push_back(expandedVar);
+ }
+}
+
+int GetVariablePackingRows(const ShaderVariable &variable)
+{
+ return GetTypePackingRows(variable.type) * variable.getArraySizeProduct();
+}
+
+class VariablePacker
+{
+ public:
+ bool checkExpandedVariablesWithinPackingLimits(unsigned int maxVectors,
+ std::vector<sh::ShaderVariable> *variables);
+
+ private:
+ static const int kNumColumns = 4;
+ static const unsigned kColumnMask = (1 << kNumColumns) - 1;
+
+ unsigned makeColumnFlags(int column, int numComponentsPerRow);
+ void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow);
+ bool searchColumn(int column, int numRows, int *destRow, int *destSize);
+
+ int topNonFullRow_;
+ int bottomNonFullRow_;
+ int maxRows_;
+ std::vector<unsigned> rows_;
+};
+
+struct TVariableInfoComparer
+{
+ bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const
+ {
+ int lhsSortOrder = gl::VariableSortOrder(lhs.type);
+ int rhsSortOrder = gl::VariableSortOrder(rhs.type);
+ if (lhsSortOrder != rhsSortOrder)
+ {
+ return lhsSortOrder < rhsSortOrder;
+ }
+ // Sort by largest first.
+ return lhs.getArraySizeProduct() > rhs.getArraySizeProduct();
+ }
+};
+
+unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
+{
+ return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & kColumnMask) >> column;
+}
+
+void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
+{
+ unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
+ for (int r = 0; r < numRows; ++r)
+ {
+ int row = topRow + r;
+ ASSERT((rows_[row] & columnFlags) == 0);
+ rows_[row] |= columnFlags;
+ }
+}
+
+bool VariablePacker::searchColumn(int column, int numRows, int *destRow, int *destSize)
+{
+ ASSERT(destRow);
+
+ for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; ++topNonFullRow_)
+ {
+ }
+
+ for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; --bottomNonFullRow_)
+ {
+ }
+
+ if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows)
+ {
+ return false;
+ }
+
+ unsigned columnFlags = makeColumnFlags(column, 1);
+ int topGoodRow = 0;
+ int smallestGoodTop = -1;
+ int smallestGoodSize = maxRows_ + 1;
+ int bottomRow = bottomNonFullRow_ + 1;
+ bool found = false;
+ for (int row = topNonFullRow_; row <= bottomRow; ++row)
+ {
+ bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
+ if (rowEmpty)
+ {
+ if (!found)
+ {
+ topGoodRow = row;
+ found = true;
+ }
+ }
+ else
+ {
+ if (found)
+ {
+ int size = row - topGoodRow;
+ if (size >= numRows && size < smallestGoodSize)
+ {
+ smallestGoodSize = size;
+ smallestGoodTop = topGoodRow;
+ }
+ }
+ found = false;
+ }
+ }
+ if (smallestGoodTop < 0)
+ {
+ return false;
+ }
+
+ *destRow = smallestGoodTop;
+ if (destSize)
+ {
+ *destSize = smallestGoodSize;
+ }
+ return true;
+}
+
+bool VariablePacker::checkExpandedVariablesWithinPackingLimits(
+ unsigned int maxVectors,
+ std::vector<sh::ShaderVariable> *variables)
+{
+ ASSERT(maxVectors > 0);
+ maxRows_ = maxVectors;
+ topNonFullRow_ = 0;
+ bottomNonFullRow_ = maxRows_ - 1;
+
+ // Check whether each variable fits in the available vectors.
+ for (const sh::ShaderVariable &variable : *variables)
+ {
+ // Structs should have been expanded before reaching here.
+ ASSERT(!variable.isStruct());
+ if (variable.getArraySizeProduct() > maxVectors / GetTypePackingRows(variable.type))
+ {
+ return false;
+ }
+ }
+
+ // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
+ // order by type, then by size of array, largest first.
+ std::sort(variables->begin(), variables->end(), TVariableInfoComparer());
+ rows_.clear();
+ rows_.resize(maxVectors, 0);
+
+ // Packs the 4 column variables.
+ size_t ii = 0;
+ for (; ii < variables->size(); ++ii)
+ {
+ const sh::ShaderVariable &variable = (*variables)[ii];
+ if (GetTypePackingComponentsPerRow(variable.type) != 4)
+ {
+ break;
+ }
+ topNonFullRow_ += GetVariablePackingRows(variable);
+ }
+
+ if (topNonFullRow_ > maxRows_)
+ {
+ return false;
+ }
+
+ // Packs the 3 column variables.
+ int num3ColumnRows = 0;
+ for (; ii < variables->size(); ++ii)
+ {
+ const sh::ShaderVariable &variable = (*variables)[ii];
+ if (GetTypePackingComponentsPerRow(variable.type) != 3)
+ {
+ break;
+ }
+ num3ColumnRows += GetVariablePackingRows(variable);
+ }
+
+ if (topNonFullRow_ + num3ColumnRows > maxRows_)
+ {
+ return false;
+ }
+
+ fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
+
+ // Packs the 2 column variables.
+ int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
+ int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
+ int rowsAvailableInColumns01 = twoColumnRowsAvailable;
+ int rowsAvailableInColumns23 = twoColumnRowsAvailable;
+ for (; ii < variables->size(); ++ii)
+ {
+ const sh::ShaderVariable &variable = (*variables)[ii];
+ if (GetTypePackingComponentsPerRow(variable.type) != 2)
+ {
+ break;
+ }
+ int numRows = GetVariablePackingRows(variable);
+ if (numRows <= rowsAvailableInColumns01)
+ {
+ rowsAvailableInColumns01 -= numRows;
+ }
+ else if (numRows <= rowsAvailableInColumns23)
+ {
+ rowsAvailableInColumns23 -= numRows;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ int numRowsUsedInColumns01 = twoColumnRowsAvailable - rowsAvailableInColumns01;
+ int numRowsUsedInColumns23 = twoColumnRowsAvailable - rowsAvailableInColumns23;
+ fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
+ fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, 2, 2);
+
+ // Packs the 1 column variables.
+ for (; ii < variables->size(); ++ii)
+ {
+ const sh::ShaderVariable &variable = (*variables)[ii];
+ ASSERT(1 == GetTypePackingComponentsPerRow(variable.type));
+ int numRows = GetVariablePackingRows(variable);
+ int smallestColumn = -1;
+ int smallestSize = maxRows_ + 1;
+ int topRow = -1;
+ for (int column = 0; column < kNumColumns; ++column)
+ {
+ int row = 0;
+ int size = 0;
+ if (searchColumn(column, numRows, &row, &size))
+ {
+ if (size < smallestSize)
+ {
+ smallestSize = size;
+ smallestColumn = column;
+ topRow = row;
+ }
+ }
+ }
+
+ if (smallestColumn < 0)
+ {
+ return false;
+ }
+
+ fillColumns(topRow, numRows, smallestColumn, 1);
+ }
+
+ ASSERT(variables->size() == ii);
+
+ return true;
+}
+
+} // anonymous namespace
+
+int GetTypePackingComponentsPerRow(sh::GLenum type)
+{
+ switch (type)
+ {
+ case GL_FLOAT_MAT4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_BOOL_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ return 4;
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ return 3;
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_BOOL_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ return 2;
+ default:
+ ASSERT(gl::VariableComponentCount(type) == 1);
+ return 1;
+ }
+}
+
+int GetTypePackingRows(sh::GLenum type)
+{
+ switch (type)
+ {
+ case GL_FLOAT_MAT4:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4x2:
+ return 4;
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT3x2:
+ return 3;
+ case GL_FLOAT_MAT2:
+ return 2;
+ default:
+ ASSERT(gl::VariableRowCount(type) == 1);
+ return 1;
+ }
+}
+
+template <typename T>
+bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector<T> &variables)
+{
+ VariablePacker packer;
+ std::vector<sh::ShaderVariable> expandedVariables;
+ for (const ShaderVariable &variable : variables)
+ {
+ ExpandVariable(variable, variable.name, &expandedVariables);
+ }
+ return packer.checkExpandedVariablesWithinPackingLimits(maxVectors, &expandedVariables);
+}
+
+template bool CheckVariablesInPackingLimits<ShaderVariable>(
+ unsigned int maxVectors,
+ const std::vector<ShaderVariable> &variables);
+template bool CheckVariablesInPackingLimits<Uniform>(unsigned int maxVectors,
+ const std::vector<Uniform> &variables);
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/VariablePacker.h b/gfx/angle/checkout/src/compiler/translator/VariablePacker.h
new file mode 100644
index 0000000000..36b2104cd0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/VariablePacker.h
@@ -0,0 +1,32 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Check whether variables fit within packing limits according to the packing rules from the GLSL ES
+// 1.00.17 spec, Appendix A, section 7.
+
+#ifndef COMPILER_TRANSLATOR_VARIABLEPACKER_H_
+#define COMPILER_TRANSLATOR_VARIABLEPACKER_H_
+
+#include <vector>
+
+#include <GLSLANG/ShaderLang.h>
+
+namespace sh
+{
+
+// Gets how many components in a row a data type takes.
+int GetTypePackingComponentsPerRow(sh::GLenum type);
+
+// Gets how many rows a data type takes.
+int GetTypePackingRows(sh::GLenum type);
+
+// Returns true if the passed in variables pack in maxVectors.
+// T should be ShaderVariable or one of the subclasses of ShaderVariable.
+template <typename T>
+bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector<T> &variables);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp
new file mode 100644
index 0000000000..eb431c3117
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp
@@ -0,0 +1,149 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/VersionGLSL.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+namespace
+{
+constexpr const ImmutableString kGlPointCoordString("gl_PointCoord");
+} // anonymous namespace
+
+int ShaderOutputTypeToGLSLVersion(ShShaderOutput output)
+{
+ switch (output)
+ {
+ case SH_GLSL_130_OUTPUT:
+ return GLSL_VERSION_130;
+ case SH_GLSL_140_OUTPUT:
+ return GLSL_VERSION_140;
+ case SH_GLSL_150_CORE_OUTPUT:
+ return GLSL_VERSION_150;
+ case SH_GLSL_330_CORE_OUTPUT:
+ return GLSL_VERSION_330;
+ case SH_GLSL_400_CORE_OUTPUT:
+ return GLSL_VERSION_400;
+ case SH_GLSL_410_CORE_OUTPUT:
+ return GLSL_VERSION_410;
+ case SH_GLSL_420_CORE_OUTPUT:
+ return GLSL_VERSION_420;
+ case SH_GLSL_430_CORE_OUTPUT:
+ return GLSL_VERSION_430;
+ case SH_GLSL_440_CORE_OUTPUT:
+ return GLSL_VERSION_440;
+ case SH_GLSL_450_CORE_OUTPUT:
+ return GLSL_VERSION_450;
+ case SH_GLSL_COMPATIBILITY_OUTPUT:
+ return GLSL_VERSION_110;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+// We need to scan for the following:
+// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
+// but only at the global scope.
+// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
+// but inside any scope.
+// 3. Call to a matrix constructor with another matrix as argument.
+// (These constructors were reserved in GLSL version 1.10.)
+// 4. Arrays as "out" function parameters.
+// GLSL spec section 6.1.1: "When calling a function, expressions that do
+// not evaluate to l-values cannot be passed to parameters declared as
+// out or inout."
+// GLSL 1.1 section 5.8: "Other binary or unary expressions,
+// non-dereferenced arrays, function names, swizzles with repeated fields,
+// and constants cannot be l-values."
+// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
+// are built-in types, entire structures or arrays... are all l-values."
+//
+TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output)
+ : TIntermTraverser(true, false, false)
+{
+ mVersion = ShaderOutputTypeToGLSLVersion(output);
+ if (pragma.stdgl.invariantAll)
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+ if (type == GL_COMPUTE_SHADER)
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_430);
+ }
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol *node)
+{
+ if (node->variable().symbolType() == SymbolType::BuiltIn &&
+ node->getName() == kGlPointCoordString)
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+}
+
+bool TVersionGLSL::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ const TIntermSequence &sequence = *(node->getSequence());
+ if (sequence.front()->getAsTyped()->getType().isInvariant())
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+ return true;
+}
+
+bool TVersionGLSL::visitInvariantDeclaration(Visit, TIntermInvariantDeclaration *node)
+{
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ return true;
+}
+
+void TVersionGLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ size_t paramCount = node->getFunction()->getParamCount();
+ for (size_t i = 0; i < paramCount; ++i)
+ {
+ const TVariable *param = node->getFunction()->getParam(i);
+ const TType &type = param->getType();
+ if (type.isArray())
+ {
+ TQualifier qualifier = type.getQualifier();
+ if ((qualifier == EvqOut) || (qualifier == EvqInOut))
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ break;
+ }
+ }
+ }
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpConstruct && node->getType().isMatrix())
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ if (sequence.size() == 1)
+ {
+ TIntermTyped *typed = sequence.front()->getAsTyped();
+ if (typed && typed->isMatrix())
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
+ }
+ }
+ return true;
+}
+
+void TVersionGLSL::ensureVersionIsAtLeast(int version)
+{
+ mVersion = std::max(version, mVersion);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/VersionGLSL.h b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.h
new file mode 100644
index 0000000000..f05da966f4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.h
@@ -0,0 +1,76 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_VERSIONGLSL_H_
+#define COMPILER_TRANSLATOR_VERSIONGLSL_H_
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+#include "compiler/translator/Pragma.h"
+
+namespace sh
+{
+
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+static const int GLSL_VERSION_130 = 130;
+static const int GLSL_VERSION_140 = 140;
+static const int GLSL_VERSION_150 = 150;
+static const int GLSL_VERSION_330 = 330;
+static const int GLSL_VERSION_400 = 400;
+static const int GLSL_VERSION_410 = 410;
+static const int GLSL_VERSION_420 = 420;
+static const int GLSL_VERSION_430 = 430;
+static const int GLSL_VERSION_440 = 440;
+static const int GLSL_VERSION_450 = 450;
+
+int ShaderOutputTypeToGLSLVersion(ShShaderOutput output);
+
+// Traverses the intermediate tree to return the minimum GLSL version
+// required to legally access all built-in features used in the shader.
+// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
+// - #version and #extension to declare version and extensions.
+// - built-in functions refract, exp, and log.
+// - updated step() to compare x < edge instead of x <= edge.
+// GLSL 1.2 which is mandated by OpenGL 2.1 provides:
+// - many changes to reduce differences when compared to the ES specification.
+// - invariant keyword and its support.
+// - c++ style name hiding rules.
+// - built-in variable gl_PointCoord for fragment shaders.
+// - matrix constructors taking matrix as argument.
+// - array as "out" function parameters
+//
+// TODO: ES3 equivalent versions of GLSL
+class TVersionGLSL : public TIntermTraverser
+{
+ public:
+ TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output);
+
+ // If output is core profile, returns 150.
+ // If output is legacy profile,
+ // Returns 120 if the following is used the shader:
+ // - "invariant",
+ // - "gl_PointCoord",
+ // - matrix/matrix constructors
+ // - array "out" parameters
+ // Else 110 is returned.
+ int getVersion() const { return mVersion; }
+
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+ bool visitInvariantDeclaration(Visit, TIntermInvariantDeclaration *node) override;
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+
+ private:
+ void ensureVersionIsAtLeast(int version);
+
+ int mVersion;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_VERSIONGLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayout.cpp b/gfx/angle/checkout/src/compiler/translator/blocklayout.cpp
new file mode 100644
index 0000000000..7d0609ec82
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/blocklayout.cpp
@@ -0,0 +1,606 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// blocklayout.cpp:
+// Implementation for block layout classes and methods.
+//
+
+#include "compiler/translator/blocklayout.h"
+
+#include "common/mathutil.h"
+#include "common/utilities.h"
+#include "compiler/translator/Common.h"
+
+namespace sh
+{
+
+namespace
+{
+class BlockLayoutMapVisitor : public BlockEncoderVisitor
+{
+ public:
+ BlockLayoutMapVisitor(BlockLayoutMap *blockInfoOut,
+ const std::string &instanceName,
+ BlockLayoutEncoder *encoder)
+ : BlockEncoderVisitor(instanceName, instanceName, encoder), mInfoOut(blockInfoOut)
+ {}
+
+ void encodeVariable(const ShaderVariable &variable,
+ const BlockMemberInfo &variableInfo,
+ const std::string &name,
+ const std::string &mappedName) override
+ {
+ ASSERT(!gl::IsSamplerType(variable.type));
+ (*mInfoOut)[name] = variableInfo;
+ }
+
+ private:
+ BlockLayoutMap *mInfoOut;
+};
+
+template <typename VarT>
+void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
+ const std::string &prefix,
+ BlockLayoutEncoder *encoder,
+ bool inRowMajorLayout,
+ BlockLayoutMap *blockInfoOut)
+{
+ BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder);
+ TraverseShaderVariables(fields, inRowMajorLayout, &visitor);
+}
+
+void TraverseStructVariable(const ShaderVariable &variable,
+ bool isRowMajorLayout,
+ ShaderVariableVisitor *visitor)
+{
+ const std::vector<ShaderVariable> &fields = variable.fields;
+
+ visitor->enterStructAccess(variable, isRowMajorLayout);
+ TraverseShaderVariables(fields, isRowMajorLayout, visitor);
+ visitor->exitStructAccess(variable, isRowMajorLayout);
+}
+
+void TraverseStructArrayVariable(const ShaderVariable &variable,
+ bool inRowMajorLayout,
+ ShaderVariableVisitor *visitor)
+{
+ visitor->enterArray(variable);
+
+ // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
+ // innermost. We make a special case for unsized arrays.
+ const unsigned int currentArraySize = variable.getNestedArraySize(0);
+ unsigned int count = std::max(currentArraySize, 1u);
+ for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
+ {
+ visitor->enterArrayElement(variable, arrayElement);
+ ShaderVariable elementVar = variable;
+ elementVar.indexIntoArray(arrayElement);
+
+ if (variable.arraySizes.size() > 1u)
+ {
+ TraverseStructArrayVariable(elementVar, inRowMajorLayout, visitor);
+ }
+ else
+ {
+ TraverseStructVariable(elementVar, inRowMajorLayout, visitor);
+ }
+
+ visitor->exitArrayElement(variable, arrayElement);
+ }
+
+ visitor->exitArray(variable);
+}
+
+void TraverseArrayOfArraysVariable(const ShaderVariable &variable,
+ unsigned int arrayNestingIndex,
+ bool isRowMajorMatrix,
+ ShaderVariableVisitor *visitor)
+{
+ visitor->enterArray(variable);
+
+ const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
+ unsigned int count = std::max(currentArraySize, 1u);
+ for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
+ {
+ visitor->enterArrayElement(variable, arrayElement);
+
+ ShaderVariable elementVar = variable;
+ elementVar.indexIntoArray(arrayElement);
+
+ if (arrayNestingIndex + 2u < variable.arraySizes.size())
+ {
+ TraverseArrayOfArraysVariable(elementVar, arrayNestingIndex, isRowMajorMatrix, visitor);
+ }
+ else
+ {
+ if (gl::IsSamplerType(variable.type))
+ {
+ visitor->visitSampler(elementVar);
+ }
+ else
+ {
+ visitor->visitVariable(elementVar, isRowMajorMatrix);
+ }
+ }
+
+ visitor->exitArrayElement(variable, arrayElement);
+ }
+
+ visitor->exitArray(variable);
+}
+
+std::string CollapseNameStack(const std::vector<std::string> &nameStack)
+{
+ std::stringstream strstr = sh::InitializeStream<std::stringstream>();
+ for (const std::string &part : nameStack)
+ {
+ strstr << part;
+ }
+ return strstr.str();
+}
+
+size_t GetStd430BaseAlignment(GLenum variableType, bool isRowMajor)
+{
+ GLenum flippedType = isRowMajor ? variableType : gl::TransposeMatrixType(variableType);
+ size_t numComponents = static_cast<size_t>(gl::VariableColumnCount(flippedType));
+ return ComponentAlignment(numComponents);
+}
+
+class BaseAlignmentVisitor : public ShaderVariableVisitor
+{
+ public:
+ BaseAlignmentVisitor() = default;
+ void visitVariable(const ShaderVariable &variable, bool isRowMajor) override
+ {
+ size_t baseAlignment = GetStd430BaseAlignment(variable.type, isRowMajor);
+ mCurrentAlignment = std::max(mCurrentAlignment, baseAlignment);
+ }
+
+ // This is in components rather than bytes.
+ size_t getBaseAlignment() const { return mCurrentAlignment; }
+
+ private:
+ size_t mCurrentAlignment = 0;
+};
+} // anonymous namespace
+
+// BlockLayoutEncoder implementation.
+BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) {}
+
+BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix)
+{
+ int arrayStride;
+ int matrixStride;
+
+ getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
+
+ const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent),
+ static_cast<int>(arrayStride * kBytesPerComponent),
+ static_cast<int>(matrixStride * kBytesPerComponent),
+ isRowMajorMatrix);
+
+ advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
+
+ return memberInfo;
+}
+
+size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor)
+{
+ size_t currentOffset = mCurrentOffset;
+ mCurrentOffset = 0;
+ BlockEncoderVisitor visitor("", "", this);
+ enterAggregateType(structVar);
+ TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
+ exitAggregateType(structVar);
+ size_t structVarSize = getCurrentOffset();
+ mCurrentOffset = currentOffset;
+ return structVarSize;
+}
+
+// static
+size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
+{
+ return (info.offset / kBytesPerComponent) / kComponentsPerRegister;
+}
+
+// static
+size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info)
+{
+ return (info.offset / kBytesPerComponent) % kComponentsPerRegister;
+}
+
+void BlockLayoutEncoder::align(size_t baseAlignment)
+{
+ mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, baseAlignment);
+}
+
+// DummyBlockEncoder implementation.
+void DummyBlockEncoder::getBlockLayoutInfo(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut)
+{
+ *arrayStrideOut = 0;
+ *matrixStrideOut = 0;
+}
+
+// Std140BlockEncoder implementation.
+Std140BlockEncoder::Std140BlockEncoder() {}
+
+void Std140BlockEncoder::enterAggregateType(const ShaderVariable &structVar)
+{
+ align(getBaseAlignment(structVar));
+}
+
+void Std140BlockEncoder::exitAggregateType(const ShaderVariable &structVar)
+{
+ align(getBaseAlignment(structVar));
+}
+
+void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut)
+{
+ // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
+ ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
+
+ size_t baseAlignment = 0;
+ int matrixStride = 0;
+ int arrayStride = 0;
+
+ if (gl::IsMatrixType(type))
+ {
+ baseAlignment = getTypeBaseAlignment(type, isRowMajorMatrix);
+ matrixStride = getTypeBaseAlignment(type, isRowMajorMatrix);
+
+ if (!arraySizes.empty())
+ {
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ arrayStride = getTypeBaseAlignment(type, isRowMajorMatrix) * numRegisters;
+ }
+ }
+ else if (!arraySizes.empty())
+ {
+ baseAlignment = getTypeBaseAlignment(type, false);
+ arrayStride = getTypeBaseAlignment(type, false);
+ }
+ else
+ {
+ const size_t numComponents = static_cast<size_t>(gl::VariableComponentCount(type));
+ baseAlignment = ComponentAlignment(numComponents);
+ }
+
+ mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
+
+ *matrixStrideOut = matrixStride;
+ *arrayStrideOut = arrayStride;
+}
+
+void Std140BlockEncoder::advanceOffset(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride)
+{
+ if (!arraySizes.empty())
+ {
+ mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes);
+ }
+ else if (gl::IsMatrixType(type))
+ {
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ mCurrentOffset += matrixStride * numRegisters;
+ }
+ else
+ {
+ mCurrentOffset += gl::VariableComponentCount(type);
+ }
+}
+
+size_t Std140BlockEncoder::getBaseAlignment(const ShaderVariable &variable) const
+{
+ return kComponentsPerRegister;
+}
+
+size_t Std140BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
+{
+ return kComponentsPerRegister;
+}
+
+// Std430BlockEncoder implementation.
+Std430BlockEncoder::Std430BlockEncoder() {}
+
+size_t Std430BlockEncoder::getBaseAlignment(const ShaderVariable &shaderVar) const
+{
+ if (shaderVar.isStruct())
+ {
+ BaseAlignmentVisitor visitor;
+ TraverseShaderVariables(shaderVar.fields, false, &visitor);
+ return visitor.getBaseAlignment();
+ }
+
+ return GetStd430BaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout);
+}
+
+size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
+{
+ return GetStd430BaseAlignment(type, isRowMajorMatrix);
+}
+
+void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
+ const std::string &prefix,
+ BlockLayoutEncoder *encoder,
+ BlockLayoutMap *blockInfoOut)
+{
+ // Matrix packing is always recorded in individual fields, so they'll set the row major layout
+ // flag to true if needed.
+ GetInterfaceBlockInfo(fields, prefix, encoder, false, blockInfoOut);
+}
+
+void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
+ const std::string &prefix,
+ BlockLayoutEncoder *encoder,
+ BlockLayoutMap *blockInfoOut)
+{
+ // Matrix packing is always recorded in individual fields, so they'll set the row major layout
+ // flag to true if needed.
+ GetInterfaceBlockInfo(uniforms, prefix, encoder, false, blockInfoOut);
+}
+
+// VariableNameVisitor implementation.
+VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix,
+ const std::string &mappedNamePrefix)
+{
+ if (!namePrefix.empty())
+ {
+ mNameStack.push_back(namePrefix + ".");
+ }
+
+ if (!mappedNamePrefix.empty())
+ {
+ mMappedNameStack.push_back(mappedNamePrefix + ".");
+ }
+}
+
+VariableNameVisitor::~VariableNameVisitor() = default;
+
+void VariableNameVisitor::enterStruct(const ShaderVariable &structVar)
+{
+ mNameStack.push_back(structVar.name);
+ mMappedNameStack.push_back(structVar.mappedName);
+}
+
+void VariableNameVisitor::exitStruct(const ShaderVariable &structVar)
+{
+ mNameStack.pop_back();
+ mMappedNameStack.pop_back();
+}
+
+void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
+{
+ mNameStack.push_back(".");
+ mMappedNameStack.push_back(".");
+}
+
+void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
+{
+ mNameStack.pop_back();
+ mMappedNameStack.pop_back();
+}
+
+void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar)
+{
+ if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
+ {
+ mNameStack.push_back(arrayVar.name);
+ mMappedNameStack.push_back(arrayVar.mappedName);
+ }
+}
+
+void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
+{
+ if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
+ {
+ mNameStack.pop_back();
+ mMappedNameStack.pop_back();
+ }
+}
+
+void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar,
+ unsigned int arrayElement)
+{
+ std::stringstream strstr = sh::InitializeStream<std::stringstream>();
+ strstr << "[" << arrayElement << "]";
+ std::string elementString = strstr.str();
+ mNameStack.push_back(elementString);
+ mMappedNameStack.push_back(elementString);
+}
+
+void VariableNameVisitor::exitArrayElement(const ShaderVariable &arrayVar,
+ unsigned int arrayElement)
+{
+ mNameStack.pop_back();
+ mMappedNameStack.pop_back();
+}
+
+std::string VariableNameVisitor::collapseNameStack() const
+{
+ return CollapseNameStack(mNameStack);
+}
+
+std::string VariableNameVisitor::collapseMappedNameStack() const
+{
+ return CollapseNameStack(mMappedNameStack);
+}
+
+void VariableNameVisitor::visitSampler(const sh::ShaderVariable &sampler)
+{
+ if (!sampler.hasParentArrayIndex())
+ {
+ mNameStack.push_back(sampler.name);
+ mMappedNameStack.push_back(sampler.mappedName);
+ }
+
+ std::string name = collapseNameStack();
+ std::string mappedName = collapseMappedNameStack();
+
+ if (!sampler.hasParentArrayIndex())
+ {
+ mNameStack.pop_back();
+ mMappedNameStack.pop_back();
+ }
+
+ visitNamedSampler(sampler, name, mappedName);
+}
+
+void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
+{
+ if (!variable.hasParentArrayIndex())
+ {
+ mNameStack.push_back(variable.name);
+ mMappedNameStack.push_back(variable.mappedName);
+ }
+
+ std::string name = collapseNameStack();
+ std::string mappedName = collapseMappedNameStack();
+
+ if (!variable.hasParentArrayIndex())
+ {
+ mNameStack.pop_back();
+ mMappedNameStack.pop_back();
+ }
+
+ visitNamedVariable(variable, isRowMajor, name, mappedName);
+}
+
+// BlockEncoderVisitor implementation.
+BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix,
+ const std::string &mappedNamePrefix,
+ BlockLayoutEncoder *encoder)
+ : VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder)
+{}
+
+BlockEncoderVisitor::~BlockEncoderVisitor() = default;
+
+void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
+{
+ mStructStackSize++;
+ if (!mIsTopLevelArrayStrideReady)
+ {
+ size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor);
+ mTopLevelArrayStride *= structSize;
+ mIsTopLevelArrayStrideReady = true;
+ }
+
+ VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
+ mEncoder->enterAggregateType(structVar);
+}
+
+void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
+{
+ mStructStackSize--;
+ mEncoder->exitAggregateType(structVar);
+ VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
+}
+
+void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar,
+ unsigned int arrayElement)
+{
+ if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
+ {
+ // From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
+ // For an active shader storage block member declared as an array of an aggregate type,
+ // an entry will be generated only for the first array element, regardless of its type.
+ // Such block members are referred to as top-level arrays. If the block member is an
+ // aggregate type, the enumeration rules are then applied recursively.
+ if (arrayElement == 0)
+ {
+ mTopLevelArraySize = arrayVar.getOutermostArraySize();
+ mTopLevelArrayStride = arrayVar.getInnerArraySizeProduct();
+ mIsTopLevelArrayStrideReady = false;
+ }
+ else
+ {
+ mSkipEnabled = true;
+ }
+ }
+ VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
+}
+
+void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar,
+ unsigned int arrayElement)
+{
+ if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
+ {
+ mTopLevelArraySize = 1;
+ mTopLevelArrayStride = 0;
+ mIsTopLevelArrayStrideReady = true;
+ mSkipEnabled = false;
+ }
+ VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
+}
+
+void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
+ bool isRowMajor,
+ const std::string &name,
+ const std::string &mappedName)
+{
+ std::vector<unsigned int> innermostArraySize;
+
+ if (variable.isArray())
+ {
+ innermostArraySize.push_back(variable.getNestedArraySize(0));
+ }
+ BlockMemberInfo variableInfo =
+ mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
+ if (!mIsTopLevelArrayStrideReady)
+ {
+ ASSERT(mTopLevelArrayStride);
+ mTopLevelArrayStride *= variableInfo.arrayStride;
+ mIsTopLevelArrayStrideReady = true;
+ }
+ variableInfo.topLevelArrayStride = mTopLevelArrayStride;
+ encodeVariable(variable, variableInfo, name, mappedName);
+}
+
+void TraverseShaderVariable(const ShaderVariable &variable,
+ bool isRowMajorLayout,
+ ShaderVariableVisitor *visitor)
+{
+ bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout);
+ bool isRowMajor = rowMajorLayout && gl::IsMatrixType(variable.type);
+
+ if (variable.isStruct())
+ {
+ visitor->enterStruct(variable);
+ if (variable.isArray())
+ {
+ TraverseStructArrayVariable(variable, rowMajorLayout, visitor);
+ }
+ else
+ {
+ TraverseStructVariable(variable, rowMajorLayout, visitor);
+ }
+ visitor->exitStruct(variable);
+ }
+ else if (variable.isArrayOfArrays())
+ {
+ TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
+ }
+ else if (gl::IsSamplerType(variable.type))
+ {
+ visitor->visitSampler(variable);
+ }
+ else
+ {
+ visitor->visitVariable(variable, isRowMajor);
+ }
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayout.h b/gfx/angle/checkout/src/compiler/translator/blocklayout.h
new file mode 100644
index 0000000000..30d5d1c3a5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/blocklayout.h
@@ -0,0 +1,302 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// blocklayout.h:
+// Methods and classes related to uniform layout and packing in GLSL and HLSL.
+//
+
+#ifndef COMMON_BLOCKLAYOUT_H_
+#define COMMON_BLOCKLAYOUT_H_
+
+#include <cstddef>
+#include <map>
+#include <vector>
+
+#include <GLSLANG/ShaderLang.h>
+#include "angle_gl.h"
+
+namespace sh
+{
+struct ShaderVariable;
+struct InterfaceBlockField;
+struct Uniform;
+struct Varying;
+struct InterfaceBlock;
+
+struct BlockMemberInfo
+{
+ constexpr BlockMemberInfo() = default;
+
+ constexpr BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
+ : offset(offset),
+ arrayStride(arrayStride),
+ matrixStride(matrixStride),
+ isRowMajorMatrix(isRowMajorMatrix)
+ {}
+
+ constexpr BlockMemberInfo(int offset,
+ int arrayStride,
+ int matrixStride,
+ bool isRowMajorMatrix,
+ int topLevelArrayStride)
+ : offset(offset),
+ arrayStride(arrayStride),
+ matrixStride(matrixStride),
+ isRowMajorMatrix(isRowMajorMatrix),
+ topLevelArrayStride(topLevelArrayStride)
+ {}
+
+ // A single integer identifying the offset of an active variable.
+ int offset = -1;
+
+ // A single integer identifying the stride between array elements in an active variable.
+ int arrayStride = -1;
+
+ // A single integer identifying the stride between columns of a column-major matrix or rows of a
+ // row-major matrix.
+ int matrixStride = -1;
+
+ // A single integer identifying whether an active variable is a row-major matrix.
+ bool isRowMajorMatrix = false;
+
+ // A single integer identifying the number of active array elements of the top-level shader
+ // storage block member containing the active variable.
+ int topLevelArrayStride = -1;
+};
+
+constexpr size_t ComponentAlignment(size_t numComponents)
+{
+ return (numComponents == 3u ? 4u : numComponents);
+}
+
+constexpr BlockMemberInfo kDefaultBlockMemberInfo;
+
+class BlockLayoutEncoder
+{
+ public:
+ BlockLayoutEncoder();
+ virtual ~BlockLayoutEncoder() {}
+
+ BlockMemberInfo encodeType(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix);
+
+ size_t getCurrentOffset() const { return mCurrentOffset * kBytesPerComponent; }
+ size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor);
+
+ // Called when entering/exiting a structure variable.
+ virtual void enterAggregateType(const ShaderVariable &structVar) = 0;
+ virtual void exitAggregateType(const ShaderVariable &structVar) = 0;
+
+ static constexpr size_t kBytesPerComponent = 4u;
+ static constexpr unsigned int kComponentsPerRegister = 4u;
+
+ static size_t GetBlockRegister(const BlockMemberInfo &info);
+ static size_t GetBlockRegisterElement(const BlockMemberInfo &info);
+
+ protected:
+ void align(size_t baseAlignment);
+
+ virtual void getBlockLayoutInfo(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut) = 0;
+ virtual void advanceOffset(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride) = 0;
+
+ size_t mCurrentOffset;
+};
+
+// Will return default values for everything.
+class DummyBlockEncoder : public BlockLayoutEncoder
+{
+ public:
+ DummyBlockEncoder() = default;
+
+ void enterAggregateType(const ShaderVariable &structVar) override {}
+ void exitAggregateType(const ShaderVariable &structVar) override {}
+
+ protected:
+ void getBlockLayoutInfo(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut) override;
+
+ void advanceOffset(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride) override
+ {}
+};
+
+// Block layout according to the std140 block layout
+// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
+
+class Std140BlockEncoder : public BlockLayoutEncoder
+{
+ public:
+ Std140BlockEncoder();
+
+ void enterAggregateType(const ShaderVariable &structVar) override;
+ void exitAggregateType(const ShaderVariable &structVar) override;
+
+ protected:
+ void getBlockLayoutInfo(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut) override;
+ void advanceOffset(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride) override;
+
+ virtual size_t getBaseAlignment(const ShaderVariable &variable) const;
+ virtual size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const;
+};
+
+class Std430BlockEncoder : public Std140BlockEncoder
+{
+ public:
+ Std430BlockEncoder();
+
+ protected:
+ size_t getBaseAlignment(const ShaderVariable &variable) const override;
+ size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const override;
+};
+
+using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
+
+void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
+ const std::string &prefix,
+ BlockLayoutEncoder *encoder,
+ BlockLayoutMap *blockInfoOut);
+
+// Used for laying out the default uniform block on the Vulkan backend.
+void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
+ const std::string &prefix,
+ BlockLayoutEncoder *encoder,
+ BlockLayoutMap *blockInfoOut);
+
+class ShaderVariableVisitor
+{
+ public:
+ virtual ~ShaderVariableVisitor() {}
+
+ virtual void enterStruct(const ShaderVariable &structVar) {}
+ virtual void exitStruct(const ShaderVariable &structVar) {}
+
+ virtual void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
+ virtual void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
+
+ virtual void enterArray(const ShaderVariable &arrayVar) {}
+ virtual void exitArray(const ShaderVariable &arrayVar) {}
+
+ virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
+ virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
+
+ virtual void visitSampler(const sh::ShaderVariable &sampler) {}
+
+ virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0;
+
+ protected:
+ ShaderVariableVisitor() {}
+};
+
+class VariableNameVisitor : public ShaderVariableVisitor
+{
+ public:
+ VariableNameVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix);
+ ~VariableNameVisitor() override;
+
+ void enterStruct(const ShaderVariable &structVar) override;
+ void exitStruct(const ShaderVariable &structVar) override;
+ void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
+ void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
+ void enterArray(const ShaderVariable &arrayVar) override;
+ void exitArray(const ShaderVariable &arrayVar) override;
+ void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
+ void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
+
+ protected:
+ virtual void visitNamedSampler(const sh::ShaderVariable &sampler,
+ const std::string &name,
+ const std::string &mappedName)
+ {}
+ virtual void visitNamedVariable(const ShaderVariable &variable,
+ bool isRowMajor,
+ const std::string &name,
+ const std::string &mappedName) = 0;
+
+ std::string collapseNameStack() const;
+ std::string collapseMappedNameStack() const;
+
+ private:
+ void visitSampler(const sh::ShaderVariable &sampler) final;
+ void visitVariable(const ShaderVariable &variable, bool isRowMajor) final;
+
+ std::vector<std::string> mNameStack;
+ std::vector<std::string> mMappedNameStack;
+};
+
+class BlockEncoderVisitor : public VariableNameVisitor
+{
+ public:
+ BlockEncoderVisitor(const std::string &namePrefix,
+ const std::string &mappedNamePrefix,
+ BlockLayoutEncoder *encoder);
+ ~BlockEncoderVisitor() override;
+
+ void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
+ void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
+ void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
+ void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
+
+ void visitNamedVariable(const ShaderVariable &variable,
+ bool isRowMajor,
+ const std::string &name,
+ const std::string &mappedName) override;
+
+ virtual void encodeVariable(const ShaderVariable &variable,
+ const BlockMemberInfo &variableInfo,
+ const std::string &name,
+ const std::string &mappedName)
+ {}
+
+ protected:
+ int mTopLevelArraySize = 1;
+ int mTopLevelArrayStride = 0;
+ bool mIsTopLevelArrayStrideReady = true;
+ bool mSkipEnabled = false;
+
+ private:
+ BlockLayoutEncoder *mEncoder;
+ unsigned int mStructStackSize = 0;
+};
+
+void TraverseShaderVariable(const ShaderVariable &variable,
+ bool isRowMajorLayout,
+ ShaderVariableVisitor *visitor);
+
+template <typename T>
+void TraverseShaderVariables(const std::vector<T> &vars,
+ bool isRowMajorLayout,
+ ShaderVariableVisitor *visitor)
+{
+ for (const T &var : vars)
+ {
+ TraverseShaderVariable(var, isRowMajorLayout, visitor);
+ }
+}
+} // namespace sh
+
+#endif // COMMON_BLOCKLAYOUT_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp
new file mode 100644
index 0000000000..dde403699c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// blocklayout.cpp:
+// Implementation for block layout classes and methods.
+//
+
+#include "compiler/translator/blocklayoutHLSL.h"
+
+#include "common/mathutil.h"
+#include "common/utilities.h"
+
+namespace sh
+{
+
+HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices)
+ : mEncoderStrategy(strategy), mTransposeMatrices(transposeMatrices)
+{}
+
+void HLSLBlockEncoder::enterAggregateType(const ShaderVariable &structVar)
+{
+ align(kComponentsPerRegister);
+}
+
+void HLSLBlockEncoder::exitAggregateType(const ShaderVariable &structVar) {}
+
+void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut)
+{
+ GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn);
+
+ // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
+ ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
+
+ int matrixStride = 0;
+ int arrayStride = 0;
+
+ // if variables are not to be packed, or we're about to
+ // pack a matrix or array, skip to the start of the next
+ // register
+ if (!isPacked() || gl::IsMatrixType(type) || !arraySizes.empty())
+ {
+ align(kComponentsPerRegister);
+ }
+
+ if (gl::IsMatrixType(type))
+ {
+ matrixStride = kComponentsPerRegister;
+
+ if (!arraySizes.empty())
+ {
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ arrayStride = kComponentsPerRegister * numRegisters;
+ }
+ }
+ else if (!arraySizes.empty())
+ {
+ arrayStride = kComponentsPerRegister;
+ }
+ else if (isPacked())
+ {
+ int numComponents = gl::VariableComponentCount(type);
+ if ((numComponents + (mCurrentOffset % kComponentsPerRegister)) > kComponentsPerRegister)
+ {
+ align(kComponentsPerRegister);
+ }
+ }
+
+ *matrixStrideOut = matrixStride;
+ *arrayStrideOut = arrayStride;
+}
+
+void HLSLBlockEncoder::advanceOffset(GLenum typeIn,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride)
+{
+ GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn);
+
+ if (!arraySizes.empty())
+ {
+ unsigned int arraySize = gl::ArraySizeProduct(arraySizes);
+ if (arraySize > 0)
+ {
+ mCurrentOffset += arrayStride * (arraySize - 1);
+ }
+ }
+
+ if (gl::IsMatrixType(type))
+ {
+ ASSERT(matrixStride == kComponentsPerRegister);
+ const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+ const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
+ mCurrentOffset += kComponentsPerRegister * (numRegisters - 1);
+ mCurrentOffset += numComponents;
+ }
+ else if (isPacked())
+ {
+ mCurrentOffset += gl::VariableComponentCount(type);
+ }
+ else
+ {
+ mCurrentOffset += kComponentsPerRegister;
+ }
+}
+
+void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
+{
+ mCurrentOffset += (numRegisters * kComponentsPerRegister);
+}
+
+HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(
+ ShShaderOutput outputType)
+{
+ switch (outputType)
+ {
+ case SH_HLSL_3_0_OUTPUT:
+ return ENCODE_LOOSE;
+ case SH_HLSL_4_1_OUTPUT:
+ case SH_HLSL_4_0_FL9_3_OUTPUT:
+ return ENCODE_PACKED;
+ default:
+ UNREACHABLE();
+ return ENCODE_PACKED;
+ }
+}
+
+template <class ShaderVarType>
+void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
+{
+ if (variable.isStruct())
+ {
+ for (size_t arrayElement = 0; arrayElement < variable.getArraySizeProduct(); arrayElement++)
+ {
+ encoder->enterAggregateType(variable);
+
+ for (const ShaderVariable &field : variable.fields)
+ {
+ HLSLVariableRegisterCount(field, encoder);
+ }
+
+ encoder->exitAggregateType(variable);
+ }
+ }
+ else
+ {
+ // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
+ encoder->encodeType(variable.type, variable.arraySizes, false);
+ }
+}
+
+unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
+{
+ HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType), true);
+ HLSLVariableRegisterCount(variable, &encoder);
+
+ const size_t registerBytes = (encoder.kBytesPerComponent * encoder.kComponentsPerRegister);
+ return static_cast<unsigned int>(
+ rx::roundUp<size_t>(encoder.getCurrentOffset(), registerBytes) / registerBytes);
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h
new file mode 100644
index 0000000000..98d93fccb0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h
@@ -0,0 +1,68 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// blocklayout.h:
+// Methods and classes related to uniform layout and packing in GLSL and HLSL.
+//
+
+#ifndef COMMON_BLOCKLAYOUTHLSL_H_
+#define COMMON_BLOCKLAYOUTHLSL_H_
+
+#include <cstddef>
+#include <vector>
+
+#include <GLSLANG/ShaderLang.h>
+#include "angle_gl.h"
+#include "blocklayout.h"
+
+namespace sh
+{
+// Block layout packed according to the D3D9 or default D3D10+ register packing rules
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx
+// The strategy should be ENCODE_LOOSE for D3D9 constant blocks, and ENCODE_PACKED
+// for everything else (D3D10+ constant blocks and all attributes/varyings).
+
+class HLSLBlockEncoder : public BlockLayoutEncoder
+{
+ public:
+ enum HLSLBlockEncoderStrategy
+ {
+ ENCODE_PACKED,
+ ENCODE_LOOSE
+ };
+
+ HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices);
+
+ void enterAggregateType(const ShaderVariable &structVar) override;
+ void exitAggregateType(const ShaderVariable &structVar) override;
+ void skipRegisters(unsigned int numRegisters);
+
+ bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; }
+
+ static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType);
+
+ protected:
+ void getBlockLayoutInfo(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut) override;
+ void advanceOffset(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride) override;
+
+ HLSLBlockEncoderStrategy mEncoderStrategy;
+ bool mTransposeMatrices;
+};
+
+// This method returns the number of used registers for a ShaderVariable. It is dependent on the
+// HLSLBlockEncoder class to count the number of used registers in a struct (which are individually
+// packed according to the same rules).
+unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType);
+} // namespace sh
+
+#endif // COMMON_BLOCKLAYOUTHLSL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp b/gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp
new file mode 100644
index 0000000000..c61e77a110
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp
@@ -0,0 +1,881 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_emulated_builtin_function_tables.py using data from
+// emulated_builtin_function_data_hlsl.json.
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// emulated_builtin_functions_hlsl:
+// HLSL code for emulating GLSL builtin functions not present in HLSL.
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+
+namespace sh
+{
+
+namespace
+{
+
+struct FunctionPair
+{
+ constexpr FunctionPair(const TSymbolUniqueId &idIn, const char *bodyIn)
+ : id(idIn.get()), body(bodyIn)
+ {}
+
+ int id;
+ const char *body;
+};
+
+constexpr FunctionPair g_hlslFunctions[] = {
+ {BuiltInId::mod_Float1_Float1,
+ "float mod_emu(float x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::mod_Float2_Float2,
+ "float2 mod_emu(float2 x, float2 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::mod_Float2_Float1,
+ "float2 mod_emu(float2 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::mod_Float3_Float3,
+ "float3 mod_emu(float3 x, float3 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::mod_Float3_Float1,
+ "float3 mod_emu(float3 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::mod_Float4_Float4,
+ "float4 mod_emu(float4 x, float4 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::mod_Float4_Float1,
+ "float4 mod_emu(float4 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"},
+ {BuiltInId::frexp_Float1_Int1,
+ "float frexp_emu(float x, out int exp)\n"
+ "{\n"
+ " float fexp;\n"
+ " float mantissa = frexp(abs(x), fexp) * sign(x);\n"
+ " exp = int(fexp);\n"
+ " return mantissa;\n"
+ "}\n"},
+ {BuiltInId::frexp_Float2_Int2,
+ "float2 frexp_emu(float2 x, out int2 exp)\n"
+ "{\n"
+ " float2 fexp;\n"
+ " float2 mantissa = frexp(abs(x), fexp) * sign(x);\n"
+ " exp = int2(fexp);\n"
+ " return mantissa;\n"
+ "}\n"},
+ {BuiltInId::frexp_Float3_Int3,
+ "float3 frexp_emu(float3 x, out int3 exp)\n"
+ "{\n"
+ " float3 fexp;\n"
+ " float3 mantissa = frexp(abs(x), fexp) * sign(x);\n"
+ " exp = int3(fexp);\n"
+ " return mantissa;\n"
+ "}\n"},
+ {BuiltInId::frexp_Float4_Int4,
+ "float4 frexp_emu(float4 x, out int4 exp)\n"
+ "{\n"
+ " float4 fexp;\n"
+ " float4 mantissa = frexp(abs(x), fexp) * sign(x);\n"
+ " exp = int4(fexp);\n"
+ " return mantissa;\n"
+ "}\n"},
+ {BuiltInId::ldexp_Float1_Int1,
+ "float ldexp_emu(float x, int exp)\n"
+ "{\n"
+ " return ldexp(x, float(exp));\n"
+ "}\n"},
+ {BuiltInId::ldexp_Float2_Int2,
+ "float2 ldexp_emu(float2 x, int2 exp)\n"
+ "{\n"
+ " return ldexp(x, float2(exp));\n"
+ "}\n"},
+ {BuiltInId::ldexp_Float3_Int3,
+ "float3 ldexp_emu(float3 x, int3 exp)\n"
+ "{\n"
+ " return ldexp(x, float3(exp));\n"
+ "}\n"},
+ {BuiltInId::ldexp_Float4_Int4,
+ "float4 ldexp_emu(float4 x, int4 exp)\n"
+ "{\n"
+ " return ldexp(x, float4(exp));\n"
+ "}\n"},
+ {BuiltInId::faceforward_Float1_Float1_Float1,
+ "float faceforward_emu(float N, float I, float Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"},
+ {BuiltInId::faceforward_Float2_Float2_Float2,
+ "float2 faceforward_emu(float2 N, float2 I, float2 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"},
+ {BuiltInId::faceforward_Float3_Float3_Float3,
+ "float3 faceforward_emu(float3 N, float3 I, float3 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"},
+ {BuiltInId::faceforward_Float4_Float4_Float4,
+ "float4 faceforward_emu(float4 N, float4 I, float4 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"},
+ {BuiltInId::atan_Float1_Float1,
+ "float atan_emu(float y, float x)\n"
+ "{\n"
+ " if(x == 0 && y == 0) x = 1;\n"
+ " return atan2(y, x);\n"
+ "}\n"},
+ {BuiltInId::atan_Float2_Float2,
+ "float2 atan_emu(float2 y, float2 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
+ "}\n"},
+ {BuiltInId::atan_Float3_Float3,
+ "float3 atan_emu(float3 y, float3 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
+ "}\n"},
+ {BuiltInId::atan_Float4_Float4,
+ "float4 atan_emu(float4 y, float4 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
+ " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], \n"
+ " x[2]), atan2(y[3], x[3]));\n"
+ "}\n"},
+ {BuiltInId::asinh_Float1,
+ "float asinh_emu(in float x)\n"
+ "{\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n"},
+ {BuiltInId::asinh_Float2,
+ "float2 asinh_emu(in float2 x)\n"
+ "{\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n"},
+ {BuiltInId::asinh_Float3,
+ "float3 asinh_emu(in float3 x)\n"
+ "{\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n"},
+ {BuiltInId::asinh_Float4,
+ "float4 asinh_emu(in float4 x)\n"
+ "{\n"
+ " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
+ "}\n"},
+ {BuiltInId::acosh_Float1,
+ "float acosh_emu(in float x)\n"
+ "{\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n"},
+ {BuiltInId::acosh_Float2,
+ "float2 acosh_emu(in float2 x)\n"
+ "{\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n"},
+ {BuiltInId::acosh_Float3,
+ "float3 acosh_emu(in float3 x)\n"
+ "{\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n"},
+ {BuiltInId::acosh_Float4,
+ "float4 acosh_emu(in float4 x)\n"
+ "{\n"
+ " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
+ "}\n"},
+ {BuiltInId::atanh_Float1,
+ "float atanh_emu(in float x)\n"
+ "{\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n"},
+ {BuiltInId::atanh_Float2,
+ "float2 atanh_emu(in float2 x)\n"
+ "{\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n"},
+ {BuiltInId::atanh_Float3,
+ "float3 atanh_emu(in float3 x)\n"
+ "{\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n"},
+ {BuiltInId::atanh_Float4,
+ "float4 atanh_emu(in float4 x)\n"
+ "{\n"
+ " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
+ "}\n"},
+ {BuiltInId::roundEven_Float1,
+ "float roundEven_emu(in float x)\n"
+ "{\n"
+ " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n"
+ "}\n"},
+ {BuiltInId::roundEven_Float2,
+ "float2 roundEven_emu(in float2 x)\n"
+ "{\n"
+ " float2 v;\n"
+ " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
+ " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
+ " return v;\n"
+ "}\n"},
+ {BuiltInId::roundEven_Float3,
+ "float3 roundEven_emu(in float3 x)\n"
+ "{\n"
+ " float3 v;\n"
+ " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
+ " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
+ " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
+ " return v;\n"
+ "}\n"},
+ {BuiltInId::roundEven_Float4,
+ "float4 roundEven_emu(in float4 x)\n"
+ "{\n"
+ " float4 v;\n"
+ " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
+ " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
+ " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
+ " v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n"
+ " return v;\n"
+ "}\n"},
+ {BuiltInId::packSnorm2x16_Float2,
+ "int webgl_toSnorm16(in float x) {\n"
+ " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
+ "}\n"
+ "uint packSnorm2x16_emu(in float2 v)\n"
+ "{\n"
+ " int x = webgl_toSnorm16(v.x);\n"
+ " int y = webgl_toSnorm16(v.y);\n"
+ " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
+ "}\n"},
+ {BuiltInId::packUnorm2x16_Float2,
+ "uint webgl_toUnorm16(in float x) {\n"
+ " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n"
+ "}\n"
+ "uint packUnorm2x16_emu(in float2 v)\n"
+ "{\n"
+ " uint x = webgl_toUnorm16(v.x);\n"
+ " uint y = webgl_toUnorm16(v.y);\n"
+ " return (y << 16) | x;\n"
+ "}\n"},
+ {BuiltInId::packHalf2x16_Float2,
+ "uint packHalf2x16_emu(in float2 v)\n"
+ "{\n"
+ " uint x = f32tof16(v.x);\n"
+ " uint y = f32tof16(v.y);\n"
+ " return (y << 16) | x;\n"
+ "}\n"},
+ {BuiltInId::unpackSnorm2x16_UInt1,
+ "float webgl_fromSnorm16(in uint x) {\n"
+ " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n"
+ " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
+ "}\n"
+ "float2 unpackSnorm2x16_emu(in uint u)\n"
+ "{\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u;\n"
+ " return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));\n"
+ "}\n"},
+ {BuiltInId::unpackUnorm2x16_UInt1,
+ "float webgl_fromUnorm16(in uint x) {\n"
+ " return float(x) / 65535.0;\n"
+ "}\n"
+ "float2 unpackUnorm2x16_emu(in uint u)\n"
+ "{\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u & 0xffffu;\n"
+ " return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));\n"
+ "}\n"},
+ {BuiltInId::unpackHalf2x16_UInt1,
+ "float2 unpackHalf2x16_emu(in uint u)\n"
+ "{\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u & 0xffffu;\n"
+ " return float2(f16tof32(x), f16tof32(y));\n"
+ "}\n"},
+ {BuiltInId::packSnorm4x8_Float4,
+ "int webgl_toSnorm8(in float x) {\n"
+ " return int(round(clamp(x, -1.0, 1.0) * 127.0));\n"
+ "}\n"
+ "uint packSnorm4x8_emu(in float4 v)\n"
+ "{\n"
+ " int x = webgl_toSnorm8(v.x);\n"
+ " int y = webgl_toSnorm8(v.y);\n"
+ " int z = webgl_toSnorm8(v.z);\n"
+ " int w = webgl_toSnorm8(v.w);\n"
+ " return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) \n"
+ " | ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);\n"
+ "}\n"},
+ {BuiltInId::packUnorm4x8_Float4,
+ "uint webgl_toUnorm8(in float x) {\n"
+ " return uint(round(clamp(x, 0.0, 1.0) * 255.0));\n"
+ "}\n"
+ "uint packUnorm4x8_emu(in float4 v)\n"
+ "{\n"
+ " uint x = webgl_toUnorm8(v.x);\n"
+ " uint y = webgl_toUnorm8(v.y);\n"
+ " uint z = webgl_toUnorm8(v.z);\n"
+ " uint w = webgl_toUnorm8(v.w);\n"
+ " return (w << 24) | (z << 16) | (y << 8) | x;\n"
+ "}\n"},
+ {BuiltInId::unpackSnorm4x8_UInt1,
+ "float webgl_fromSnorm8(in uint x) {\n"
+ " int xi = asint(x & 0x7fu) - asint(x & 0x80u);\n"
+ " return clamp(float(xi) / 127.0, -1.0, 1.0);\n"
+ "}\n"
+ "float4 unpackSnorm4x8_emu(in uint u)\n"
+ "{\n"
+ " uint w = (u >> 24);\n"
+ " uint z = (u >> 16);\n"
+ " uint y = (u >> 8);\n"
+ " uint x = u;\n"
+ " return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), \n"
+ " webgl_fromSnorm8(z), webgl_fromSnorm8(w));\n"
+ "}\n"},
+ {BuiltInId::unpackUnorm4x8_UInt1,
+ "float webgl_fromUnorm8(in uint x) {\n"
+ " return float(x) / 255.0;\n"
+ "}\n"
+ "float4 unpackUnorm4x8_emu(in uint u)\n"
+ "{\n"
+ " uint w = (u >> 24) & 0xffu;\n"
+ " uint z = (u >> 16) & 0xffu;\n"
+ " uint y = (u >> 8) & 0xffu;\n"
+ " uint x = u & 0xffu;\n"
+ " return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), \n"
+ " webgl_fromUnorm8(z), webgl_fromUnorm8(w));\n"
+ "}\n"},
+ // The matrix resulting from outer product needs to be transposed
+ // (matrices are stored as transposed to simplify element access in HLSL).
+ // So the function should return transpose(c * r) where c is a column vector
+ // and r is a row vector. This can be simplified by using the following
+ // formula:
+ // transpose(c * r) = transpose(r) * transpose(c)
+ // transpose(r) and transpose(c) are in a sense free, since to get the
+ // transpose of r, we simply can build a column matrix out of the original
+ // vector instead of a row matrix.
+ {BuiltInId::outerProduct_Float2_Float2,
+ "float2x2 outerProduct_emu(in float2 c, in float2 r)\n"
+ "{\n"
+ " return mul(float2x1(r), float1x2(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float3_Float3,
+ "float3x3 outerProduct_emu(in float3 c, in float3 r)\n"
+ "{\n"
+ " return mul(float3x1(r), float1x3(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float4_Float4,
+ "float4x4 outerProduct_emu(in float4 c, in float4 r)\n"
+ "{\n"
+ " return mul(float4x1(r), float1x4(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float3_Float2,
+ "float2x3 outerProduct_emu(in float3 c, in float2 r)\n"
+ "{\n"
+ " return mul(float2x1(r), float1x3(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float2_Float3,
+ "float3x2 outerProduct_emu(in float2 c, in float3 r)\n"
+ "{\n"
+ " return mul(float3x1(r), float1x2(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float4_Float2,
+ "float2x4 outerProduct_emu(in float4 c, in float2 r)\n"
+ "{\n"
+ " return mul(float2x1(r), float1x4(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float2_Float4,
+ "float4x2 outerProduct_emu(in float2 c, in float4 r)\n"
+ "{\n"
+ " return mul(float4x1(r), float1x2(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float4_Float3,
+ "float3x4 outerProduct_emu(in float4 c, in float3 r)\n"
+ "{\n"
+ " return mul(float3x1(r), float1x4(c));\n"
+ "}\n"},
+ {BuiltInId::outerProduct_Float3_Float4,
+ "float4x3 outerProduct_emu(in float3 c, in float4 r)\n"
+ "{\n"
+ " return mul(float4x1(r), float1x3(c));\n"
+ "}\n"},
+ // Remember here that the parameter matrix is actually the transpose
+ // of the matrix that we're trying to invert, and the resulting matrix
+ // should also be the transpose of the inverse.
+ // When accessing the parameter matrix with m[a][b] it can be thought of so
+ // that a is the column and b is the row of the matrix that we're inverting.
+ // We calculate the inverse as the adjugate matrix divided by the
+ // determinant of the matrix being inverted. However, as the result needs
+ // to be transposed, we actually use of the transpose of the adjugate matrix
+ // which happens to be the cofactor matrix. That's stored in 'cof'.
+ // We don't need to care about divide-by-zero since results are undefined
+ // for singular or poorly-conditioned matrices.
+ {BuiltInId::inverse_Float2x2,
+ "float2x2 inverse_emu(in float2x2 m)\n"
+ "{\n"
+ " float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n"
+ " return cof / determinant(transpose(m));\n"
+ "}\n"},
+ // cofAB is the cofactor for column A and row B.
+ {BuiltInId::inverse_Float3x3,
+ "float3x3 inverse_emu(in float3x3 m)\n"
+ "{\n"
+ " float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n"
+ " float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n"
+ " float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n"
+ " float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n"
+ " float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n"
+ " float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n"
+ " float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n"
+ " float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n"
+ " float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n"
+ " float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n"
+ " return cof / determinant(transpose(m));\n"
+ "}\n"},
+ {BuiltInId::inverse_Float4x4,
+ "float4x4 inverse_emu(in float4x4 m)\n"
+ "{\n"
+ " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * \n"
+ " m[1][2] * m[2][3]\n"
+ " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * \n"
+ " m[1][3];\n"
+ " float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * \n"
+ " m[1][2] * m[2][3]\n"
+ " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * \n"
+ " m[1][3]);\n"
+ " float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * \n"
+ " m[1][1] * m[2][3]\n"
+ " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * \n"
+ " m[1][3];\n"
+ " float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * \n"
+ " m[1][1] * m[2][2]\n"
+ " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * \n"
+ " m[1][2]);\n"
+ " float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * \n"
+ " m[0][2] * m[2][3]\n"
+ " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * \n"
+ " m[0][3]);\n"
+ " float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * \n"
+ " m[0][2] * m[2][3]\n"
+ " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * \n"
+ " m[0][3];\n"
+ " float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * \n"
+ " m[0][1] * m[2][3]\n"
+ " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * \n"
+ " m[0][3]);\n"
+ " float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * \n"
+ " m[0][1] * m[2][2]\n"
+ " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * \n"
+ " m[0][2];\n"
+ " float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * \n"
+ " m[0][2] * m[1][3]\n"
+ " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * \n"
+ " m[0][3];\n"
+ " float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * \n"
+ " m[0][2] * m[1][3]\n"
+ " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * \n"
+ " m[0][3]);\n"
+ " float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * \n"
+ " m[0][1] * m[1][3]\n"
+ " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * \n"
+ " m[0][3];\n"
+ " float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * \n"
+ " m[0][1] * m[1][2]\n"
+ " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * \n"
+ " m[0][2]);\n"
+ " float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * \n"
+ " m[0][2] * m[1][3]\n"
+ " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * \n"
+ " m[0][3]);\n"
+ " float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * \n"
+ " m[0][2] * m[1][3]\n"
+ " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * \n"
+ " m[0][3];\n"
+ " float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * \n"
+ " m[0][1] * m[1][3]\n"
+ " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * \n"
+ " m[0][3]);\n"
+ " float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * \n"
+ " m[0][1] * m[1][2]\n"
+ " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * \n"
+ " m[0][2];\n"
+ " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,\n"
+ " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n"
+ " return cof / determinant(transpose(m));\n"
+ "}\n"},
+ // Emulate ESSL3 variant of mix that takes last argument as boolean vector.
+ // genType mix(genType x, genType y, genBType a): Selects which vector each returned component
+ // comes from. For a component of 'a' that is false, the corresponding component of 'x' is
+ // returned. For a component of 'a' that is true, the corresponding component of 'y' is
+ // returned.
+ {BuiltInId::mix_Float1_Float1_Bool1,
+ "float mix_emu(float x, float y, bool a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n"},
+ {BuiltInId::mix_Float2_Float2_Bool2,
+ "float2 mix_emu(float2 x, float2 y, bool2 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n"},
+ {BuiltInId::mix_Float3_Float3_Bool3,
+ "float3 mix_emu(float3 x, float3 y, bool3 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n"},
+ {BuiltInId::mix_Float4_Float4_Bool4,
+ "float4 mix_emu(float4 x, float4 y, bool4 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_UInt1_Int1_Int1,
+ "uint bitfieldExtract_emu(uint value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return 0u;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " return (value & mask) >> offset;\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_UInt2_Int1_Int1,
+ "uint2 bitfieldExtract_emu(uint2 value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return uint2(0u, 0u);\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " return (value & mask) >> offset;\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_UInt3_Int1_Int1,
+ "uint3 bitfieldExtract_emu(uint3 value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return uint3(0u, 0u, 0u);\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " return (value & mask) >> offset;\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_UInt4_Int1_Int1,
+ "uint4 bitfieldExtract_emu(uint4 value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return uint4(0u, 0u, 0u, 0u);\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " return (value & mask) >> offset;\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_Int1_Int1_Int1,
+ "int bitfieldExtract_emu(int value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return 0;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint resultUnsigned = (asuint(value) & mask) >> offset;\n"
+ " if (bits != 32 && (resultUnsigned & maskMsb) != 0)\n"
+ " {\n"
+ " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
+ " resultUnsigned |= higherBitsMask;\n"
+ " }\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_Int2_Int1_Int1,
+ "int2 bitfieldExtract_emu(int2 value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return int2(0, 0);\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint2 resultUnsigned = (asuint(value) & mask) >> offset;\n"
+ " if (bits != 32)\n"
+ " {\n"
+ " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
+ " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
+ " }\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_Int3_Int1_Int1,
+ "int3 bitfieldExtract_emu(int3 value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return int3(0, 0, 0);\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint3 resultUnsigned = (asuint(value) & mask) >> offset;\n"
+ " if (bits != 32)\n"
+ " {\n"
+ " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
+ " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
+ " }\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldExtract_Int4_Int1_Int1,
+ "int4 bitfieldExtract_emu(int4 value, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return int4(0, 0, 0, 0);\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint4 resultUnsigned = (asuint(value) & mask) >> offset;\n"
+ " if (bits != 32)\n"
+ " {\n"
+ " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
+ " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
+ " }\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_UInt1_UInt1_Int1_Int1,
+ "uint bitfieldInsert_emu(uint base, uint insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " return (base & baseMask) | ((insert << offset) & insertMask);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_UInt2_UInt2_Int1_Int1,
+ "uint2 bitfieldInsert_emu(uint2 base, uint2 insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " return (base & baseMask) | ((insert << offset) & insertMask);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_UInt3_UInt3_Int1_Int1,
+ "uint3 bitfieldInsert_emu(uint3 base, uint3 insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " return (base & baseMask) | ((insert << offset) & insertMask);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_UInt4_UInt4_Int1_Int1,
+ "uint4 bitfieldInsert_emu(uint4 base, uint4 insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " return (base & baseMask) | ((insert << offset) & insertMask);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_Int1_Int1_Int1_Int1,
+ "int bitfieldInsert_emu(int base, int insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
+ " insertMask);\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_Int2_Int2_Int1_Int1,
+ "int2 bitfieldInsert_emu(int2 base, int2 insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
+ " insertMask);\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_Int3_Int3_Int1_Int1,
+ "int3 bitfieldInsert_emu(int3 base, int3 insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
+ " insertMask);\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::bitfieldInsert_Int4_Int4_Int1_Int1,
+ "int4 bitfieldInsert_emu(int4 base, int4 insert, int offset, int bits)\n"
+ "{\n"
+ " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
+ " {\n"
+ " return base;\n"
+ " }\n"
+ " uint maskMsb = (1u << (bits - 1));\n"
+ " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
+ " uint baseMask = ~insertMask;\n"
+ " uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
+ " insertMask);\n"
+ " return asint(resultUnsigned);\n"
+ "}\n"},
+ {BuiltInId::uaddCarry_UInt1_UInt1_UInt1,
+ "uint uaddCarry_emu(uint x, uint y, out uint carry)\n"
+ "{\n"
+ " carry = uint(x > (0xffffffffu - y));\n"
+ " return x + y;\n"
+ "}\n"},
+ {BuiltInId::uaddCarry_UInt2_UInt2_UInt2,
+ "uint2 uaddCarry_emu(uint2 x, uint2 y, out uint2 carry)\n"
+ "{\n"
+ " carry = uint2(x > (0xffffffffu - y));\n"
+ " return x + y;\n"
+ "}\n"},
+ {BuiltInId::uaddCarry_UInt3_UInt3_UInt3,
+ "uint3 uaddCarry_emu(uint3 x, uint3 y, out uint3 carry)\n"
+ "{\n"
+ " carry = uint3(x > (0xffffffffu - y));\n"
+ " return x + y;\n"
+ "}\n"},
+ {BuiltInId::uaddCarry_UInt4_UInt4_UInt4,
+ "uint4 uaddCarry_emu(uint4 x, uint4 y, out uint4 carry)\n"
+ "{\n"
+ " carry = uint4(x > (0xffffffffu - y));\n"
+ " return x + y;\n"
+ "}\n"},
+ {BuiltInId::usubBorrow_UInt1_UInt1_UInt1,
+ "uint usubBorrow_emu(uint x, uint y, out uint borrow)\n"
+ "{\n"
+ " borrow = uint(x < y);\n"
+ " return x - y;\n"
+ "}\n"},
+ {BuiltInId::usubBorrow_UInt2_UInt2_UInt2,
+ "uint2 usubBorrow_emu(uint2 x, uint2 y, out uint2 borrow)\n"
+ "{\n"
+ " borrow = uint2(x < y);\n"
+ " return x - y;\n"
+ "}\n"},
+ {BuiltInId::usubBorrow_UInt3_UInt3_UInt3,
+ "uint3 usubBorrow_emu(uint3 x, uint3 y, out uint3 borrow)\n"
+ "{\n"
+ " borrow = uint3(x < y);\n"
+ " return x - y;\n"
+ "}\n"},
+ {BuiltInId::usubBorrow_UInt4_UInt4_UInt4,
+ "uint4 usubBorrow_emu(uint4 x, uint4 y, out uint4 borrow)\n"
+ "{\n"
+ " borrow = uint4(x < y);\n"
+ " return x - y;\n"
+ "}\n"},
+ // We emulate tanh just to avoid overflow on large arguments.
+ {BuiltInId::tanh_Float1,
+ "float tanh_emu(float x)\n"
+ "{\n"
+ " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n"
+ "}\n"},
+ {BuiltInId::tanh_Float2,
+ "float2 tanh_emu(float2 x)\n"
+ "{\n"
+ " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n"
+ "}\n"},
+ {BuiltInId::tanh_Float3,
+ "float3 tanh_emu(float3 x)\n"
+ "{\n"
+ " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n"
+ "}\n"},
+ {BuiltInId::tanh_Float4,
+ "float4 tanh_emu(float4 x)\n"
+ "{\n"
+ " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n"
+ "}\n"},
+};
+} // anonymous namespace
+
+const char *FindHLSLFunction(int uniqueId)
+{
+ for (size_t index = 0; index < ArraySize(g_hlslFunctions); ++index)
+ {
+ const auto &function = g_hlslFunctions[index];
+ if (function.id == uniqueId)
+ {
+ return function.body;
+ }
+ }
+
+ return nullptr;
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/glslang.h b/gfx/angle/checkout/src/compiler/translator/glslang.h
new file mode 100644
index 0000000000..e54c31ba3e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/glslang.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_GLSLANG_H_
+#define COMPILER_TRANSLATOR_GLSLANG_H_
+
+namespace sh
+{
+class TParseContext;
+}
+
+extern int glslang_initialize(sh::TParseContext *context);
+extern int glslang_finalize(sh::TParseContext *context);
+
+extern int glslang_scan(size_t count,
+ const char *const string[],
+ const int length[],
+ sh::TParseContext *context);
+extern int glslang_parse(sh::TParseContext *context);
+
+#endif // COMPILER_TRANSLATOR_GLSLANG_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp b/gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp
new file mode 100644
index 0000000000..3a65f1ebce
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp
@@ -0,0 +1,4108 @@
+#line 17 "./glslang.l"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+/* clang-format off */
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4005)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#pragma warning(disable: 4702)
+#endif
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+// Flex isn't semi-colon clean.
+#pragma clang diagnostic ignored "-Wextra-semi-stmt"
+#endif
+
+
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+
+
+
+
+
+
+
+
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef yyget_lval
+#define yyget_lval_ALREADY_DEFINED
+#else
+#define yyget_lval yyget_lval
+#endif
+
+
+#ifdef yyset_lval
+#define yyset_lval_ALREADY_DEFINED
+#else
+#define yyset_lval yyset_lval
+#endif
+
+
+
+
+
+#ifdef yyget_lloc
+#define yyget_lloc_ALREADY_DEFINED
+#else
+#define yyget_lloc yyget_lloc
+#endif
+
+
+#ifdef yyset_lloc
+#define yyset_lloc_ALREADY_DEFINED
+#else
+#define yyset_lloc yyset_lloc
+#endif
+
+
+
+
+
+
+
+
+
+
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+
+
+
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+
+
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+ #define YY_LINENO_REWIND_TO(dst) \
+ do {\
+ const char *p;\
+ for ( p = yy_cp-1; p >= (dst); --p)\
+ if ( *p == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+
+
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+
+
+
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+
+/* Begin user sect3 */
+
+#define yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+
+
+
+
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+
+
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 247
+#define YY_END_OF_BUFFER 248
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[891] =
+ { 0,
+ 0, 0, 0, 0, 248, 246, 245, 245, 229, 235,
+ 240, 224, 225, 233, 232, 221, 230, 228, 234, 187,
+ 187, 222, 218, 236, 223, 237, 241, 184, 226, 227,
+ 239, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 219, 238, 220, 231, 244, 243, 247,
+ 242, 215, 201, 220, 209, 204, 199, 207, 197, 208,
+ 198, 193, 200, 192, 186, 187, 0, 190, 0, 227,
+ 219, 226, 216, 212, 214, 213, 217, 184, 205, 211,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+
+ 184, 184, 184, 184, 13, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 16, 184,
+ 184, 24, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 206, 210, 242,
+ 0, 196, 192, 0, 195, 189, 0, 191, 185, 202,
+ 203, 184, 184, 144, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 14, 184,
+
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 29,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 25, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 0,
+ 193, 0, 192, 194, 188, 184, 184, 184, 184, 32,
+ 184, 184, 184, 19, 181, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 17, 147, 184, 184, 184,
+ 184, 22, 184, 184, 151, 162, 184, 184, 184, 184,
+
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 159,
+ 4, 37, 38, 39, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 150,
+ 33, 184, 184, 30, 184, 184, 184, 184, 184, 184,
+ 184, 49, 50, 51, 31, 184, 184, 184, 184, 184,
+ 184, 184, 184, 11, 184, 55, 56, 57, 184, 145,
+ 184, 184, 7, 184, 184, 184, 184, 171, 172, 173,
+ 184, 34, 184, 163, 28, 174, 175, 176, 2, 168,
+ 169, 170, 184, 184, 184, 26, 166, 184, 184, 184,
+
+ 184, 184, 52, 53, 54, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 112, 184, 184, 184,
+ 184, 184, 184, 184, 184, 160, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 146, 184, 184,
+ 183, 58, 59, 60, 184, 184, 15, 184, 184, 184,
+ 117, 184, 184, 9, 184, 184, 115, 184, 184, 184,
+ 161, 156, 118, 184, 184, 184, 184, 184, 184, 152,
+ 184, 184, 184, 184, 184, 87, 40, 43, 45, 44,
+ 41, 47, 46, 48, 42, 184, 184, 184, 184, 167,
+ 143, 184, 184, 154, 184, 184, 184, 36, 113, 27,
+
+ 180, 23, 155, 86, 184, 165, 18, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 20, 35, 184, 184, 184, 184, 184,
+ 184, 119, 92, 98, 184, 184, 184, 184, 184, 89,
+ 91, 3, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 148, 184, 184, 184, 184, 184, 8,
+ 184, 184, 10, 184, 184, 184, 184, 184, 184, 21,
+ 106, 12, 157, 120, 93, 100, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 153,
+ 184, 184, 184, 104, 110, 107, 184, 184, 184, 184,
+
+ 184, 184, 184, 149, 121, 94, 99, 184, 184, 164,
+ 184, 108, 184, 184, 184, 184, 6, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 103, 158, 1, 184,
+ 184, 184, 184, 184, 184, 182, 184, 116, 5, 177,
+ 61, 64, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 105, 184, 184, 184, 184,
+ 184, 184, 101, 184, 184, 184, 184, 184, 134, 69,
+ 70, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 114, 184, 184, 184, 102,
+ 136, 74, 75, 184, 184, 184, 184, 109, 184, 184,
+
+ 184, 184, 184, 184, 184, 129, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 68, 184, 184,
+ 184, 184, 62, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 130, 122, 184,
+ 95, 184, 184, 184, 73, 184, 184, 71, 184, 184,
+ 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 131, 184, 184, 78, 184, 184, 76, 184,
+ 184, 123, 96, 184, 125, 184, 126, 184, 184, 184,
+ 184, 184, 184, 111, 184, 184, 184, 184, 66, 184,
+ 65, 140, 184, 184, 124, 97, 184, 184, 184, 184,
+
+ 184, 184, 184, 184, 184, 184, 184, 184, 138, 141,
+ 184, 132, 184, 67, 184, 184, 184, 184, 184, 184,
+ 184, 184, 139, 142, 184, 184, 184, 184, 135, 72,
+ 184, 184, 184, 178, 184, 184, 184, 79, 184, 184,
+ 137, 77, 184, 184, 184, 184, 184, 184, 184, 184,
+ 184, 83, 184, 184, 184, 184, 184, 184, 184, 184,
+ 84, 184, 184, 184, 184, 80, 184, 85, 88, 184,
+ 127, 128, 90, 184, 184, 184, 63, 184, 184, 184,
+ 179, 184, 133, 81, 184, 184, 184, 184, 82, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 1, 1, 1, 5, 6, 1, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 1, 31, 32, 33, 34, 35, 36,
+ 37, 37, 37, 37, 37, 37, 38, 37, 39, 37,
+ 37, 40, 41, 42, 43, 37, 37, 44, 45, 37,
+ 46, 1, 47, 48, 49, 1, 50, 51, 52, 53,
+
+ 54, 55, 56, 57, 58, 37, 59, 60, 61, 62,
+ 63, 64, 37, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[78] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 2, 3, 1, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 1, 1, 1, 1, 1, 1,
+ 5, 5, 5, 5, 6, 7, 8, 8, 8, 8,
+ 8, 8, 9, 8, 8, 1, 1, 1, 8, 5,
+ 5, 5, 5, 6, 7, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 8, 8,
+ 8, 8, 8, 1, 1, 1, 1
+ } ;
+
+static const flex_int16_t yy_base[900] =
+ { 0,
+ 0, 0, 77, 0, 1094, 1095, 1095, 1095, 1065, 127,
+ 151, 1095, 1095, 1064, 148, 1095, 147, 145, 1063, 167,
+ 158, 1061, 1095, 167, 1061, 145, 1095, 0, 1095, 1095,
+ 149, 1039, 147, 135, 155, 162, 146, 174, 1024, 172,
+ 178, 179, 169, 196, 1018, 198, 1031, 200, 197, 213,
+ 202, 113, 1016, 1095, 153, 1095, 1095, 1095, 1095, 1095,
+ 0, 1095, 1095, 1095, 1095, 1095, 1095, 1095, 1095, 1095,
+ 1095, 237, 1095, 241, 237, 271, 243, 1095, 0, 1095,
+ 1095, 1095, 1055, 1095, 1095, 1095, 1054, 0, 1095, 1095,
+ 1015, 1013, 1018, 197, 1015, 1023, 1021, 1021, 1008, 1011,
+
+ 1022, 226, 1016, 1004, 1001, 1014, 1001, 998, 998, 1004,
+ 136, 235, 998, 1008, 994, 1000, 1003, 1004, 0, 996,
+ 1006, 230, 1005, 986, 999, 980, 216, 984, 997, 988,
+ 243, 981, 237, 993, 995, 250, 984, 259, 971, 980,
+ 253, 259, 984, 980, 982, 971, 974, 250, 255, 269,
+ 983, 971, 983, 266, 976, 975, 963, 1095, 1095, 0,
+ 318, 1095, 296, 323, 1095, 1095, 325, 324, 206, 1095,
+ 1095, 981, 972, 0, 968, 963, 967, 976, 970, 972,
+ 298, 956, 956, 967, 959, 271, 969, 966, 966, 964,
+ 961, 953, 959, 946, 944, 956, 942, 958, 0, 955,
+
+ 943, 950, 947, 951, 952, 945, 942, 931, 930, 943,
+ 946, 934, 945, 941, 929, 935, 926, 336, 931, 934,
+ 925, 932, 921, 925, 916, 930, 929, 920, 926, 294,
+ 910, 913, 911, 910, 920, 910, 905, 903, 905, 915,
+ 901, 903, 900, 911, 910, 913, 895, 301, 903, 899,
+ 897, 906, 885, 349, 903, 905, 894, 886, 919, 354,
+ 370, 368, 383, 1095, 1095, 890, 881, 891, 890, 0,
+ 888, 892, 379, 0, 0, 880, 878, 878, 879, 874,
+ 882, 871, 888, 877, 382, 0, 0, 871, 881, 880,
+ 880, 0, 865, 385, 0, 0, 867, 390, 874, 875,
+
+ 866, 860, 859, 860, 859, 859, 337, 393, 854, 0,
+ 0, 850, 849, 848, 850, 851, 856, 850, 846, 859,
+ 854, 854, 852, 851, 845, 839, 841, 840, 844, 849,
+ 835, 838, 833, 841, 846, 834, 831, 843, 834, 0,
+ 0, 840, 836, 0, 828, 828, 833, 824, 831, 396,
+ 828, 0, 0, 0, 0, 818, 830, 829, 816, 817,
+ 826, 827, 827, 0, 812, 0, 0, 0, 813, 0,
+ 821, 812, 0, 811, 812, 806, 816, 0, 0, 0,
+ 807, 0, 803, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 813, 400, 812, 0, 0, 810, 806, 803,
+
+ 847, 846, 0, 0, 0, 793, 403, 409, 412, 798,
+ 794, 799, 790, 788, 801, 786, 0, 786, 799, 788,
+ 784, 790, 785, 792, 792, 0, 789, 786, 790, 774,
+ 772, 775, 781, 787, 782, 781, 769, 0, 771, 772,
+ 0, 0, 0, 0, 769, 772, 0, 766, 776, 767,
+ 0, 777, 757, 0, 766, 761, 0, 754, 754, 767,
+ 0, 769, 0, 418, 784, 783, 782, 747, 746, 0,
+ 763, 762, 757, 794, 785, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 744, 757, 744, 741, 0,
+ 0, 746, 745, 0, 742, 749, 748, 0, 734, 0,
+
+ 0, 0, 0, 0, 731, 0, 0, 730, 741, 423,
+ 734, 740, 739, 736, 731, 728, 748, 734, 719, 719,
+ 732, 717, 729, 0, 0, 722, 747, 746, 745, 710,
+ 709, 406, 411, 0, 721, 724, 722, 711, 707, 722,
+ 0, 0, 718, 715, 714, 704, 703, 693, 710, 696,
+ 427, 704, 707, 0, 726, 725, 724, 689, 688, 0,
+ 702, 689, 0, 699, 692, 684, 685, 691, 694, 0,
+ 0, 0, 0, 716, 715, 0, 690, 693, 678, 685,
+ 676, 683, 684, 684, 683, 669, 447, 680, 680, 0,
+ 681, 670, 669, 0, 0, 0, 696, 695, 694, 659,
+
+ 658, 654, 662, 0, 692, 691, 0, 666, 669, 0,
+ 450, 0, 647, 668, 682, 654, 0, 650, 649, 658,
+ 658, 646, 660, 644, 658, 653, 0, 0, 0, 672,
+ 671, 670, 635, 634, 633, 0, 633, 0, 0, 417,
+ 446, 659, 643, 646, 629, 641, 629, 628, 637, 637,
+ 656, 655, 654, 619, 618, 0, 623, 613, 616, 617,
+ 616, 626, 0, 629, 625, 627, 623, 610, 643, 438,
+ 0, 618, 621, 611, 612, 604, 611, 602, 625, 611,
+ 607, 609, 607, 607, 606, 0, 594, 593, 603, 0,
+ 625, 450, 0, 600, 603, 600, 585, 0, 601, 600,
+
+ 584, 576, 584, 574, 582, 0, 579, 578, 601, 587,
+ 585, 585, 578, 568, 571, 585, 569, 602, 580, 581,
+ 578, 575, 587, 562, 576, 575, 559, 558, 557, 580,
+ 566, 564, 564, 567, 562, 543, 542, 0, 572, 542,
+ 570, 540, 544, 543, 576, 554, 551, 0, 555, 548,
+ 549, 539, 538, 519, 502, 515, 499, 162, 258, 258,
+ 257, 290, 0, 298, 316, 363, 353, 369, 0, 359,
+ 381, 0, 0, 392, 0, 396, 0, 404, 407, 396,
+ 403, 406, 407, 0, 401, 411, 403, 420, 448, 428,
+ 0, 0, 442, 443, 0, 0, 444, 445, 431, 430,
+
+ 433, 446, 438, 451, 452, 431, 432, 440, 0, 0,
+ 456, 466, 438, 468, 460, 454, 442, 460, 454, 443,
+ 444, 452, 0, 0, 483, 469, 467, 468, 0, 0,
+ 472, 461, 467, 0, 468, 454, 477, 0, 465, 490,
+ 0, 0, 480, 487, 472, 470, 471, 463, 480, 487,
+ 488, 0, 486, 470, 506, 470, 501, 527, 475, 476,
+ 0, 493, 495, 496, 487, 0, 510, 0, 0, 518,
+ 0, 0, 0, 490, 491, 485, 0, 511, 487, 488,
+ 0, 542, 0, 0, 515, 526, 518, 521, 0, 1095,
+ 561, 567, 573, 579, 583, 589, 590, 596, 599
+
+ } ;
+
+static const flex_int16_t yy_def[900] =
+ { 0,
+ 890, 1, 890, 3, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 891, 890, 890, 890, 890, 890, 890, 892, 890, 890,
+ 890, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 890, 890, 890, 890, 890, 890, 890,
+ 893, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 894, 890, 895, 20, 891, 896, 890, 897, 890,
+ 890, 890, 890, 890, 890, 890, 890, 892, 890, 890,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 890, 890, 893,
+ 898, 890, 895, 899, 890, 890, 890, 896, 897, 890,
+ 890, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 890,
+ 898, 890, 899, 890, 890, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
+ 892, 892, 892, 892, 892, 892, 892, 892, 892, 0,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890
+
+ } ;
+
+static const flex_int16_t yy_nxt[1173] =
+ { 0,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 22, 23, 24, 25, 26, 27,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 28, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 28, 53, 28, 54, 55, 56, 57, 58, 59, 60,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 61, 58, 58, 58, 61, 61, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 58, 58, 58, 58, 63, 64, 65, 68, 70, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 155,
+ 74, 81, 86, 87, 71, 69, 89, 156, 66, 74,
+ 158, 75, 75, 75, 75, 75, 75, 75, 75, 76,
+ 76, 82, 77, 83, 84, 195, 90, 95, 92, 96,
+
+ 78, 77, 97, 98, 99, 107, 196, 108, 100, 78,
+ 79, 77, 93, 94, 101, 103, 109, 102, 128, 104,
+ 77, 116, 129, 110, 105, 78, 792, 159, 126, 117,
+ 106, 111, 119, 112, 78, 120, 113, 79, 121, 122,
+ 118, 127, 114, 123, 124, 130, 125, 133, 265, 137,
+ 144, 152, 167, 145, 167, 153, 138, 139, 131, 175,
+ 140, 146, 134, 176, 154, 135, 141, 142, 147, 143,
+ 148, 161, 162, 265, 149, 164, 165, 216, 150, 166,
+ 890, 151, 184, 74, 197, 217, 185, 186, 224, 207,
+ 161, 162, 208, 209, 164, 165, 210, 198, 211, 229,
+
+ 221, 225, 237, 226, 166, 77, 222, 890, 233, 239,
+ 246, 247, 248, 78, 793, 230, 231, 238, 250, 794,
+ 249, 234, 240, 255, 77, 256, 251, 260, 795, 260,
+ 164, 165, 262, 890, 262, 890, 280, 281, 78, 168,
+ 168, 168, 168, 168, 168, 168, 168, 168, 168, 164,
+ 165, 274, 312, 313, 314, 345, 326, 401, 402, 264,
+ 327, 796, 797, 346, 275, 352, 353, 354, 261, 261,
+ 261, 261, 261, 261, 261, 261, 261, 261, 264, 890,
+ 798, 890, 263, 263, 263, 263, 263, 263, 263, 263,
+ 263, 263, 890, 799, 890, 366, 367, 368, 378, 379,
+
+ 380, 386, 387, 388, 800, 162, 390, 391, 392, 403,
+ 404, 405, 442, 443, 444, 465, 466, 467, 165, 477,
+ 478, 479, 801, 802, 162, 480, 481, 482, 483, 484,
+ 485, 468, 469, 527, 528, 529, 579, 165, 555, 556,
+ 557, 581, 597, 598, 599, 803, 580, 676, 804, 530,
+ 531, 582, 805, 806, 558, 559, 807, 677, 600, 601,
+ 808, 602, 630, 631, 632, 651, 652, 653, 708, 809,
+ 810, 811, 812, 813, 814, 709, 678, 710, 633, 634,
+ 729, 654, 655, 679, 815, 680, 681, 730, 816, 731,
+ 817, 818, 819, 820, 821, 822, 823, 824, 825, 826,
+
+ 827, 828, 829, 830, 831, 832, 833, 834, 835, 836,
+ 837, 838, 839, 840, 841, 842, 843, 844, 845, 846,
+ 847, 848, 849, 850, 851, 852, 853, 854, 855, 856,
+ 857, 858, 859, 860, 861, 862, 863, 864, 865, 866,
+ 867, 868, 869, 870, 871, 872, 873, 874, 875, 876,
+ 877, 878, 879, 880, 881, 882, 883, 884, 885, 886,
+ 887, 888, 889, 76, 76, 791, 76, 790, 789, 76,
+ 88, 88, 88, 88, 88, 88, 160, 160, 160, 160,
+ 160, 160, 72, 788, 72, 72, 163, 787, 163, 163,
+ 168, 786, 168, 169, 169, 169, 169, 261, 785, 261,
+
+ 263, 784, 263, 783, 782, 781, 780, 779, 778, 777,
+ 776, 775, 774, 773, 772, 771, 770, 769, 768, 767,
+ 766, 765, 764, 763, 762, 761, 760, 759, 758, 757,
+ 756, 755, 754, 753, 752, 751, 750, 749, 748, 747,
+ 746, 745, 744, 743, 742, 741, 740, 739, 738, 737,
+ 736, 735, 734, 733, 732, 728, 727, 726, 725, 724,
+ 723, 722, 721, 720, 719, 718, 717, 716, 715, 714,
+ 713, 712, 711, 707, 706, 705, 704, 703, 702, 701,
+ 700, 699, 698, 697, 696, 695, 694, 693, 692, 691,
+ 690, 689, 688, 687, 686, 685, 684, 683, 682, 675,
+
+ 674, 673, 672, 671, 670, 669, 668, 667, 666, 665,
+ 664, 663, 662, 661, 660, 659, 658, 657, 656, 650,
+ 649, 648, 647, 646, 645, 644, 643, 642, 641, 640,
+ 639, 638, 637, 636, 635, 629, 628, 627, 626, 625,
+ 624, 623, 622, 621, 620, 619, 618, 617, 616, 615,
+ 614, 613, 612, 611, 610, 609, 608, 607, 606, 605,
+ 604, 603, 596, 595, 594, 593, 592, 591, 590, 589,
+ 588, 587, 586, 585, 584, 583, 578, 577, 576, 575,
+ 574, 573, 572, 571, 570, 569, 568, 567, 566, 565,
+ 564, 563, 562, 561, 560, 554, 553, 552, 551, 550,
+
+ 549, 548, 547, 546, 545, 544, 543, 542, 541, 540,
+ 539, 538, 537, 536, 535, 534, 533, 532, 526, 525,
+ 524, 523, 522, 521, 520, 519, 518, 517, 516, 515,
+ 514, 513, 512, 511, 510, 509, 508, 507, 506, 505,
+ 504, 503, 502, 501, 500, 499, 498, 497, 496, 495,
+ 494, 493, 492, 491, 490, 489, 488, 487, 486, 476,
+ 475, 474, 473, 472, 471, 470, 464, 463, 462, 461,
+ 460, 459, 458, 457, 456, 455, 454, 453, 452, 451,
+ 450, 449, 448, 447, 446, 445, 441, 440, 439, 438,
+ 437, 436, 435, 434, 433, 432, 431, 430, 429, 428,
+
+ 427, 426, 425, 424, 423, 422, 421, 420, 419, 418,
+ 417, 416, 415, 414, 413, 412, 411, 410, 409, 408,
+ 407, 406, 400, 399, 398, 397, 396, 395, 394, 393,
+ 389, 385, 384, 383, 382, 381, 377, 376, 375, 374,
+ 373, 372, 371, 370, 369, 365, 364, 363, 362, 361,
+ 360, 359, 358, 357, 356, 355, 351, 350, 349, 348,
+ 347, 344, 343, 342, 341, 340, 339, 338, 337, 336,
+ 335, 334, 333, 332, 331, 330, 329, 328, 325, 324,
+ 323, 322, 321, 320, 319, 318, 317, 316, 315, 311,
+ 310, 309, 308, 307, 306, 305, 304, 303, 302, 301,
+
+ 300, 299, 298, 297, 296, 295, 294, 293, 292, 291,
+ 290, 289, 288, 287, 286, 285, 284, 283, 282, 279,
+ 278, 277, 276, 273, 272, 271, 270, 269, 268, 267,
+ 266, 259, 258, 257, 254, 253, 252, 245, 244, 243,
+ 242, 241, 236, 235, 232, 228, 227, 223, 220, 219,
+ 218, 215, 214, 213, 212, 206, 205, 204, 203, 202,
+ 201, 200, 199, 194, 193, 192, 191, 190, 189, 188,
+ 187, 183, 182, 181, 180, 179, 178, 177, 174, 173,
+ 172, 171, 170, 157, 136, 132, 115, 91, 85, 80,
+ 73, 67, 62, 890, 5, 890, 890, 890, 890, 890,
+
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890
+ } ;
+
+static const flex_int16_t yy_chk[1173] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 10, 10, 11, 15, 17, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 52,
+ 21, 24, 26, 26, 17, 15, 31, 52, 11, 20,
+ 55, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 24, 21, 24, 24, 111, 31, 34, 33, 34,
+
+ 21, 20, 34, 34, 35, 37, 111, 37, 35, 20,
+ 20, 21, 33, 33, 35, 36, 37, 35, 43, 36,
+ 20, 40, 43, 38, 36, 21, 758, 55, 42, 40,
+ 36, 38, 41, 38, 20, 41, 38, 20, 41, 41,
+ 40, 42, 38, 41, 41, 44, 41, 46, 169, 48,
+ 49, 51, 77, 49, 77, 51, 48, 48, 44, 94,
+ 48, 49, 46, 94, 51, 46, 48, 48, 49, 48,
+ 50, 72, 72, 169, 50, 74, 74, 127, 50, 75,
+ 75, 50, 102, 76, 112, 127, 102, 102, 133, 122,
+ 72, 72, 122, 122, 74, 74, 122, 112, 122, 136,
+
+ 131, 133, 141, 133, 75, 76, 131, 75, 138, 142,
+ 148, 148, 149, 76, 759, 136, 136, 141, 150, 760,
+ 149, 138, 142, 154, 76, 154, 150, 161, 761, 161,
+ 163, 163, 164, 168, 164, 168, 186, 186, 76, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 163,
+ 163, 181, 218, 218, 218, 248, 230, 307, 307, 168,
+ 230, 762, 764, 248, 181, 254, 254, 254, 260, 260,
+ 260, 260, 260, 260, 260, 260, 260, 260, 168, 261,
+ 765, 261, 262, 262, 262, 262, 262, 262, 262, 262,
+ 262, 262, 263, 766, 263, 273, 273, 273, 285, 285,
+
+ 285, 294, 294, 294, 767, 261, 298, 298, 298, 308,
+ 308, 308, 350, 350, 350, 394, 394, 394, 263, 407,
+ 407, 407, 768, 770, 261, 408, 408, 408, 409, 409,
+ 409, 394, 394, 464, 464, 464, 532, 263, 510, 510,
+ 510, 533, 551, 551, 551, 771, 532, 640, 774, 464,
+ 464, 533, 776, 778, 510, 510, 779, 640, 551, 551,
+ 780, 551, 587, 587, 587, 611, 611, 611, 670, 781,
+ 782, 783, 785, 786, 787, 670, 641, 670, 587, 587,
+ 692, 611, 611, 641, 788, 641, 641, 692, 789, 692,
+ 790, 793, 794, 797, 798, 799, 800, 801, 802, 803,
+
+ 804, 805, 806, 807, 808, 811, 812, 813, 814, 815,
+ 816, 817, 818, 819, 820, 821, 822, 825, 826, 827,
+ 828, 831, 832, 833, 835, 836, 837, 839, 840, 843,
+ 844, 845, 846, 847, 848, 849, 850, 851, 853, 854,
+ 855, 856, 857, 858, 859, 860, 862, 863, 864, 865,
+ 867, 870, 874, 875, 876, 878, 879, 880, 882, 885,
+ 886, 887, 888, 891, 891, 757, 891, 756, 755, 891,
+ 892, 892, 892, 892, 892, 892, 893, 893, 893, 893,
+ 893, 893, 894, 754, 894, 894, 895, 753, 895, 895,
+ 896, 752, 896, 897, 897, 897, 897, 898, 751, 898,
+
+ 899, 750, 899, 749, 747, 746, 745, 744, 743, 742,
+ 741, 740, 739, 737, 736, 735, 734, 733, 732, 731,
+ 730, 729, 728, 727, 726, 725, 724, 723, 722, 721,
+ 720, 719, 718, 717, 716, 715, 714, 713, 712, 711,
+ 710, 709, 708, 707, 705, 704, 703, 702, 701, 700,
+ 699, 697, 696, 695, 694, 691, 689, 688, 687, 685,
+ 684, 683, 682, 681, 680, 679, 678, 677, 676, 675,
+ 674, 673, 672, 669, 668, 667, 666, 665, 664, 662,
+ 661, 660, 659, 658, 657, 655, 654, 653, 652, 651,
+ 650, 649, 648, 647, 646, 645, 644, 643, 642, 637,
+
+ 635, 634, 633, 632, 631, 630, 626, 625, 624, 623,
+ 622, 621, 620, 619, 618, 616, 615, 614, 613, 609,
+ 608, 606, 605, 603, 602, 601, 600, 599, 598, 597,
+ 593, 592, 591, 589, 588, 586, 585, 584, 583, 582,
+ 581, 580, 579, 578, 577, 575, 574, 569, 568, 567,
+ 566, 565, 564, 562, 561, 559, 558, 557, 556, 555,
+ 553, 552, 550, 549, 548, 547, 546, 545, 544, 543,
+ 540, 539, 538, 537, 536, 535, 531, 530, 529, 528,
+ 527, 526, 523, 522, 521, 520, 519, 518, 517, 516,
+ 515, 514, 513, 512, 511, 509, 508, 505, 499, 497,
+
+ 496, 495, 493, 492, 489, 488, 487, 486, 475, 474,
+ 473, 472, 471, 469, 468, 467, 466, 465, 462, 460,
+ 459, 458, 456, 455, 453, 452, 450, 449, 448, 446,
+ 445, 440, 439, 437, 436, 435, 434, 433, 432, 431,
+ 430, 429, 428, 427, 425, 424, 423, 422, 421, 420,
+ 419, 418, 416, 415, 414, 413, 412, 411, 410, 406,
+ 402, 401, 400, 399, 398, 395, 393, 383, 381, 377,
+ 376, 375, 374, 372, 371, 369, 365, 363, 362, 361,
+ 360, 359, 358, 357, 356, 351, 349, 348, 347, 346,
+ 345, 343, 342, 339, 338, 337, 336, 335, 334, 333,
+
+ 332, 331, 330, 329, 328, 327, 326, 325, 324, 323,
+ 322, 321, 320, 319, 318, 317, 316, 315, 314, 313,
+ 312, 309, 306, 305, 304, 303, 302, 301, 300, 299,
+ 297, 293, 291, 290, 289, 288, 284, 283, 282, 281,
+ 280, 279, 278, 277, 276, 272, 271, 269, 268, 267,
+ 266, 259, 258, 257, 256, 255, 253, 252, 251, 250,
+ 249, 247, 246, 245, 244, 243, 242, 241, 240, 239,
+ 238, 237, 236, 235, 234, 233, 232, 231, 229, 228,
+ 227, 226, 225, 224, 223, 222, 221, 220, 219, 217,
+ 216, 215, 214, 213, 212, 211, 210, 209, 208, 207,
+
+ 206, 205, 204, 203, 202, 201, 200, 198, 197, 196,
+ 195, 194, 193, 192, 191, 190, 189, 188, 187, 185,
+ 184, 183, 182, 180, 179, 178, 177, 176, 175, 173,
+ 172, 157, 156, 155, 153, 152, 151, 147, 146, 145,
+ 144, 143, 140, 139, 137, 135, 134, 132, 130, 129,
+ 128, 126, 125, 124, 123, 121, 120, 118, 117, 116,
+ 115, 114, 113, 110, 109, 108, 107, 106, 105, 104,
+ 103, 101, 100, 99, 98, 97, 96, 95, 93, 92,
+ 91, 87, 83, 53, 47, 45, 39, 32, 25, 22,
+ 19, 14, 9, 5, 890, 890, 890, 890, 890, 890,
+
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ 890, 890
+ } ;
+
+
+/* Table of booleans, true if rule could match eol. */
+static const flex_int32_t yy_rule_can_match_eol[248] =
+ { 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/*
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+#include "compiler/preprocessor/Token.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/glslang.h"
+#include "compiler/translator/length_limits.h"
+#include "compiler/translator/util.h"
+
+using namespace sh;
+
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
+#endif
+
+#define YY_NO_INPUT
+#define YY_USER_ACTION \
+ yylloc->first_file = yylloc->last_file = yycolumn; \
+ yylloc->first_line = yylloc->last_line = yylineno;
+
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
+static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
+static int ES2_ident_ES3_keyword(TParseContext *context, int token);
+static int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token);
+static int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token);
+static int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token);
+static int ES2_extension_ES3_keyword_else_reserved(TParseContext *context, TExtension extension, int token);
+static int ES3_extension_keyword_else_ident(TParseContext *context, TExtension extension, int token);
+static int ES2_ident_ES3_reserved_ES3_1_extension_keyword(TParseContext *context, TExtension extension, int token);
+static int ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(TParseContext *context, TExtension extension, int token);
+static int uint_constant(TParseContext *context);
+static int int_constant(TParseContext *context);
+static int float_constant(yyscan_t yyscanner);
+static int floatsuffix_check(TParseContext* context);
+static int yuvcscstandardext_constant(TParseContext *context);
+
+
+
+
+#define INITIAL 0
+#define FIELDS 1
+
+
+
+
+
+
+#define YY_EXTRA_TYPE TParseContext*
+
+
+
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+
+
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+
+
+ YYSTYPE * yylval_r;
+
+
+
+ YYLTYPE * yylloc_r;
+
+
+ }; /* end struct yyguts_t */
+
+
+
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+
+
+
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+
+
+ # define yylloc yyg->yylloc_r
+
+
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+
+
+int yyget_debug ( yyscan_t yyscanner );
+
+
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+
+
+char *yyget_text ( yyscan_t yyscanner );
+
+
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+
+
+
+int yyget_column ( yyscan_t yyscanner );
+
+
+
+
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+
+
+
+YYSTYPE * yyget_lval ( yyscan_t yyscanner );
+
+
+void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
+
+
+
+ YYLTYPE *yyget_lloc ( yyscan_t yyscanner );
+
+
+
+ void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner );
+
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+
+
+
+
+
+
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+
+
+/* end tables serialization structures and prototypes */
+
+
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern int yylex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+
+
+
+ yylval = yylval_param;
+
+
+
+ yylloc = yylloc_param;
+
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+
+
+ TParseContext* context = yyextra;
+
+
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 891 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 890 );
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{ return INVARIANT; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ return HIGH_PRECISION; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ return MEDIUM_PRECISION; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ return LOW_PRECISION; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ return PRECISION; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{ return ES2_keyword_ES3_reserved(context, ATTRIBUTE); }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ return CONST_QUAL; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ return UNIFORM; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ return ES2_and_ES3_ident_ES3_1_keyword(context, BUFFER); }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return ES2_keyword_ES3_reserved(context, VARYING); }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return BREAK; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return CONTINUE; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return DO; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return FOR; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return WHILE; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return IF; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return ELSE; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SWITCH); }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, CASE); }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, DEFAULT); }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, CENTROID); }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, FLAT); }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SMOOTH); }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ return IN_QUAL; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ return OUT_QUAL; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ return INOUT_QUAL; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ return ES2_and_ES3_ident_ES3_1_keyword(context, SHARED); }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ return FLOAT_TYPE; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ return INT_TYPE; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UINT_TYPE); }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ return VOID_TYPE; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ return BOOL_TYPE; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{ yylval->lex.b = true; return BOOLCONSTANT; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ yylval->lex.b = false; return BOOLCONSTANT; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ return DISCARD; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ return RETURN; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ return MATRIX2; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+{ return MATRIX3; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ return MATRIX4; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2); }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3); }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4); }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2x3); }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3x2); }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2x4); }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4x2); }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3x4); }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4x3); }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ return VEC2; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ return VEC3; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ return VEC4; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ return IVEC2; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ return IVEC3; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ return IVEC4; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+{ return BVEC2; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+{ return BVEC3; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{ return BVEC4; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC2); }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC3); }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC4); }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ return SAMPLER2D; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ return SAMPLERCUBE; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ return SAMPLER_EXTERNAL_OES; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ return ES2_extension_ES3_keyword_else_reserved(context, TExtension::OES_texture_3D, SAMPLER3D); }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ return SAMPLER2DRECT; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ return ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(context, TExtension::ANGLE_texture_multisample, SAMPLER2DMS); }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER2D); }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER3D); }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ return ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(context, TExtension::ANGLE_texture_multisample, ISAMPLER2DMS); }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER2D); }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER3D); }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLERCUBE); }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ return ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(context, TExtension::ANGLE_texture_multisample, USAMPLER2DMS); }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+{ return ES3_extension_keyword_else_ident(context, TExtension::EXT_YUV_target, SAMPLEREXTERNAL2DY2YEXT); }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_extension_keyword(context, TExtension::OES_texture_storage_multisample_2d_array, SAMPLER2DMSARRAY); }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_extension_keyword(context, TExtension::OES_texture_storage_multisample_2d_array, ISAMPLER2DMSARRAY); }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_extension_keyword(context, TExtension::OES_texture_storage_multisample_2d_array, USAMPLER2DMSARRAY); }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+{ return STRUCT; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, LAYOUT); }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+{ return ES3_extension_keyword_else_ident(context, TExtension::EXT_YUV_target, YUVCSCSTANDARDEXT); }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+{ return yuvcscstandardext_constant(context); }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+{ return yuvcscstandardext_constant(context); }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+{ return yuvcscstandardext_constant(context); }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2D); }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2D); }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2D); }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2DARRAY); }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2DARRAY); }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2DARRAY); }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE3D); }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE3D); }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE3D); }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGECUBE); }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGECUBE); }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, WRITEONLY); }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, COHERENT); }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, RESTRICT); }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+{ return ES2_and_ES3_reserved_ES3_1_keyword(context, VOLATILE); }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, ATOMICUINT); }
+ YY_BREAK
+/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
+case 110:
+case 111:
+case 112:
+case 113:
+case 114:
+case 115:
+case 116:
+case 117:
+case 118:
+case 119:
+case 120:
+case 121:
+case 122:
+case 123:
+case 124:
+case 125:
+case 126:
+case 127:
+case 128:
+case 129:
+case 130:
+case 131:
+case 132:
+case 133:
+case 134:
+case 135:
+case 136:
+case 137:
+case 138:
+case 139:
+case 140:
+case 141:
+case 142:
+YY_RULE_SETUP
+{
+ if (context->getShaderVersion() < 300) {
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+ }
+ return reserved_word(yyscanner);
+}
+ YY_BREAK
+/* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */
+case 143:
+YY_RULE_SETUP
+{
+ if (context->getShaderVersion() >= 300)
+ {
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+ }
+
+ return reserved_word(yyscanner);
+}
+ YY_BREAK
+/* Reserved keywords */
+case 144:
+case 145:
+case 146:
+case 147:
+case 148:
+case 149:
+case 150:
+case 151:
+case 152:
+case 153:
+case 154:
+case 155:
+case 156:
+case 157:
+case 158:
+case 159:
+case 160:
+case 161:
+case 162:
+case 163:
+case 164:
+case 165:
+case 166:
+case 167:
+case 168:
+case 169:
+case 170:
+case 171:
+case 172:
+case 173:
+case 174:
+case 175:
+case 176:
+case 177:
+case 178:
+case 179:
+case 180:
+case 181:
+case 182:
+case 183:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 184:
+YY_RULE_SETUP
+{
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+}
+ YY_BREAK
+case 185:
+YY_RULE_SETUP
+{ return int_constant(context); }
+ YY_BREAK
+case 186:
+YY_RULE_SETUP
+{ return int_constant(context); }
+ YY_BREAK
+case 187:
+YY_RULE_SETUP
+{ return int_constant(context); }
+ YY_BREAK
+case 188:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 189:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 190:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 191:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 192:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 193:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 194:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 195:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 196:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 197:
+YY_RULE_SETUP
+{ return ADD_ASSIGN; }
+ YY_BREAK
+case 198:
+YY_RULE_SETUP
+{ return SUB_ASSIGN; }
+ YY_BREAK
+case 199:
+YY_RULE_SETUP
+{ return MUL_ASSIGN; }
+ YY_BREAK
+case 200:
+YY_RULE_SETUP
+{ return DIV_ASSIGN; }
+ YY_BREAK
+case 201:
+YY_RULE_SETUP
+{ return MOD_ASSIGN; }
+ YY_BREAK
+case 202:
+YY_RULE_SETUP
+{ return LEFT_ASSIGN; }
+ YY_BREAK
+case 203:
+YY_RULE_SETUP
+{ return RIGHT_ASSIGN; }
+ YY_BREAK
+case 204:
+YY_RULE_SETUP
+{ return AND_ASSIGN; }
+ YY_BREAK
+case 205:
+YY_RULE_SETUP
+{ return XOR_ASSIGN; }
+ YY_BREAK
+case 206:
+YY_RULE_SETUP
+{ return OR_ASSIGN; }
+ YY_BREAK
+case 207:
+YY_RULE_SETUP
+{ return INC_OP; }
+ YY_BREAK
+case 208:
+YY_RULE_SETUP
+{ return DEC_OP; }
+ YY_BREAK
+case 209:
+YY_RULE_SETUP
+{ return AND_OP; }
+ YY_BREAK
+case 210:
+YY_RULE_SETUP
+{ return OR_OP; }
+ YY_BREAK
+case 211:
+YY_RULE_SETUP
+{ return XOR_OP; }
+ YY_BREAK
+case 212:
+YY_RULE_SETUP
+{ return LE_OP; }
+ YY_BREAK
+case 213:
+YY_RULE_SETUP
+{ return GE_OP; }
+ YY_BREAK
+case 214:
+YY_RULE_SETUP
+{ return EQ_OP; }
+ YY_BREAK
+case 215:
+YY_RULE_SETUP
+{ return NE_OP; }
+ YY_BREAK
+case 216:
+YY_RULE_SETUP
+{ return LEFT_OP; }
+ YY_BREAK
+case 217:
+YY_RULE_SETUP
+{ return RIGHT_OP; }
+ YY_BREAK
+case 218:
+YY_RULE_SETUP
+{ return SEMICOLON; }
+ YY_BREAK
+case 219:
+YY_RULE_SETUP
+{ return LEFT_BRACE; }
+ YY_BREAK
+case 220:
+YY_RULE_SETUP
+{ return RIGHT_BRACE; }
+ YY_BREAK
+case 221:
+YY_RULE_SETUP
+{ return COMMA; }
+ YY_BREAK
+case 222:
+YY_RULE_SETUP
+{ return COLON; }
+ YY_BREAK
+case 223:
+YY_RULE_SETUP
+{ return EQUAL; }
+ YY_BREAK
+case 224:
+YY_RULE_SETUP
+{ return LEFT_PAREN; }
+ YY_BREAK
+case 225:
+YY_RULE_SETUP
+{ return RIGHT_PAREN; }
+ YY_BREAK
+case 226:
+YY_RULE_SETUP
+{ return LEFT_BRACKET; }
+ YY_BREAK
+case 227:
+YY_RULE_SETUP
+{ return RIGHT_BRACKET; }
+ YY_BREAK
+case 228:
+YY_RULE_SETUP
+{ BEGIN(FIELDS); return DOT; }
+ YY_BREAK
+case 229:
+YY_RULE_SETUP
+{ return BANG; }
+ YY_BREAK
+case 230:
+YY_RULE_SETUP
+{ return DASH; }
+ YY_BREAK
+case 231:
+YY_RULE_SETUP
+{ return TILDE; }
+ YY_BREAK
+case 232:
+YY_RULE_SETUP
+{ return PLUS; }
+ YY_BREAK
+case 233:
+YY_RULE_SETUP
+{ return STAR; }
+ YY_BREAK
+case 234:
+YY_RULE_SETUP
+{ return SLASH; }
+ YY_BREAK
+case 235:
+YY_RULE_SETUP
+{ return PERCENT; }
+ YY_BREAK
+case 236:
+YY_RULE_SETUP
+{ return LEFT_ANGLE; }
+ YY_BREAK
+case 237:
+YY_RULE_SETUP
+{ return RIGHT_ANGLE; }
+ YY_BREAK
+case 238:
+YY_RULE_SETUP
+{ return VERTICAL_BAR; }
+ YY_BREAK
+case 239:
+YY_RULE_SETUP
+{ return CARET; }
+ YY_BREAK
+case 240:
+YY_RULE_SETUP
+{ return AMPERSAND; }
+ YY_BREAK
+case 241:
+YY_RULE_SETUP
+{ return QUESTION; }
+ YY_BREAK
+case 242:
+YY_RULE_SETUP
+{
+ BEGIN(INITIAL);
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return FIELD_SELECTION;
+}
+ YY_BREAK
+case 243:
+YY_RULE_SETUP
+{}
+ YY_BREAK
+case 244:
+YY_RULE_SETUP
+{
+ yyextra->error(*yylloc, "Illegal character at fieldname start", yytext);
+ return 0;
+}
+ YY_BREAK
+case 245:
+/* rule 245 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(FIELDS):
+{ yyterminate(); }
+ YY_BREAK
+case 246:
+YY_RULE_SETUP
+{ assert(false); return 0; }
+ YY_BREAK
+case 247:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+
+
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ size_t result = 0;
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ result, num_to_read );
+ yyg->yy_n_chars = static_cast<int>(result);
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 891 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 891 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 890);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ if ( c == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+
+
+ b->yy_is_interactive = 0;
+
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+
+
+
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+
+
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+
+
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+
+
+
+
+
+
+
+
+
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+
+
+/* Accessor methods (get/set functions) to struct members. */
+
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+
+
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+
+
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+
+
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+
+
+
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+
+
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+
+/* Accessor methods for yylval and yylloc */
+
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+
+
+void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+
+
+
+YYLTYPE *yyget_lloc (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylloc;
+}
+
+
+
+void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylloc = yylloc_param;
+}
+
+
+
+
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+
+
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+
+
+
+
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+
+
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+
+
+/*
+ * Internal utility routines.
+ */
+
+
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+
+#define YYTABLES_NAME "yytables"
+
+
+
+
+
+
+
+
+yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
+ angle::pp::Token token;
+ yyget_extra(yyscanner)->getPreprocessor().lex(&token);
+ yy_size_t len = token.type == angle::pp::Token::LAST ? 0 : token.text.size();
+ if (len < max_size)
+ memcpy(buf, token.text.c_str(), len);
+ yyset_column(token.location.file, yyscanner);
+ yyset_lineno(token.location.line, yyscanner);
+
+ if (len >= max_size)
+ YY_FATAL_ERROR("Input buffer overflow");
+ else if (len > 0)
+ buf[len++] = ' ';
+ return len;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ // Note that the ImmutableString used here isn't static or pool allocated - but it's fine since yytext is valid for the duration of its use.
+ const TSymbol* symbol = yyextra->symbolTable.find(ImmutableString(yytext, yyleng), yyextra->getShaderVersion());
+ if (symbol && symbol->isStruct())
+ {
+ token = TYPE_NAME;
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(*yylloc, "Illegal use of reserved word", yytext);
+ return 0;
+}
+
+int ES2_reserved_ES3_keyword(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ if (context->getShaderVersion() < 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_keyword_ES3_reserved(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ if (context->getShaderVersion() >= 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ if (context->getShaderVersion() < 300)
+ {
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+ }
+ else if (context->getShaderVersion() == 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_ident_ES3_keyword(TParseContext *context, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name
+ if (context->getShaderVersion() < 300)
+ {
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ if (context->getShaderVersion() < 310)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // not a reserved word in GLSL ES 1.00 and GLSL ES 3.00, so could be used as an identifier/type name
+ if (context->getShaderVersion() < 310)
+ {
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_extension_ES3_keyword_else_reserved(TParseContext *context, TExtension extension, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // Available with extension or ES 3.00 and above, reserved otherwise
+ if (context->isExtensionEnabled(extension) || context->getShaderVersion() >= 300)
+ {
+ return token;
+ }
+
+ return reserved_word(yyscanner);
+}
+
+int ES3_extension_keyword_else_ident(TParseContext *context, TExtension extension, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // a reserved word in GLSL ES 3.00 with enabled extension, otherwise could be used as an identifier/type name
+ if (context->getShaderVersion() >= 300 && context->isExtensionEnabled(extension))
+ {
+ return token;
+ }
+
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+}
+
+int ES2_ident_ES3_reserved_ES3_1_extension_keyword(TParseContext *context, TExtension extension, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // a keyword in GLSL ES 3.10 with enabled extension
+ if (context->getShaderVersion() >= 310 && context->isExtensionEnabled(extension))
+ {
+ return token;
+ }
+ // a reserved word in GLSL ES 3.00+
+ if (context->getShaderVersion() >= 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ // Otherwise can be used as an identifier/type name
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+}
+
+int ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(TParseContext *context, TExtension extension, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // A keyword in GLSL ES 3.00 with enabled extension or in GLSL ES 3.10
+ if (context->getShaderVersion() >= 310 || (context->getShaderVersion() == 300 && context->isExtensionEnabled(extension)))
+ {
+ return token;
+ }
+
+ if(context->getShaderVersion() == 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+}
+
+int uint_constant(TParseContext *context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+
+ if (context->getShaderVersion() < 300)
+ {
+ context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext);
+ return 0;
+ }
+
+ if (!atoi_clamp(yytext, &(yylval->lex.u)))
+ yyextra->error(*yylloc, "Integer overflow", yytext);
+
+ return UINTCONSTANT;
+}
+
+int floatsuffix_check(TParseContext* context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+
+ if (context->getShaderVersion() < 300)
+ {
+ context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext);
+ return 0;
+ }
+
+ std::string text = yytext;
+ text.resize(text.size() - 1);
+ if (!strtof_clamp(text, &(yylval->lex.f)))
+ yyextra->warning(*yylloc, "Float overflow", yytext);
+
+ return(FLOATCONSTANT);
+}
+
+void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) {
+ context->error(*lloc, reason, yyget_text(scanner));
+}
+
+int int_constant(TParseContext *context) {
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+
+ unsigned int u;
+ if (!atoi_clamp(yytext, &u))
+ {
+ if (context->getShaderVersion() >= 300)
+ yyextra->error(*yylloc, "Integer overflow", yytext);
+ else
+ yyextra->warning(*yylloc, "Integer overflow", yytext);
+ }
+ yylval->lex.i = static_cast<int>(u);
+ return INTCONSTANT;
+}
+
+int float_constant(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ if (!strtof_clamp(yytext, &(yylval->lex.f)))
+ yyextra->warning(*yylloc, "Float overflow", yytext);
+ return FLOATCONSTANT;
+}
+
+int yuvcscstandardext_constant(TParseContext *context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
+
+ // a reserved word in GLSL ES 3.00 with enabled extension, otherwise could be used as an identifier/type name
+ if (context->getShaderVersion() >= 300 && context->isExtensionEnabled(TExtension::EXT_YUV_target))
+ {
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return YUVCSCSTANDARDEXTCONSTANT;
+ }
+
+ yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
+ return check_type(yyscanner);
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context, &scanner))
+ return 1;
+
+ context->setScanner(scanner);
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->getScanner();
+ if (scanner == NULL) return 0;
+
+ context->setScanner(NULL);
+ yylex_destroy(scanner);
+
+ return 0;
+}
+
+int glslang_scan(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL, context->getScanner());
+ yyset_column(0, context->getScanner());
+ yyset_lineno(1, context->getScanner());
+
+ // Initialize preprocessor.
+ angle::pp::Preprocessor *preprocessor = &context->getPreprocessor();
+
+ if (!preprocessor->init(count, string, length))
+ return 1;
+
+ // Define extension macros.
+ const TExtensionBehavior& extBehavior = context->extensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ preprocessor->predefineMacro(GetExtensionNameString(iter->first), 1);
+ }
+ if (context->getFragmentPrecisionHigh())
+ preprocessor->predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ preprocessor->setMaxTokenSize(sh::GetGlobalMaxTokenSize(context->getShaderSpec()));
+
+ return 0;
+}
+
diff --git a/gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp b/gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp
new file mode 100644
index 0000000000..bf4efe8cb7
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp
@@ -0,0 +1,5201 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "3.0.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 2
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Copy the first part of user declarations. */
+
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// clang-format off
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#pragma warning(disable: 4702)
+#endif
+
+#include "angle_gl.h"
+#include "compiler/translator/Declarator.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/ParseContext.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+using namespace sh;
+
+
+
+
+# ifndef YY_NULLPTR
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "glslang_tab.h". */
+#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+/* "%code requires" blocks. */
+
+
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+#define YYLTYPE_IS_TRIVIAL 1
+
+
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ UINT_TYPE = 268,
+ BREAK = 269,
+ CONTINUE = 270,
+ DO = 271,
+ ELSE = 272,
+ FOR = 273,
+ IF = 274,
+ DISCARD = 275,
+ RETURN = 276,
+ SWITCH = 277,
+ CASE = 278,
+ DEFAULT = 279,
+ BVEC2 = 280,
+ BVEC3 = 281,
+ BVEC4 = 282,
+ IVEC2 = 283,
+ IVEC3 = 284,
+ IVEC4 = 285,
+ VEC2 = 286,
+ VEC3 = 287,
+ VEC4 = 288,
+ UVEC2 = 289,
+ UVEC3 = 290,
+ UVEC4 = 291,
+ MATRIX2 = 292,
+ MATRIX3 = 293,
+ MATRIX4 = 294,
+ IN_QUAL = 295,
+ OUT_QUAL = 296,
+ INOUT_QUAL = 297,
+ UNIFORM = 298,
+ BUFFER = 299,
+ VARYING = 300,
+ MATRIX2x3 = 301,
+ MATRIX3x2 = 302,
+ MATRIX2x4 = 303,
+ MATRIX4x2 = 304,
+ MATRIX3x4 = 305,
+ MATRIX4x3 = 306,
+ CENTROID = 307,
+ FLAT = 308,
+ SMOOTH = 309,
+ READONLY = 310,
+ WRITEONLY = 311,
+ COHERENT = 312,
+ RESTRICT = 313,
+ VOLATILE = 314,
+ SHARED = 315,
+ STRUCT = 316,
+ VOID_TYPE = 317,
+ WHILE = 318,
+ SAMPLER2D = 319,
+ SAMPLERCUBE = 320,
+ SAMPLER_EXTERNAL_OES = 321,
+ SAMPLER2DRECT = 322,
+ SAMPLER2DARRAY = 323,
+ ISAMPLER2D = 324,
+ ISAMPLER3D = 325,
+ ISAMPLERCUBE = 326,
+ ISAMPLER2DARRAY = 327,
+ USAMPLER2D = 328,
+ USAMPLER3D = 329,
+ USAMPLERCUBE = 330,
+ USAMPLER2DARRAY = 331,
+ SAMPLER2DMS = 332,
+ ISAMPLER2DMS = 333,
+ USAMPLER2DMS = 334,
+ SAMPLER2DMSARRAY = 335,
+ ISAMPLER2DMSARRAY = 336,
+ USAMPLER2DMSARRAY = 337,
+ SAMPLER3D = 338,
+ SAMPLER3DRECT = 339,
+ SAMPLER2DSHADOW = 340,
+ SAMPLERCUBESHADOW = 341,
+ SAMPLER2DARRAYSHADOW = 342,
+ SAMPLEREXTERNAL2DY2YEXT = 343,
+ IMAGE2D = 344,
+ IIMAGE2D = 345,
+ UIMAGE2D = 346,
+ IMAGE3D = 347,
+ IIMAGE3D = 348,
+ UIMAGE3D = 349,
+ IMAGE2DARRAY = 350,
+ IIMAGE2DARRAY = 351,
+ UIMAGE2DARRAY = 352,
+ IMAGECUBE = 353,
+ IIMAGECUBE = 354,
+ UIMAGECUBE = 355,
+ ATOMICUINT = 356,
+ LAYOUT = 357,
+ YUVCSCSTANDARDEXT = 358,
+ YUVCSCSTANDARDEXTCONSTANT = 359,
+ IDENTIFIER = 360,
+ TYPE_NAME = 361,
+ FLOATCONSTANT = 362,
+ INTCONSTANT = 363,
+ UINTCONSTANT = 364,
+ BOOLCONSTANT = 365,
+ FIELD_SELECTION = 366,
+ LEFT_OP = 367,
+ RIGHT_OP = 368,
+ INC_OP = 369,
+ DEC_OP = 370,
+ LE_OP = 371,
+ GE_OP = 372,
+ EQ_OP = 373,
+ NE_OP = 374,
+ AND_OP = 375,
+ OR_OP = 376,
+ XOR_OP = 377,
+ MUL_ASSIGN = 378,
+ DIV_ASSIGN = 379,
+ ADD_ASSIGN = 380,
+ MOD_ASSIGN = 381,
+ LEFT_ASSIGN = 382,
+ RIGHT_ASSIGN = 383,
+ AND_ASSIGN = 384,
+ XOR_ASSIGN = 385,
+ OR_ASSIGN = 386,
+ SUB_ASSIGN = 387,
+ LEFT_PAREN = 388,
+ RIGHT_PAREN = 389,
+ LEFT_BRACKET = 390,
+ RIGHT_BRACKET = 391,
+ LEFT_BRACE = 392,
+ RIGHT_BRACE = 393,
+ DOT = 394,
+ COMMA = 395,
+ COLON = 396,
+ EQUAL = 397,
+ SEMICOLON = 398,
+ BANG = 399,
+ DASH = 400,
+ TILDE = 401,
+ PLUS = 402,
+ STAR = 403,
+ SLASH = 404,
+ PERCENT = 405,
+ LEFT_ANGLE = 406,
+ RIGHT_ANGLE = 407,
+ VERTICAL_BAR = 408,
+ CARET = 409,
+ AMPERSAND = 410,
+ QUESTION = 411
+ };
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+
+
+ struct {
+ union {
+ const char *string; // pool allocated.
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ const TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode *intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped *intermTypedNode;
+ TIntermAggregate *intermAggregate;
+ TIntermBlock *intermBlock;
+ TIntermDeclaration *intermDeclaration;
+ TIntermFunctionPrototype *intermFunctionPrototype;
+ TIntermSwitch *intermSwitch;
+ TIntermCase *intermCase;
+ };
+ union {
+ TVector<unsigned int> *arraySizes;
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction *function;
+ TFunctionLookup *functionLookup;
+ TParameter param;
+ TDeclarator *declarator;
+ TDeclaratorList *declaratorList;
+ TFieldList *fieldList;
+ TQualifierWrapperBase *qualifierWrapper;
+ TTypeQualifierBuilder *typeQualifierBuilder;
+ };
+ } interm;
+
+
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type. */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+int yyparse (TParseContext* context, void *scanner);
+
+#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+
+extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner);
+extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, const char* reason);
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) { \
+ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ } \
+ else { \
+ (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \
+ } \
+ } while (0)
+
+#define VERTEX_ONLY(S, L) do { \
+ if (context->getShaderType() != GL_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only", S); \
+ } \
+} while (0)
+
+#define COMPUTE_ONLY(S, L) do { \
+ if (context->getShaderType() != GL_COMPUTE_SHADER) { \
+ context->error(L, " supported in compute shaders only", S); \
+ } \
+} while (0)
+
+#define ES2_ONLY(S, L) do { \
+ if (context->getShaderVersion() != 100) { \
+ context->error(L, " supported in GLSL ES 1.00 only", S); \
+ } \
+} while (0)
+
+#define ES3_OR_NEWER(TOKEN, LINE, REASON) do { \
+ if (context->getShaderVersion() < 300) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.00 and above only", TOKEN); \
+ } \
+} while (0)
+
+#define ES3_1_ONLY(TOKEN, LINE, REASON) do { \
+ if (context->getShaderVersion() != 310) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.10 only", TOKEN); \
+ } \
+} while (0)
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__ \
+ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+# define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+# define _Noreturn __declspec (noreturn)
+# else
+# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 138
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 2973
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 157
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 95
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 300
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 426
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 411
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, without out-of-bounds checking. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 248, 248, 249, 252, 259, 262, 267, 272, 277,
+ 282, 291, 297, 300, 303, 306, 309, 312, 318, 325,
+ 331, 334, 342, 345, 351, 354, 360, 364, 371, 379,
+ 382, 385, 391, 394, 397, 400, 407, 408, 409, 410,
+ 418, 419, 422, 425, 432, 433, 436, 442, 443, 447,
+ 454, 455, 458, 461, 464, 470, 471, 474, 480, 481,
+ 488, 489, 496, 497, 504, 505, 511, 512, 518, 519,
+ 525, 526, 532, 533, 539, 540, 541, 542, 546, 547,
+ 548, 552, 556, 560, 564, 571, 574, 580, 587, 594,
+ 597, 600, 604, 608, 612, 616, 620, 627, 634, 637,
+ 644, 652, 669, 679, 682, 688, 692, 696, 700, 707,
+ 714, 717, 721, 725, 730, 737, 741, 745, 749, 754,
+ 761, 765, 771, 774, 780, 784, 791, 797, 801, 805,
+ 808, 811, 820, 825, 829, 832, 835, 838, 841, 845,
+ 848, 852, 855, 858, 861, 864, 867, 874, 881, 884,
+ 887, 893, 900, 903, 909, 912, 915, 918, 924, 927,
+ 934, 939, 946, 951, 962, 965, 968, 971, 974, 977,
+ 981, 985, 989, 993, 997, 1001, 1005, 1009, 1013, 1017,
+ 1021, 1025, 1029, 1033, 1037, 1041, 1045, 1049, 1053, 1057,
+ 1061, 1068, 1071, 1074, 1077, 1080, 1083, 1086, 1089, 1092,
+ 1095, 1098, 1101, 1104, 1107, 1110, 1113, 1116, 1119, 1122,
+ 1125, 1128, 1131, 1141, 1148, 1155, 1158, 1161, 1164, 1167,
+ 1170, 1173, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197,
+ 1205, 1205, 1208, 1208, 1214, 1217, 1223, 1226, 1233, 1237,
+ 1243, 1246, 1252, 1256, 1260, 1261, 1267, 1268, 1269, 1270,
+ 1271, 1272, 1273, 1277, 1281, 1281, 1281, 1288, 1289, 1293,
+ 1293, 1294, 1294, 1299, 1303, 1310, 1314, 1321, 1322, 1326,
+ 1332, 1336, 1345, 1345, 1352, 1355, 1361, 1365, 1371, 1371,
+ 1376, 1376, 1380, 1380, 1388, 1391, 1397, 1400, 1406, 1410,
+ 1417, 1420, 1423, 1426, 1429, 1437, 1443, 1449, 1452, 1458,
+ 1458
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION",
+ "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE",
+ "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "UINT_TYPE",
+ "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN",
+ "SWITCH", "CASE", "DEFAULT", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3",
+ "IVEC4", "VEC2", "VEC3", "VEC4", "UVEC2", "UVEC3", "UVEC4", "MATRIX2",
+ "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM",
+ "BUFFER", "VARYING", "MATRIX2x3", "MATRIX3x2", "MATRIX2x4", "MATRIX4x2",
+ "MATRIX3x4", "MATRIX4x3", "CENTROID", "FLAT", "SMOOTH", "READONLY",
+ "WRITEONLY", "COHERENT", "RESTRICT", "VOLATILE", "SHARED", "STRUCT",
+ "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE", "SAMPLER_EXTERNAL_OES",
+ "SAMPLER2DRECT", "SAMPLER2DARRAY", "ISAMPLER2D", "ISAMPLER3D",
+ "ISAMPLERCUBE", "ISAMPLER2DARRAY", "USAMPLER2D", "USAMPLER3D",
+ "USAMPLERCUBE", "USAMPLER2DARRAY", "SAMPLER2DMS", "ISAMPLER2DMS",
+ "USAMPLER2DMS", "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY",
+ "USAMPLER2DMSARRAY", "SAMPLER3D", "SAMPLER3DRECT", "SAMPLER2DSHADOW",
+ "SAMPLERCUBESHADOW", "SAMPLER2DARRAYSHADOW", "SAMPLEREXTERNAL2DY2YEXT",
+ "IMAGE2D", "IIMAGE2D", "UIMAGE2D", "IMAGE3D", "IIMAGE3D", "UIMAGE3D",
+ "IMAGE2DARRAY", "IIMAGE2DARRAY", "UIMAGE2DARRAY", "IMAGECUBE",
+ "IIMAGECUBE", "UIMAGECUBE", "ATOMICUINT", "LAYOUT", "YUVCSCSTANDARDEXT",
+ "YUVCSCSTANDARDEXTCONSTANT", "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT",
+ "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", "FIELD_SELECTION",
+ "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP",
+ "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN",
+ "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN",
+ "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN",
+ "LEFT_BRACKET", "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT",
+ "COMMA", "COLON", "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS",
+ "STAR", "SLASH", "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR",
+ "CARET", "AMPERSAND", "QUESTION", "$accept", "identifier",
+ "variable_identifier", "primary_expression", "postfix_expression",
+ "integer_expression", "function_call", "function_call_or_method",
+ "function_call_generic", "function_call_header_no_parameters",
+ "function_call_header_with_parameters", "function_call_header",
+ "function_identifier", "unary_expression", "unary_operator",
+ "multiplicative_expression", "additive_expression", "shift_expression",
+ "relational_expression", "equality_expression", "and_expression",
+ "exclusive_or_expression", "inclusive_or_expression",
+ "logical_and_expression", "logical_xor_expression",
+ "logical_or_expression", "conditional_expression",
+ "assignment_expression", "assignment_operator", "expression",
+ "constant_expression", "enter_struct", "declaration",
+ "function_prototype", "function_declarator",
+ "function_header_with_parameters", "function_header",
+ "parameter_declarator", "parameter_declaration",
+ "parameter_type_specifier", "init_declarator_list", "single_declaration",
+ "fully_specified_type", "interpolation_qualifier", "type_qualifier",
+ "invariant_qualifier", "single_type_qualifier", "storage_qualifier",
+ "type_specifier", "precision_qualifier", "layout_qualifier",
+ "layout_qualifier_id_list", "layout_qualifier_id",
+ "type_specifier_no_prec", "array_specifier", "type_specifier_nonarray",
+ "struct_specifier", "$@1", "$@2", "struct_declaration_list",
+ "struct_declaration", "struct_declarator_list", "struct_declarator",
+ "initializer", "declaration_statement", "statement", "simple_statement",
+ "compound_statement_with_scope", "$@3", "$@4", "statement_no_new_scope",
+ "statement_with_scope", "$@5", "$@6", "compound_statement_no_new_scope",
+ "statement_list", "expression_statement", "selection_statement",
+ "selection_rest_statement", "switch_statement", "$@7", "case_label",
+ "condition", "iteration_statement", "$@8", "$@9", "$@10",
+ "for_init_statement", "conditionopt", "for_rest_statement",
+ "jump_statement", "translation_unit", "external_declaration",
+ "function_definition", "$@11", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
+ 395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
+ 405, 406, 407, 408, 409, 410, 411
+};
+# endif
+
+#define YYPACT_NINF -361
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-361)))
+
+#define YYTABLE_NINF -260
+
+#define yytable_value_is_error(Yytable_value) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ 2569, -361, -361, -361, -361, 126, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -61, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, -361, -361, -361, -361, -361, -108, -361, -361,
+ -361, -69, -99, -45, 2673, -119, -361, 2, -361, 1397,
+ -361, -361, -361, -361, -361, -361, -361, -80, -361, 2465,
+ -361, -361, 2867, -361, -361, -361, -24, -40, -361, -17,
+ -361, 2673, -361, -361, -361, 2673, 39, 39, -361, -5,
+ -96, -56, -361, 2673, -361, -361, 1495, -32, -361, -361,
+ -9, 2673, -361, -361, -2, -51, -361, 420, -361, -361,
+ -361, -361, -80, -65, -361, 1873, -60, -361, -361, 2673,
+ 39, 2123, -361, -361, 27, -361, -361, -361, -361, -361,
+ 1873, 1873, 1873, -361, -361, -361, -361, -361, -361, -361,
+ -67, -361, -361, -361, 28, -48, 1997, 33, -361, 1873,
+ 15, 22, 58, -89, 54, 24, 34, 38, 67, 72,
+ -95, -361, 59, -361, 1622, -361, 2237, 2673, 66, -361,
+ -40, 53, 55, -361, 64, 69, 56, 1749, 71, 1873,
+ 68, 75, 62, -361, -361, 26, -361, -361, -86, -361,
+ -69, 77, -361, -361, -361, -361, 565, -361, -361, -361,
+ -361, -361, -361, -32, 1873, -57, -361, -361, 1873, 39,
+ -80, -50, -361, -83, -361, -361, -361, -43, -361, -361,
+ 1873, 2770, -361, -361, 1873, 81, -361, -361, -361, 1873,
+ 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873,
+ 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, -361,
+ -361, 80, -361, 2351, -361, -361, -361, -361, -361, 74,
+ -361, 1873, -361, -361, -21, 1873, 76, -361, -361, -361,
+ 710, -361, -361, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, 1873, 1873, -361, -361, -361, -361, 1873, -361,
+ -16, -32, 39, -361, -101, -361, -361, 82, 65, -361,
+ 86, -361, -361, -361, -361, -361, 15, 15, 22, 22,
+ 58, 58, 58, 58, -89, -89, 54, 24, 34, 38,
+ 67, 72, 40, -361, -361, 157, -17, 1000, 1145, -34,
+ -361, -30, -361, 1271, 710, -361, -361, -361, -361, -361,
+ 1873, -361, -361, 1873, 88, -361, -361, -361, -361, 1271,
+ 74, -361, 65, 39, 2673, 89, 84, 90, -361, 1873,
+ -361, 85, 91, 207, -361, 92, 93, 855, -361, 95,
+ -29, 1873, 855, 74, -361, 1873, -361, -361, -361, -361,
+ 96, 65, -361, -361, -361, -361
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint16 yydefact[] =
+{
+ 0, 126, 148, 149, 150, 0, 132, 134, 168, 165,
+ 166, 167, 172, 173, 174, 175, 176, 177, 169, 170,
+ 171, 178, 179, 180, 181, 182, 183, 135, 136, 137,
+ 139, 140, 133, 184, 185, 186, 187, 188, 189, 138,
+ 123, 122, 141, 142, 143, 144, 145, 146, 0, 164,
+ 191, 193, 212, 214, 194, 197, 198, 199, 200, 203,
+ 204, 205, 206, 195, 201, 207, 196, 202, 208, 192,
+ 209, 210, 211, 213, 215, 216, 217, 218, 219, 220,
+ 221, 222, 223, 224, 225, 226, 227, 0, 190, 229,
+ 298, 299, 0, 99, 98, 0, 110, 115, 130, 0,
+ 131, 124, 127, 120, 129, 128, 147, 158, 228, 0,
+ 295, 297, 0, 2, 3, 232, 0, 0, 89, 0,
+ 97, 0, 106, 100, 108, 0, 109, 0, 90, 2,
+ 116, 0, 95, 0, 125, 121, 0, 159, 1, 296,
+ 0, 0, 230, 157, 154, 0, 152, 0, 300, 101,
+ 105, 107, 103, 111, 102, 0, 117, 88, 96, 0,
+ 0, 0, 234, 10, 4, 8, 6, 7, 9, 31,
+ 0, 0, 0, 160, 38, 37, 39, 36, 5, 12,
+ 32, 14, 19, 20, 0, 0, 25, 0, 40, 0,
+ 44, 47, 50, 55, 58, 60, 62, 64, 66, 68,
+ 70, 87, 0, 29, 0, 91, 0, 0, 0, 151,
+ 0, 0, 0, 280, 0, 0, 0, 0, 0, 0,
+ 0, 0, 254, 263, 267, 40, 72, 85, 0, 243,
+ 0, 147, 246, 265, 245, 244, 0, 247, 248, 249,
+ 250, 251, 252, 104, 0, 112, 242, 119, 0, 0,
+ 240, 0, 238, 0, 235, 33, 34, 0, 16, 17,
+ 0, 0, 23, 22, 0, 164, 26, 28, 35, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 161,
+ 162, 0, 233, 0, 155, 156, 153, 291, 290, 261,
+ 282, 0, 294, 292, 0, 0, 0, 275, 278, 253,
+ 0, 75, 76, 78, 77, 80, 81, 82, 83, 84,
+ 79, 74, 0, 0, 268, 264, 266, 114, 0, 118,
+ 0, 241, 0, 236, 0, 92, 11, 0, 18, 30,
+ 15, 21, 27, 41, 42, 43, 46, 45, 48, 49,
+ 53, 54, 51, 52, 56, 57, 59, 61, 63, 65,
+ 67, 69, 0, 163, 231, 0, 0, 0, 0, 0,
+ 293, 0, 274, 0, 255, 73, 86, 113, 237, 239,
+ 0, 93, 13, 0, 0, 260, 262, 285, 284, 287,
+ 261, 272, 276, 0, 0, 0, 0, 0, 71, 0,
+ 286, 0, 0, 271, 269, 0, 0, 0, 256, 0,
+ 0, 288, 0, 261, 273, 0, 258, 279, 257, 94,
+ 0, 289, 283, 270, 277, 281
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -361, -47, -361, -361, -361, -361, -361, -361, -28, -361,
+ -361, -361, -361, 42, -361, -87, -85, -140, -88, -55,
+ -49, -52, -44, -42, -39, -361, -131, -146, -361, -159,
+ -196, -361, 14, 17, -361, -361, -361, 117, 122, 120,
+ -361, -361, -337, -361, -90, -361, -93, -361, -92, 242,
+ -361, -361, 41, 0, -115, -361, -361, -361, -361, -123,
+ -150, 4, -78, -232, -113, -226, -348, -149, -361, -361,
+ -155, -360, -361, -361, -116, -46, -110, -361, -361, -361,
+ -361, -361, -130, -361, -361, -361, -361, -361, -361, -361,
+ -361, -361, 151, -361, -361
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 250, 178, 179, 180, 337, 181, 182, 183, 184,
+ 185, 186, 187, 225, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 226, 227, 322, 228,
+ 202, 133, 229, 230, 92, 93, 94, 122, 123, 124,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 145, 146, 203, 137, 107, 108, 207, 141, 161,
+ 162, 251, 252, 247, 232, 233, 234, 235, 310, 396,
+ 417, 365, 366, 367, 418, 236, 237, 238, 404, 239,
+ 405, 240, 395, 241, 373, 299, 368, 389, 401, 402,
+ 242, 109, 110, 111, 119
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int16 yytable[] =
+{
+ 106, 116, 126, 148, 125, 201, 134, 135, 291, 246,
+ 326, 254, 327, 257, 90, 156, 329, 91, 206, 386,
+ 143, 127, 334, 306, 128, 117, 287, 276, 277, 126,
+ 403, 125, 134, 126, 380, 120, 393, 243, 245, 136,
+ 266, 160, 381, 159, 113, 114, 155, 258, 259, 160,
+ 130, 159, 393, 423, 323, 136, 254, 324, 304, 416,
+ 335, 288, 278, 279, 416, 144, 134, 249, 260, 160,
+ 136, 159, 261, 201, 118, 204, 115, 244, 204, 152,
+ 153, 157, 248, 209, 293, 328, 263, 158, 201, 210,
+ 332, 336, 264, 333, 106, 121, 377, 323, 246, 106,
+ 390, 338, 246, 204, 391, 420, 323, 129, 114, 106,
+ 323, 323, 140, 142, 160, 160, 159, 159, 342, 323,
+ 147, 106, 370, 90, 332, 106, 91, 378, 154, 362,
+ 2, 3, 4, 106, 205, 331, 350, 351, 352, 353,
+ 208, 106, 369, 254, 113, 114, 371, 231, 326, 311,
+ 312, 313, 314, 315, 316, 317, 318, 319, 320, 106,
+ -30, 106, 262, 269, 270, 271, 267, 272, 321, 273,
+ 274, 275, 280, 281, 294, 295, 375, 376, 188, 282,
+ 323, 383, 246, 424, 397, 346, 347, 285, 283, 348,
+ 349, 284, 354, 355, 286, 289, 297, 300, 298, 302,
+ 309, 160, 301, 159, 305, 323, 106, 106, 308, 307,
+ -29, -259, 255, 256, 392, -24, 363, 372, 382, -31,
+ 384, 399, 408, 407, 413, 412, 409, 356, 411, 222,
+ 392, 268, 358, 341, 357, 415, 231, 398, 419, 425,
+ 410, 359, 150, 149, 360, 151, 188, 112, 361, 201,
+ 385, 296, 421, 330, 379, 387, 414, 422, 388, 400,
+ 139, 188, 0, 0, 374, 0, 0, 0, 0, 246,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 394, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 106, 0, 0, 0, 0, 0, 394,
+ 0, 134, 135, 0, 0, 0, 0, 0, 0, 0,
+ 231, 343, 344, 345, 188, 188, 188, 188, 188, 188,
+ 188, 188, 188, 188, 188, 188, 188, 188, 188, 188,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 406, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 231, 231, 0,
+ 0, 0, 0, 231, 231, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 231,
+ 0, 0, 0, 0, 106, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 231, 0, 0,
+ 0, 0, 231, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 211, 212, 213, 0, 214, 215,
+ 216, 217, 218, 219, 220, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 221, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 0, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 163, 164, 89, 165, 166, 167,
+ 168, 169, 0, 0, 170, 171, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 172, 0, 0, 0, 222, 223, 0,
+ 0, 0, 0, 224, 174, 175, 176, 177, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 211,
+ 212, 213, 0, 214, 215, 216, 217, 218, 219, 220,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 221, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 163,
+ 164, 89, 165, 166, 167, 168, 169, 0, 0, 170,
+ 171, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 172, 0,
+ 0, 0, 222, 325, 0, 0, 0, 0, 224, 174,
+ 175, 176, 177, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 211, 212, 213, 0, 214, 215,
+ 216, 217, 218, 219, 220, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 221, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 0, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 163, 164, 89, 165, 166, 167,
+ 168, 169, 0, 0, 170, 171, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 172, 0, 0, 0, 222, 0, 0,
+ 0, 0, 0, 224, 174, 175, 176, 177, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 211,
+ 212, 213, 0, 214, 215, 216, 217, 218, 219, 220,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 221, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 163,
+ 164, 89, 165, 166, 167, 168, 169, 0, 0, 170,
+ 171, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 172, 0,
+ 0, 0, 147, 0, 0, 0, 0, 0, 224, 174,
+ 175, 176, 177, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 211, 212, 213, 0, 214, 215,
+ 216, 217, 218, 219, 220, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 221, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 0, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 163, 164, 89, 165, 166, 167,
+ 168, 169, 0, 0, 170, 171, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 172, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 224, 174, 175, 176, 177, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 0, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 163,
+ 164, 89, 165, 166, 167, 168, 169, 0, 0, 170,
+ 171, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 172, 6,
+ 7, 8, 9, 10, 11, 0, 0, 0, 224, 174,
+ 175, 176, 177, 0, 0, 0, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 0, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 0, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 163, 164, 89, 165, 166,
+ 167, 168, 169, 0, 0, 170, 171, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 3, 4, 172, 6, 7, 8, 9, 10,
+ 11, 0, 0, 0, 0, 174, 175, 176, 177, 0,
+ 0, 0, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 0, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 0, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 0, 131, 89, 0, 8, 9, 10, 11, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 0, 0, 0, 0, 0,
+ 132, 33, 34, 35, 36, 37, 38, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 49, 0, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 88, 163,
+ 164, 89, 165, 166, 167, 168, 169, 0, 0, 170,
+ 171, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 172, 0,
+ 0, 173, 8, 9, 10, 11, 0, 0, 0, 174,
+ 175, 176, 177, 0, 0, 0, 0, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 0, 0, 0, 0, 0, 0, 33, 34,
+ 35, 36, 37, 38, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 48, 49, 0, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 0, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 0, 88, 163, 164, 89, 165,
+ 166, 167, 168, 169, 0, 0, 170, 171, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 172, 0, 0, 290, 8,
+ 9, 10, 11, 0, 0, 0, 174, 175, 176, 177,
+ 0, 0, 0, 0, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 0,
+ 0, 0, 0, 0, 0, 33, 34, 35, 36, 37,
+ 38, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 49, 0, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 0, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 0, 88, 163, 164, 89, 165, 166, 167, 168,
+ 169, 0, 0, 170, 171, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 172, 8, 9, 10, 11, 0, 0, 0,
+ 0, 0, 303, 174, 175, 176, 177, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 0, 0, 0, 0, 0, 0, 33,
+ 34, 35, 36, 37, 38, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 0, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 88, 163, 164, 89,
+ 165, 166, 167, 168, 169, 0, 0, 170, 171, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 172, 8, 9, 10,
+ 11, 0, 0, 0, 0, 0, 0, 174, 175, 176,
+ 177, 0, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 0, 0, 0,
+ 0, 0, 0, 33, 34, 35, 36, 37, 38, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 265,
+ 0, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 0, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 88, 163, 164, 89, 165, 166, 167, 168, 169, 0,
+ 0, 170, 171, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 172, 6, 7, 8, 9, 10, 11, 0, 0, 0,
+ 0, 174, 175, 176, 177, 0, 0, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 0, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 0, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 0, 0, 89,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 3, 4, 0, 6, 7, 8, 9, 10,
+ 11, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 253, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 0, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 0, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 0, 0, 89, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 0, 6,
+ 7, 8, 9, 10, 11, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 292, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 0, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 0, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 0, 0, 89, 0, 0,
+ 0, 0, 0, 0, 0, 138, 0, 0, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 364,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 0, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 0,
+ 0, 89, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 0, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 0, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 87, 88, 0, 0, 89, 1, 2, 3, 4,
+ 0, 6, 7, 8, 9, 10, 11, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 0, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 0, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 0, 0, 89,
+ 8, 9, 10, 11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 0, 0, 0, 0, 0, 0, 33, 34, 35, 36,
+ 37, 38, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 48, 49, 0, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 0, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 0, 88, 0, 339, 89, 8, 9, 10,
+ 11, 340, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 0, 0, 0,
+ 0, 0, 0, 33, 34, 35, 36, 37, 38, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 49,
+ 0, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 0, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 88, 0, 0, 89
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 0, 48, 94, 119, 94, 136, 99, 99, 204, 155,
+ 236, 161, 244, 172, 0, 130, 248, 0, 141, 367,
+ 60, 140, 105, 219, 143, 133, 121, 116, 117, 121,
+ 390, 121, 125, 125, 135, 134, 373, 152, 153, 135,
+ 186, 133, 143, 133, 105, 106, 142, 114, 115, 141,
+ 97, 141, 389, 413, 140, 135, 206, 143, 217, 407,
+ 143, 156, 151, 152, 412, 105, 159, 159, 135, 161,
+ 135, 161, 139, 204, 143, 135, 137, 142, 135, 126,
+ 127, 137, 142, 134, 207, 142, 134, 143, 219, 140,
+ 140, 134, 140, 143, 94, 140, 328, 140, 244, 99,
+ 134, 260, 248, 135, 134, 134, 140, 105, 106, 109,
+ 140, 140, 112, 137, 206, 207, 206, 207, 264, 140,
+ 137, 121, 143, 109, 140, 125, 109, 143, 133, 288,
+ 4, 5, 6, 133, 143, 250, 276, 277, 278, 279,
+ 142, 141, 301, 293, 105, 106, 305, 147, 374, 123,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 159,
+ 133, 161, 134, 148, 149, 150, 133, 145, 142, 147,
+ 112, 113, 118, 119, 108, 109, 322, 323, 136, 155,
+ 140, 141, 328, 415, 380, 272, 273, 120, 154, 274,
+ 275, 153, 280, 281, 122, 136, 143, 133, 143, 143,
+ 138, 293, 133, 293, 133, 140, 206, 207, 133, 141,
+ 133, 137, 170, 171, 373, 134, 136, 141, 136, 133,
+ 63, 133, 138, 134, 17, 134, 136, 282, 143, 137,
+ 389, 189, 284, 261, 283, 142, 236, 383, 143, 143,
+ 399, 285, 125, 121, 286, 125, 204, 5, 287, 380,
+ 366, 210, 411, 249, 332, 368, 405, 412, 368, 389,
+ 109, 219, -1, -1, 310, -1, -1, -1, -1, 415,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 373, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 293, -1, -1, -1, -1, -1, 389,
+ -1, 394, 394, -1, -1, -1, -1, -1, -1, -1,
+ 310, 269, 270, 271, 272, 273, 274, 275, 276, 277,
+ 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 393, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 367, 368, -1,
+ -1, -1, -1, 373, 374, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 389,
+ -1, -1, -1, -1, 394, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 407, -1, -1,
+ -1, -1, 412, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 380, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, -1, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, -1, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, -1, -1, 114, 115, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 133, -1, -1, -1, 137, 138, -1,
+ -1, -1, -1, 143, 144, 145, 146, 147, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, -1, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, -1, -1, 114,
+ 115, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 133, -1,
+ -1, -1, 137, 138, -1, -1, -1, -1, 143, 144,
+ 145, 146, 147, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, -1, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, -1, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, -1, -1, 114, 115, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 133, -1, -1, -1, 137, -1, -1,
+ -1, -1, -1, 143, 144, 145, 146, 147, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, -1, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, -1, -1, 114,
+ 115, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 133, -1,
+ -1, -1, 137, -1, -1, -1, -1, -1, 143, 144,
+ 145, 146, 147, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, -1, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, -1, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, -1, -1, 114, 115, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 133, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 143, 144, 145, 146, 147, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, -1, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, -1, -1, 114,
+ 115, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 3, 4, 5, 6, 133, 8,
+ 9, 10, 11, 12, 13, -1, -1, -1, 143, 144,
+ 145, 146, 147, -1, -1, -1, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, -1, 64, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, -1, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, -1, -1, 114, 115, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 3, 4, 5, 6, 133, 8, 9, 10, 11, 12,
+ 13, -1, -1, -1, -1, 144, 145, 146, 147, -1,
+ -1, -1, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ -1, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, -1, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, -1, 105, 106, -1, 10, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, -1, -1, -1,
+ 143, 46, 47, 48, 49, 50, 51, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 61, 62, -1, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, -1, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, -1, -1, 114,
+ 115, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 133, -1,
+ -1, 136, 10, 11, 12, 13, -1, -1, -1, 144,
+ 145, 146, 147, -1, -1, -1, -1, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, -1, -1, -1, -1, 46, 47,
+ 48, 49, 50, 51, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 61, 62, -1, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, -1, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, -1, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, -1, -1, 114, 115, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 133, -1, -1, 136, 10,
+ 11, 12, 13, -1, -1, -1, 144, 145, 146, 147,
+ -1, -1, -1, -1, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, -1, -1, -1, -1, 46, 47, 48, 49, 50,
+ 51, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 61, 62, -1, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, -1, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, -1, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, -1, -1, 114, 115, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 133, 10, 11, 12, 13, -1, -1, -1,
+ -1, -1, 143, 144, 145, 146, 147, -1, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, -1, -1, -1, -1, 46,
+ 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 61, 62, -1, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, -1, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, -1, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, -1, -1, 114, 115, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 133, 10, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, 144, 145, 146,
+ 147, -1, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, -1,
+ -1, -1, -1, 46, 47, 48, 49, 50, 51, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 61, 62,
+ -1, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, -1, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, -1,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111, -1,
+ -1, 114, 115, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 3, 4, 5, 6,
+ 133, 8, 9, 10, 11, 12, 13, -1, -1, -1,
+ -1, 144, 145, 146, 147, -1, -1, -1, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, -1, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, -1, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, -1, -1, 106,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 3, 4, 5, 6, -1, 8, 9, 10, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 138, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ -1, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, -1, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, -1, -1, 106, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 3, 4, 5, 6, -1, 8,
+ 9, 10, 11, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 138, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, -1, 64, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, -1, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, -1, -1, 106, -1, -1,
+ -1, -1, -1, -1, -1, 0, -1, -1, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 138,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, -1, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, -1,
+ -1, 106, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, -1, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, -1, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, -1, -1, 106, 3, 4, 5, 6,
+ -1, 8, 9, 10, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, -1, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, -1, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, -1, -1, 106,
+ 10, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ -1, -1, -1, -1, -1, -1, 46, 47, 48, 49,
+ 50, 51, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 61, 62, -1, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, -1, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, -1, 103, -1, 105, 106, 10, 11, 12,
+ 13, 111, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, -1,
+ -1, -1, -1, 46, 47, 48, 49, 50, 51, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 61, 62,
+ -1, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, -1, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, -1,
+ 103, -1, -1, 106
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 106,
+ 189, 190, 191, 192, 193, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 210, 212, 213, 248,
+ 249, 250, 206, 105, 106, 137, 158, 133, 143, 251,
+ 134, 140, 194, 195, 196, 201, 205, 140, 143, 105,
+ 158, 105, 143, 188, 203, 205, 135, 211, 0, 249,
+ 210, 215, 137, 60, 105, 208, 209, 137, 231, 195,
+ 194, 196, 158, 158, 133, 142, 211, 137, 143, 201,
+ 205, 216, 217, 104, 105, 107, 108, 109, 110, 111,
+ 114, 115, 133, 136, 144, 145, 146, 147, 159, 160,
+ 161, 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+ 182, 183, 187, 210, 135, 143, 216, 214, 142, 134,
+ 140, 14, 15, 16, 18, 19, 20, 21, 22, 23,
+ 24, 63, 137, 138, 143, 170, 183, 184, 186, 189,
+ 190, 210, 221, 222, 223, 224, 232, 233, 234, 236,
+ 238, 240, 247, 211, 142, 211, 184, 220, 142, 205,
+ 158, 218, 219, 138, 217, 170, 170, 186, 114, 115,
+ 135, 139, 134, 134, 140, 62, 184, 133, 170, 148,
+ 149, 150, 145, 147, 112, 113, 116, 117, 151, 152,
+ 118, 119, 155, 154, 153, 120, 122, 121, 156, 136,
+ 136, 187, 138, 216, 108, 109, 209, 143, 143, 242,
+ 133, 133, 143, 143, 186, 133, 187, 141, 133, 138,
+ 225, 123, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 142, 185, 140, 143, 138, 222, 220, 142, 220,
+ 218, 211, 140, 143, 105, 143, 134, 162, 186, 105,
+ 111, 165, 184, 170, 170, 170, 172, 172, 173, 173,
+ 174, 174, 174, 174, 175, 175, 176, 177, 178, 179,
+ 180, 181, 186, 136, 138, 228, 229, 230, 243, 186,
+ 143, 186, 141, 241, 232, 184, 184, 220, 143, 219,
+ 135, 143, 136, 141, 63, 231, 223, 221, 233, 244,
+ 134, 134, 186, 199, 201, 239, 226, 187, 184, 133,
+ 239, 245, 246, 228, 235, 237, 158, 134, 138, 136,
+ 186, 143, 134, 17, 224, 142, 223, 227, 231, 143,
+ 134, 186, 227, 228, 220, 143
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 157, 158, 158, 159, 160, 160, 160, 160, 160,
+ 160, 160, 161, 161, 161, 161, 161, 161, 162, 163,
+ 164, 164, 165, 165, 166, 166, 167, 167, 168, 169,
+ 169, 169, 170, 170, 170, 170, 171, 171, 171, 171,
+ 172, 172, 172, 172, 173, 173, 173, 174, 174, 174,
+ 175, 175, 175, 175, 175, 176, 176, 176, 177, 177,
+ 178, 178, 179, 179, 180, 180, 181, 181, 182, 182,
+ 183, 183, 184, 184, 185, 185, 185, 185, 185, 185,
+ 185, 185, 185, 185, 185, 186, 186, 187, 188, 189,
+ 189, 189, 189, 189, 189, 189, 189, 190, 191, 191,
+ 192, 192, 193, 194, 194, 195, 195, 195, 195, 196,
+ 197, 197, 197, 197, 197, 198, 198, 198, 198, 198,
+ 199, 199, 200, 200, 201, 201, 202, 203, 203, 203,
+ 203, 203, 204, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 204, 204, 205, 206, 206,
+ 206, 207, 208, 208, 209, 209, 209, 209, 210, 210,
+ 211, 211, 211, 211, 212, 212, 212, 212, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 214, 213, 215, 213, 216, 216, 217, 217, 218, 218,
+ 219, 219, 220, 221, 222, 222, 223, 223, 223, 223,
+ 223, 223, 223, 224, 225, 226, 224, 227, 227, 229,
+ 228, 230, 228, 231, 231, 232, 232, 233, 233, 234,
+ 235, 235, 237, 236, 238, 238, 239, 239, 241, 240,
+ 242, 240, 243, 240, 244, 244, 245, 245, 246, 246,
+ 247, 247, 247, 247, 247, 248, 248, 249, 249, 251,
+ 250
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 4, 1, 3, 2, 2, 1, 1,
+ 1, 3, 2, 2, 2, 1, 2, 3, 2, 1,
+ 1, 1, 1, 2, 2, 2, 1, 1, 1, 1,
+ 1, 3, 3, 3, 1, 3, 3, 1, 3, 3,
+ 1, 3, 3, 3, 3, 1, 3, 3, 1, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+ 1, 5, 1, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 1, 2, 2,
+ 2, 4, 5, 6, 9, 2, 3, 2, 1, 1,
+ 2, 3, 3, 2, 3, 2, 1, 2, 1, 1,
+ 1, 3, 4, 6, 5, 1, 2, 3, 5, 4,
+ 1, 2, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 1, 3, 1, 3, 3, 1, 1, 2,
+ 2, 3, 3, 4, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 6, 0, 5, 1, 2, 3, 4, 1, 3,
+ 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 0, 0, 5, 1, 1, 0,
+ 2, 0, 2, 2, 3, 1, 2, 1, 2, 5,
+ 3, 1, 0, 6, 3, 2, 1, 4, 0, 6,
+ 0, 8, 0, 7, 1, 1, 1, 0, 2, 3,
+ 2, 2, 2, 3, 2, 1, 2, 1, 1, 0,
+ 3
+};
+
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, context, scanner, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+
+YY_ATTRIBUTE_UNUSED
+static unsigned
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+{
+ unsigned res = 0;
+ int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+ if (0 <= yylocp->first_line)
+ {
+ res += YYFPRINTF (yyo, "%d", yylocp->first_line);
+ if (0 <= yylocp->first_column)
+ res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
+ }
+ if (0 <= yylocp->last_line)
+ {
+ if (yylocp->first_line < yylocp->last_line)
+ {
+ res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
+ if (0 <= end_col)
+ res += YYFPRINTF (yyo, ".%d", end_col);
+ }
+ else if (0 <= end_col && yylocp->first_column < end_col)
+ res += YYFPRINTF (yyo, "-%d", end_col);
+ }
+ return res;
+ }
+
+# define YY_LOCATION_PRINT(File, Loc) \
+ yy_location_print_ (File, &(Loc))
+
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, Location, context, scanner); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT. |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context, void *scanner)
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ YYUSE (yylocationp);
+ YYUSE (context);
+ YYUSE (scanner);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context, void *scanner)
+{
+ YYFPRINTF (yyoutput, "%s %s (",
+ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context, scanner);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, TParseContext* context, void *scanner)
+{
+ unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ yystos[yyssp[yyi + 1 - yynrhs]],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , &(yylsp[(yyi + 1) - (yynrhs)]) , context, scanner);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, context, scanner); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, TParseContext* context, void *scanner)
+{
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
+ YYUSE (context);
+ YYUSE (scanner);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yytype);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (TParseContext* context, void *scanner)
+{
+/* The lookahead symbol. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+/* Location data for the lookahead symbol. */
+static YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+ = { 1, 1, 1, 1 }
+# endif
+;
+YYLTYPE yylloc = yyloc_default;
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ 'yyss': related to states.
+ 'yyvs': related to semantic values.
+ 'yyls': related to locations.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls;
+ YYLTYPE *yylsp;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[3];
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yylsp = yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ yylsp[0] = yylloc;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+
+ yyls = yyls1;
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = yylex (&yylval, &yylloc, scanner);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+
+ {
+ // The symbol table search was done in the lexical phase
+ (yyval.interm.intermTypedNode) = context->parseVariableIdentifier((yylsp[0]), ImmutableString((yyvsp[0].lex).string), (yyvsp[0].lex).symbol);
+ }
+
+ break;
+
+ case 5:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 6:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setIConst((yyvsp[0].lex).i);
+ (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 7:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setUConst((yyvsp[0].lex).u);
+ (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 8:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setFConst((yyvsp[0].lex).f);
+ (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 9:
+
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setBConst((yyvsp[0].lex).b);
+ (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 10:
+
+ {
+ if (!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_YUV_target))
+ {
+ context->error((yylsp[0]), "unsupported value", ImmutableString((yyvsp[0].lex).string));
+ }
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setYuvCscStandardEXTConst(getYuvCscStandardEXT(ImmutableString((yyvsp[0].lex).string)));
+ (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 11:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 12:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 13:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addIndexExpression((yyvsp[-3].interm.intermTypedNode), (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 14:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 15:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addFieldSelectionExpression((yyvsp[-2].interm.intermTypedNode), (yylsp[-1]), ImmutableString((yyvsp[0].lex).string), (yylsp[0]));
+ }
+
+ break;
+
+ case 16:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode), (yylsp[0]));
+ }
+
+ break;
+
+ case 17:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode), (yylsp[0]));
+ }
+
+ break;
+
+ case 18:
+
+ {
+ context->checkIsScalarInteger((yyvsp[0].interm.intermTypedNode), "[]");
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 19:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm.functionLookup), (yylsp[0]));
+ }
+
+ break;
+
+ case 20:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[0].interm.functionLookup);
+ }
+
+ break;
+
+ case 21:
+
+ {
+ ES3_OR_NEWER("", (yylsp[0]), "methods");
+ (yyval.interm.functionLookup) = (yyvsp[0].interm.functionLookup);
+ (yyval.interm.functionLookup)->setThisNode((yyvsp[-2].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 22:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup);
+ }
+
+ break;
+
+ case 23:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup);
+ }
+
+ break;
+
+ case 24:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup);
+ }
+
+ break;
+
+ case 25:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[0].interm.functionLookup);
+ }
+
+ break;
+
+ case 26:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup);
+ (yyval.interm.functionLookup)->addArgument((yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 27:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[-2].interm.functionLookup);
+ (yyval.interm.functionLookup)->addArgument((yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 28:
+
+ {
+ (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup);
+ }
+
+ break;
+
+ case 29:
+
+ {
+ (yyval.interm.functionLookup) = context->addConstructorFunc((yyvsp[0].interm.type));
+ }
+
+ break;
+
+ case 30:
+
+ {
+ (yyval.interm.functionLookup) = context->addNonConstructorFunc(ImmutableString((yyvsp[0].lex).string), (yyvsp[0].lex).symbol);
+ }
+
+ break;
+
+ case 31:
+
+ {
+ (yyval.interm.functionLookup) = context->addNonConstructorFunc(ImmutableString((yyvsp[0].lex).string), (yyvsp[0].lex).symbol);
+ }
+
+ break;
+
+ case 32:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 33:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPreIncrement, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 34:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPreDecrement, (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 35:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addUnaryMath((yyvsp[-1].interm.op), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 36:
+
+ { (yyval.interm.op) = EOpPositive; }
+
+ break;
+
+ case 37:
+
+ { (yyval.interm.op) = EOpNegative; }
+
+ break;
+
+ case 38:
+
+ { (yyval.interm.op) = EOpLogicalNot; }
+
+ break;
+
+ case 39:
+
+ {
+ ES3_OR_NEWER("~", (yyloc), "bit-wise operator");
+ (yyval.interm.op) = EOpBitwiseNot;
+ }
+
+ break;
+
+ case 40:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 41:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 42:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 43:
+
+ {
+ ES3_OR_NEWER("%", (yylsp[-1]), "integer modulus operator");
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpIMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 44:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 45:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 46:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 47:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 48:
+
+ {
+ ES3_OR_NEWER("<<", (yylsp[-1]), "bit-wise operator");
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitShiftLeft, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 49:
+
+ {
+ ES3_OR_NEWER(">>", (yylsp[-1]), "bit-wise operator");
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitShiftRight, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 50:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 51:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 52:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 53:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 54:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 55:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 56:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 57:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpNotEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 58:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 59:
+
+ {
+ ES3_OR_NEWER("&", (yylsp[-1]), "bit-wise operator");
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 60:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 61:
+
+ {
+ ES3_OR_NEWER("^", (yylsp[-1]), "bit-wise operator");
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 62:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 63:
+
+ {
+ ES3_OR_NEWER("|", (yylsp[-1]), "bit-wise operator");
+ (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 64:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 65:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 66:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 67:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 68:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 69:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 70:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 71:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addTernarySelection((yyvsp[-4].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-3]));
+ }
+
+ break;
+
+ case 72:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 73:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addAssign((yyvsp[-1].interm.op), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 74:
+
+ { (yyval.interm.op) = EOpAssign; }
+
+ break;
+
+ case 75:
+
+ { (yyval.interm.op) = EOpMulAssign; }
+
+ break;
+
+ case 76:
+
+ { (yyval.interm.op) = EOpDivAssign; }
+
+ break;
+
+ case 77:
+
+ {
+ ES3_OR_NEWER("%=", (yyloc), "integer modulus operator");
+ (yyval.interm.op) = EOpIModAssign;
+ }
+
+ break;
+
+ case 78:
+
+ { (yyval.interm.op) = EOpAddAssign; }
+
+ break;
+
+ case 79:
+
+ { (yyval.interm.op) = EOpSubAssign; }
+
+ break;
+
+ case 80:
+
+ {
+ ES3_OR_NEWER("<<=", (yyloc), "bit-wise operator");
+ (yyval.interm.op) = EOpBitShiftLeftAssign;
+ }
+
+ break;
+
+ case 81:
+
+ {
+ ES3_OR_NEWER(">>=", (yyloc), "bit-wise operator");
+ (yyval.interm.op) = EOpBitShiftRightAssign;
+ }
+
+ break;
+
+ case 82:
+
+ {
+ ES3_OR_NEWER("&=", (yyloc), "bit-wise operator");
+ (yyval.interm.op) = EOpBitwiseAndAssign;
+ }
+
+ break;
+
+ case 83:
+
+ {
+ ES3_OR_NEWER("^=", (yyloc), "bit-wise operator");
+ (yyval.interm.op) = EOpBitwiseXorAssign;
+ }
+
+ break;
+
+ case 84:
+
+ {
+ ES3_OR_NEWER("|=", (yyloc), "bit-wise operator");
+ (yyval.interm.op) = EOpBitwiseOrAssign;
+ }
+
+ break;
+
+ case 85:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 86:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
+ }
+
+ break;
+
+ case 87:
+
+ {
+ context->checkIsConst((yyvsp[0].interm.intermTypedNode));
+ (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 88:
+
+ {
+ context->enterStructDeclaration((yylsp[-1]), ImmutableString((yyvsp[-1].lex).string));
+ (yyval.lex) = (yyvsp[-1].lex);
+ }
+
+ break;
+
+ case 89:
+
+ {
+ (yyval.interm.intermNode) = context->addFunctionPrototypeDeclaration(*((yyvsp[-1].interm).function), (yylsp[-1]));
+ }
+
+ break;
+
+ case 90:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[-1].interm).intermDeclaration;
+ }
+
+ break;
+
+ case 91:
+
+ {
+ context->parseDefaultPrecisionQualifier((yyvsp[-2].interm.precision), (yyvsp[-1].interm.type), (yylsp[-3]));
+ (yyval.interm.intermNode) = nullptr;
+ }
+
+ break;
+
+ case 92:
+
+ {
+ ES3_OR_NEWER(ImmutableString((yyvsp[-3].lex).string), (yylsp[-4]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-4].interm.typeQualifierBuilder), (yylsp[-3]), ImmutableString((yyvsp[-3].lex).string), (yyvsp[-2].interm.fieldList), kEmptyImmutableString, (yyloc), NULL, (yyloc));
+ }
+
+ break;
+
+ case 93:
+
+ {
+ ES3_OR_NEWER(ImmutableString((yyvsp[-4].lex).string), (yylsp[-5]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-5].interm.typeQualifierBuilder), (yylsp[-4]), ImmutableString((yyvsp[-4].lex).string), (yyvsp[-3].interm.fieldList), ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]), NULL, (yyloc));
+ }
+
+ break;
+
+ case 94:
+
+ {
+ ES3_OR_NEWER(ImmutableString((yyvsp[-7].lex).string), (yylsp[-8]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-8].interm.typeQualifierBuilder), (yylsp[-7]), ImmutableString((yyvsp[-7].lex).string), (yyvsp[-6].interm.fieldList), ImmutableString((yyvsp[-4].lex).string), (yylsp[-4]), (yyvsp[-2].interm.intermTypedNode), (yylsp[-3]));
+ }
+
+ break;
+
+ case 95:
+
+ {
+ context->parseGlobalLayoutQualifier(*(yyvsp[-1].interm.typeQualifierBuilder));
+ (yyval.interm.intermNode) = nullptr;
+ }
+
+ break;
+
+ case 96:
+
+ {
+ (yyval.interm.intermNode) = context->parseInvariantDeclaration(*(yyvsp[-2].interm.typeQualifierBuilder), (yylsp[-1]), ImmutableString((yyvsp[-1].lex).string), (yyvsp[-1].lex).symbol);
+ }
+
+ break;
+
+ case 97:
+
+ {
+ (yyval.interm).function = context->parseFunctionDeclarator((yylsp[0]), (yyvsp[-1].interm.function));
+ context->exitFunctionDeclaration();
+ }
+
+ break;
+
+ case 98:
+
+ {
+ (yyval.interm.function) = (yyvsp[0].interm.function);
+ }
+
+ break;
+
+ case 99:
+
+ {
+ (yyval.interm.function) = (yyvsp[0].interm.function);
+ }
+
+ break;
+
+ case 100:
+
+ {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[-1].interm.function);
+ if ((yyvsp[0].interm.param).type->getBasicType() != EbtVoid)
+ {
+ (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm.param).createVariable(&context->symbolTable));
+ }
+ }
+
+ break;
+
+ case 101:
+
+ {
+ (yyval.interm.function) = (yyvsp[-2].interm.function);
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ if ((yyvsp[0].interm.param).type->getBasicType() == EbtVoid)
+ {
+ // This parameter > first is void
+ context->error((yylsp[-1]), "cannot be a parameter type except for '(void)'", "void");
+ }
+ else
+ {
+ (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm.param).createVariable(&context->symbolTable));
+ }
+ }
+
+ break;
+
+ case 102:
+
+ {
+ (yyval.interm.function) = context->parseFunctionHeader((yyvsp[-2].interm.type), ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]));
+
+ context->symbolTable.push();
+ context->enterFunctionDeclaration();
+ }
+
+ break;
+
+ case 103:
+
+ {
+ (yyval.interm.param) = context->parseParameterDeclarator((yyvsp[-1].interm.type), ImmutableString((yyvsp[0].lex).string), (yylsp[0]));
+ }
+
+ break;
+
+ case 104:
+
+ {
+ (yyval.interm.param) = context->parseParameterArrayDeclarator(ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]), *((yyvsp[0].interm.arraySizes)), (yylsp[0]), &(yyvsp[-2].interm.type));
+ }
+
+ break;
+
+ case 105:
+
+ {
+ (yyval.interm.param) = (yyvsp[0].interm.param);
+ context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.param).type);
+ }
+
+ break;
+
+ case 106:
+
+ {
+ (yyval.interm.param) = (yyvsp[0].interm.param);
+ (yyval.interm.param).type->setQualifier(EvqIn);
+ }
+
+ break;
+
+ case 107:
+
+ {
+ (yyval.interm.param) = (yyvsp[0].interm.param);
+ context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.param).type);
+ }
+
+ break;
+
+ case 108:
+
+ {
+ (yyval.interm.param) = (yyvsp[0].interm.param);
+ (yyval.interm.param).type->setQualifier(EvqIn);
+ }
+
+ break;
+
+ case 109:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[0].interm.type)) };
+ (yyval.interm.param) = param;
+ }
+
+ break;
+
+ case 110:
+
+ {
+ (yyval.interm) = (yyvsp[0].interm);
+ }
+
+ break;
+
+ case 111:
+
+ {
+ (yyval.interm) = (yyvsp[-2].interm);
+ context->parseDeclarator((yyval.interm).type, (yylsp[0]), ImmutableString((yyvsp[0].lex).string), (yyval.interm).intermDeclaration);
+ }
+
+ break;
+
+ case 112:
+
+ {
+ (yyval.interm) = (yyvsp[-3].interm);
+ context->parseArrayDeclarator((yyval.interm).type, (yylsp[-1]), ImmutableString((yyvsp[-1].lex).string), (yylsp[0]), *((yyvsp[0].interm.arraySizes)), (yyval.interm).intermDeclaration);
+ }
+
+ break;
+
+ case 113:
+
+ {
+ ES3_OR_NEWER("=", (yylsp[-1]), "first-class arrays (array initializer)");
+ (yyval.interm) = (yyvsp[-5].interm);
+ context->parseArrayInitDeclarator((yyval.interm).type, (yylsp[-3]), ImmutableString((yyvsp[-3].lex).string), (yylsp[-2]), *((yyvsp[-2].interm.arraySizes)), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode), (yyval.interm).intermDeclaration);
+ }
+
+ break;
+
+ case 114:
+
+ {
+ (yyval.interm) = (yyvsp[-4].interm);
+ context->parseInitDeclarator((yyval.interm).type, (yylsp[-2]), ImmutableString((yyvsp[-2].lex).string), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode), (yyval.interm).intermDeclaration);
+ }
+
+ break;
+
+ case 115:
+
+ {
+ (yyval.interm).type = (yyvsp[0].interm.type);
+ (yyval.interm).intermDeclaration = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), kEmptyImmutableString);
+ }
+
+ break;
+
+ case 116:
+
+ {
+ (yyval.interm).type = (yyvsp[-1].interm.type);
+ (yyval.interm).intermDeclaration = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), ImmutableString((yyvsp[0].lex).string));
+ }
+
+ break;
+
+ case 117:
+
+ {
+ (yyval.interm).type = (yyvsp[-2].interm.type);
+ (yyval.interm).intermDeclaration = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[-1]), ImmutableString((yyvsp[-1].lex).string), (yylsp[0]), *((yyvsp[0].interm.arraySizes)));
+ }
+
+ break;
+
+ case 118:
+
+ {
+ ES3_OR_NEWER("[]", (yylsp[-2]), "first-class arrays (array initializer)");
+ (yyval.interm).type = (yyvsp[-4].interm.type);
+ (yyval.interm).intermDeclaration = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-3]), ImmutableString((yyvsp[-3].lex).string), (yylsp[-2]), *((yyvsp[-2].interm.arraySizes)), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 119:
+
+ {
+ (yyval.interm).type = (yyvsp[-3].interm.type);
+ (yyval.interm).intermDeclaration = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[-2]), ImmutableString((yyvsp[-2].lex).string), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 120:
+
+ {
+ context->addFullySpecifiedType(&(yyvsp[0].interm.type));
+ (yyval.interm.type) = (yyvsp[0].interm.type);
+ }
+
+ break;
+
+ case 121:
+
+ {
+ (yyval.interm.type) = context->addFullySpecifiedType(*(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.type));
+ }
+
+ break;
+
+ case 122:
+
+ {
+ (yyval.interm.qualifier) = EvqSmooth;
+ }
+
+ break;
+
+ case 123:
+
+ {
+ (yyval.interm.qualifier) = EvqFlat;
+ }
+
+ break;
+
+ case 124:
+
+ {
+ (yyval.interm.typeQualifierBuilder) = context->createTypeQualifierBuilder((yylsp[0]));
+ (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper));
+ }
+
+ break;
+
+ case 125:
+
+ {
+ (yyval.interm.typeQualifierBuilder) = (yyvsp[-1].interm.typeQualifierBuilder);
+ (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper));
+ }
+
+ break;
+
+ case 126:
+
+ {
+ // empty
+ }
+
+ break;
+
+ case 127:
+
+ {
+ context->checkLocalVariableConstStorageQualifier(*(yyvsp[0].interm.qualifierWrapper));
+ (yyval.interm.qualifierWrapper) = (yyvsp[0].interm.qualifierWrapper);
+ }
+
+ break;
+
+ case 128:
+
+ {
+ context->checkIsAtGlobalLevel((yylsp[0]), "layout");
+ (yyval.interm.qualifierWrapper) = new TLayoutQualifierWrapper((yyvsp[0].interm.layoutQualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 129:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TPrecisionQualifierWrapper((yyvsp[0].interm.precision), (yylsp[0]));
+ }
+
+ break;
+
+ case 130:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TInterpolationQualifierWrapper((yyvsp[0].interm.qualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 131:
+
+ {
+ context->checkIsAtGlobalLevel((yylsp[0]), "invariant");
+ (yyval.interm.qualifierWrapper) = new TInvariantQualifierWrapper((yylsp[0]));
+ }
+
+ break;
+
+ case 132:
+
+ {
+ VERTEX_ONLY("attribute", (yylsp[0]));
+ ES2_ONLY("attribute", (yylsp[0]));
+ (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqAttribute, (yylsp[0]));
+ }
+
+ break;
+
+ case 133:
+
+ {
+ ES2_ONLY("varying", (yylsp[0]));
+ (yyval.interm.qualifierWrapper) = context->parseVaryingQualifier((yylsp[0]));
+ }
+
+ break;
+
+ case 134:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper(EvqConst, (yylsp[0]));
+ }
+
+ break;
+
+ case 135:
+
+ {
+ (yyval.interm.qualifierWrapper) = context->parseInQualifier((yylsp[0]));
+ }
+
+ break;
+
+ case 136:
+
+ {
+ (yyval.interm.qualifierWrapper) = context->parseOutQualifier((yylsp[0]));
+ }
+
+ break;
+
+ case 137:
+
+ {
+ (yyval.interm.qualifierWrapper) = context->parseInOutQualifier((yylsp[0]));
+ }
+
+ break;
+
+ case 138:
+
+ {
+ ES3_OR_NEWER("centroid", (yylsp[0]), "storage qualifier");
+ (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper(EvqCentroid, (yylsp[0]));
+ }
+
+ break;
+
+ case 139:
+
+ {
+ (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqUniform, (yylsp[0]));
+ }
+
+ break;
+
+ case 140:
+
+ {
+ ES3_1_ONLY("buffer", (yylsp[0]), "storage qualifier");
+ (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqBuffer, (yylsp[0]));
+ }
+
+ break;
+
+ case 141:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqReadOnly, (yylsp[0]));
+ }
+
+ break;
+
+ case 142:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqWriteOnly, (yylsp[0]));
+ }
+
+ break;
+
+ case 143:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqCoherent, (yylsp[0]));
+ }
+
+ break;
+
+ case 144:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqRestrict, (yylsp[0]));
+ }
+
+ break;
+
+ case 145:
+
+ {
+ (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqVolatile, (yylsp[0]));
+ }
+
+ break;
+
+ case 146:
+
+ {
+ COMPUTE_ONLY("shared", (yylsp[0]));
+ (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqShared, (yylsp[0]));
+ }
+
+ break;
+
+ case 147:
+
+ {
+ (yyval.interm.type) = (yyvsp[0].interm.type);
+ (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[0].interm.type).getBasicType());
+ }
+
+ break;
+
+ case 148:
+
+ {
+ (yyval.interm.precision) = EbpHigh;
+ }
+
+ break;
+
+ case 149:
+
+ {
+ (yyval.interm.precision) = EbpMedium;
+ }
+
+ break;
+
+ case 150:
+
+ {
+ (yyval.interm.precision) = EbpLow;
+ }
+
+ break;
+
+ case 151:
+
+ {
+ ES3_OR_NEWER("layout", (yylsp[-3]), "qualifier");
+ (yyval.interm.layoutQualifier) = (yyvsp[-1].interm.layoutQualifier);
+ }
+
+ break;
+
+ case 152:
+
+ {
+ (yyval.interm.layoutQualifier) = (yyvsp[0].interm.layoutQualifier);
+ }
+
+ break;
+
+ case 153:
+
+ {
+ (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier), (yylsp[0]));
+ }
+
+ break;
+
+ case 154:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString((yyvsp[0].lex).string), (yylsp[0]));
+ }
+
+ break;
+
+ case 155:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString((yyvsp[-2].lex).string), (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0]));
+ }
+
+ break;
+
+ case 156:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString((yyvsp[-2].lex).string), (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0]));
+ }
+
+ break;
+
+ case 157:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString("shared"), (yylsp[0]));
+ }
+
+ break;
+
+ case 158:
+
+ {
+ (yyval.interm.type).initialize((yyvsp[0].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ }
+
+ break;
+
+ case 159:
+
+ {
+ (yyval.interm.type).initialize((yyvsp[-1].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary));
+ (yyval.interm.type).setArraySizes((yyvsp[0].interm.arraySizes));
+ }
+
+ break;
+
+ case 160:
+
+ {
+ ES3_OR_NEWER("[]", (yylsp[-1]), "implicitly sized array");
+ (yyval.interm.arraySizes) = new TVector<unsigned int>();
+ (yyval.interm.arraySizes)->push_back(0u);
+ }
+
+ break;
+
+ case 161:
+
+ {
+ (yyval.interm.arraySizes) = new TVector<unsigned int>();
+ unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding a variable's non-arrayness won't follow.
+ (yyval.interm.arraySizes)->push_back(size);
+ }
+
+ break;
+
+ case 162:
+
+ {
+ ES3_1_ONLY("[]", (yylsp[-1]), "arrays of arrays");
+ (yyval.interm.arraySizes) = (yyvsp[-2].interm.arraySizes);
+ (yyval.interm.arraySizes)->insert((yyval.interm.arraySizes)->begin(), 0u);
+ }
+
+ break;
+
+ case 163:
+
+ {
+ ES3_1_ONLY("[]", (yylsp[-2]), "arrays of arrays");
+ (yyval.interm.arraySizes) = (yyvsp[-3].interm.arraySizes);
+ unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode));
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding a variable's non-arrayness won't follow.
+ (yyval.interm.arraySizes)->insert((yyval.interm.arraySizes)->begin(), size);
+ }
+
+ break;
+
+ case 164:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtVoid, (yylsp[0]));
+ }
+
+ break;
+
+ case 165:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ }
+
+ break;
+
+ case 166:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ }
+
+ break;
+
+ case 167:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ }
+
+ break;
+
+ case 168:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ }
+
+ break;
+
+ case 169:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 170:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 171:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 172:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 173:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 174:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 175:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 176:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 177:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 178:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(2);
+ }
+
+ break;
+
+ case 179:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(3);
+ }
+
+ break;
+
+ case 180:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setAggregate(4);
+ }
+
+ break;
+
+ case 181:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(2, 2);
+ }
+
+ break;
+
+ case 182:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(3, 3);
+ }
+
+ break;
+
+ case 183:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(4, 4);
+ }
+
+ break;
+
+ case 184:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(2, 3);
+ }
+
+ break;
+
+ case 185:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(3, 2);
+ }
+
+ break;
+
+ case 186:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(2, 4);
+ }
+
+ break;
+
+ case 187:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(4, 2);
+ }
+
+ break;
+
+ case 188:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(3, 4);
+ }
+
+ break;
+
+ case 189:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0]));
+ (yyval.interm.typeSpecifierNonArray).setMatrix(4, 3);
+ }
+
+ break;
+
+ case 190:
+
+ {
+ if (!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_YUV_target))
+ {
+ context->error((yylsp[0]), "unsupported type", "yuvCscStandardEXT");
+ }
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtYuvCscStandardEXT, (yylsp[0]));
+ }
+
+ break;
+
+ case 191:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 192:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 193:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 194:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 195:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DMS, (yylsp[0]));
+ }
+
+ break;
+
+ case 196:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DMSArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 197:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 198:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 199:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISamplerCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 200:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 201:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DMS, (yylsp[0]));
+ }
+
+ break;
+
+ case 202:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DMSArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 203:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 204:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 205:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSamplerCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 206:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 207:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DMS, (yylsp[0]));
+ }
+
+ break;
+
+ case 208:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DMSArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 209:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DShadow, (yylsp[0]));
+ }
+
+ break;
+
+ case 210:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCubeShadow, (yylsp[0]));
+ }
+
+ break;
+
+ case 211:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArrayShadow, (yylsp[0]));
+ }
+
+ break;
+
+ case 212:
+
+ {
+ constexpr std::array<TExtension, 3u> extensions{ { TExtension::NV_EGL_stream_consumer_external,
+ TExtension::OES_EGL_image_external_essl3,
+ TExtension::OES_EGL_image_external } };
+ if (!context->checkCanUseOneOfExtensions((yylsp[0]), extensions))
+ {
+ context->error((yylsp[0]), "unsupported type", "samplerExternalOES");
+ }
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerExternalOES, (yylsp[0]));
+ }
+
+ break;
+
+ case 213:
+
+ {
+ if (!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_YUV_target))
+ {
+ context->error((yylsp[0]), "unsupported type", "__samplerExternal2DY2YEXT");
+ }
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerExternal2DY2YEXT, (yylsp[0]));
+ }
+
+ break;
+
+ case 214:
+
+ {
+ if (!context->checkCanUseExtension((yylsp[0]), TExtension::ARB_texture_rectangle))
+ {
+ context->error((yylsp[0]), "unsupported type", "sampler2DRect");
+ }
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DRect, (yylsp[0]));
+ }
+
+ break;
+
+ case 215:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtImage2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 216:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtIImage2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 217:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUImage2D, (yylsp[0]));
+ }
+
+ break;
+
+ case 218:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtImage3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 219:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtIImage3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 220:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUImage3D, (yylsp[0]));
+ }
+
+ break;
+
+ case 221:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtImage2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 222:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtIImage2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 223:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUImage2DArray, (yylsp[0]));
+ }
+
+ break;
+
+ case 224:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtImageCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 225:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtIImageCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 226:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtUImageCube, (yylsp[0]));
+ }
+
+ break;
+
+ case 227:
+
+ {
+ (yyval.interm.typeSpecifierNonArray).initialize(EbtAtomicCounter, (yylsp[0]));
+ }
+
+ break;
+
+ case 228:
+
+ {
+ (yyval.interm.typeSpecifierNonArray) = (yyvsp[0].interm.typeSpecifierNonArray);
+ }
+
+ break;
+
+ case 229:
+
+ {
+ // This is for user defined type names. The lexical phase looked up the type.
+ const TStructure *structure = static_cast<const TStructure*>((yyvsp[0].lex).symbol);
+ (yyval.interm.typeSpecifierNonArray).initializeStruct(structure, false, (yylsp[0]));
+ }
+
+ break;
+
+ case 230:
+
+ { context->enterStructDeclaration((yylsp[-1]), ImmutableString((yyvsp[-1].lex).string)); }
+
+ break;
+
+ case 231:
+
+ {
+ (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-5]), (yylsp[-4]), ImmutableString((yyvsp[-4].lex).string), (yyvsp[-1].interm.fieldList));
+ }
+
+ break;
+
+ case 232:
+
+ { context->enterStructDeclaration((yylsp[0]), kEmptyImmutableString); }
+
+ break;
+
+ case 233:
+
+ {
+ (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-4]), (yyloc), kEmptyImmutableString, (yyvsp[-1].interm.fieldList));
+ }
+
+ break;
+
+ case 234:
+
+ {
+ (yyval.interm.fieldList) = context->addStructFieldList((yyvsp[0].interm.fieldList), (yylsp[0]));
+ }
+
+ break;
+
+ case 235:
+
+ {
+ (yyval.interm.fieldList) = context->combineStructFieldLists((yyvsp[-1].interm.fieldList), (yyvsp[0].interm.fieldList), (yylsp[0]));
+ }
+
+ break;
+
+ case 236:
+
+ {
+ (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[-2].interm.type), (yyvsp[-1].interm.declaratorList));
+ }
+
+ break;
+
+ case 237:
+
+ {
+ // ES3 Only, but errors should be handled elsewhere
+ (yyval.interm.fieldList) = context->addStructDeclaratorListWithQualifiers(*(yyvsp[-3].interm.typeQualifierBuilder), &(yyvsp[-2].interm.type), (yyvsp[-1].interm.declaratorList));
+ }
+
+ break;
+
+ case 238:
+
+ {
+ (yyval.interm.declaratorList) = new TDeclaratorList();
+ (yyval.interm.declaratorList)->push_back((yyvsp[0].interm.declarator));
+ }
+
+ break;
+
+ case 239:
+
+ {
+ (yyval.interm.declaratorList)->push_back((yyvsp[0].interm.declarator));
+ }
+
+ break;
+
+ case 240:
+
+ {
+ (yyval.interm.declarator) = context->parseStructDeclarator(ImmutableString((yyvsp[0].lex).string), (yylsp[0]));
+ }
+
+ break;
+
+ case 241:
+
+ {
+ (yyval.interm.declarator) = context->parseStructArrayDeclarator(ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]), (yyvsp[0].interm.arraySizes));
+ }
+
+ break;
+
+ case 242:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
+
+ break;
+
+ case 243:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 244:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
+
+ break;
+
+ case 245:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 246:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 247:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 248:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 249:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermSwitch); }
+
+ break;
+
+ case 250:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermCase); }
+
+ break;
+
+ case 251:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 252:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 253:
+
+ {
+ (yyval.interm.intermBlock) = new TIntermBlock();
+ (yyval.interm.intermBlock)->setLine((yyloc));
+ }
+
+ break;
+
+ case 254:
+
+ { context->symbolTable.push(); }
+
+ break;
+
+ case 255:
+
+ { context->symbolTable.pop(); }
+
+ break;
+
+ case 256:
+
+ {
+ (yyvsp[-2].interm.intermBlock)->setLine((yyloc));
+ (yyval.interm.intermBlock) = (yyvsp[-2].interm.intermBlock);
+ }
+
+ break;
+
+ case 257:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
+
+ break;
+
+ case 258:
+
+ { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 259:
+
+ { context->symbolTable.push(); }
+
+ break;
+
+ case 260:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
+
+ break;
+
+ case 261:
+
+ { context->symbolTable.push(); }
+
+ break;
+
+ case 262:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+ break;
+
+ case 263:
+
+ {
+ (yyval.interm.intermBlock) = new TIntermBlock();
+ (yyval.interm.intermBlock)->setLine((yyloc));
+ }
+
+ break;
+
+ case 264:
+
+ {
+ (yyvsp[-1].interm.intermBlock)->setLine((yyloc));
+ (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock);
+ }
+
+ break;
+
+ case 265:
+
+ {
+ (yyval.interm.intermBlock) = new TIntermBlock();
+ context->appendStatement((yyval.interm.intermBlock), (yyvsp[0].interm.intermNode));
+ }
+
+ break;
+
+ case 266:
+
+ {
+ (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock);
+ context->appendStatement((yyval.interm.intermBlock), (yyvsp[0].interm.intermNode));
+ }
+
+ break;
+
+ case 267:
+
+ { (yyval.interm.intermNode) = context->addEmptyStatement((yyloc)); }
+
+ break;
+
+ case 268:
+
+ { (yyval.interm.intermNode) = (yyvsp[-1].interm.intermTypedNode); }
+
+ break;
+
+ case 269:
+
+ {
+ (yyval.interm.intermNode) = context->addIfElse((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yylsp[-4]));
+ }
+
+ break;
+
+ case 270:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 271:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode);
+ (yyval.interm.nodePair).node2 = nullptr;
+ }
+
+ break;
+
+ case 272:
+
+ { context->incrSwitchNestingLevel(); }
+
+ break;
+
+ case 273:
+
+ {
+ (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermBlock), (yylsp[-5]));
+ context->decrSwitchNestingLevel();
+ }
+
+ break;
+
+ case 274:
+
+ {
+ (yyval.interm.intermCase) = context->addCase((yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
+ }
+
+ break;
+
+ case 275:
+
+ {
+ (yyval.interm.intermCase) = context->addDefault((yylsp[-1]));
+ }
+
+ break;
+
+ case 276:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermTypedNode);
+ context->checkIsScalarBool((yyvsp[0].interm.intermTypedNode)->getLine(), (yyvsp[0].interm.intermTypedNode));
+ }
+
+ break;
+
+ case 277:
+
+ {
+ (yyval.interm.intermNode) = context->addConditionInitializer((yyvsp[-3].interm.type), ImmutableString((yyvsp[-2].lex).string), (yyvsp[0].interm.intermTypedNode), (yylsp[-2]));
+ }
+
+ break;
+
+ case 278:
+
+ { context->symbolTable.push(); context->incrLoopNestingLevel(); }
+
+ break;
+
+ case 279:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
+ context->decrLoopNestingLevel();
+ }
+
+ break;
+
+ case 280:
+
+ { context->incrLoopNestingLevel(); }
+
+ break;
+
+ case 281:
+
+ {
+ (yyval.interm.intermNode) = context->addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
+ context->decrLoopNestingLevel();
+ }
+
+ break;
+
+ case 282:
+
+ { context->symbolTable.push(); context->incrLoopNestingLevel(); }
+
+ break;
+
+ case 283:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), (yyvsp[-2].interm.nodePair).node1, reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
+ context->decrLoopNestingLevel();
+ }
+
+ break;
+
+ case 284:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 285:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 286:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 287:
+
+ {
+ (yyval.interm.intermNode) = nullptr;
+ }
+
+ break;
+
+ case 288:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+
+ break;
+
+ case 289:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode);
+ }
+
+ break;
+
+ case 290:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1]));
+ }
+
+ break;
+
+ case 291:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1]));
+ }
+
+ break;
+
+ case 292:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1]));
+ }
+
+ break;
+
+ case 293:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
+ }
+
+ break;
+
+ case 294:
+
+ {
+ (yyval.interm.intermNode) = context->addBranch(EOpKill, (yylsp[-1]));
+ }
+
+ break;
+
+ case 295:
+
+ {
+ (yyval.interm.intermBlock) = new TIntermBlock();
+ (yyval.interm.intermBlock)->setLine((yyloc));
+ (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
+ context->setTreeRoot((yyval.interm.intermBlock));
+ }
+
+ break;
+
+ case 296:
+
+ {
+ (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
+ }
+
+ break;
+
+ case 297:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 298:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+ }
+
+ break;
+
+ case 299:
+
+ {
+ context->parseFunctionDefinitionHeader((yylsp[0]), (yyvsp[0].interm).function, &((yyvsp[0].interm).intermFunctionPrototype));
+ }
+
+ break;
+
+ case 300:
+
+ {
+ (yyval.interm.intermNode) = context->addFunctionDefinition((yyvsp[-2].interm).intermFunctionPrototype, (yyvsp[0].interm.intermBlock), (yylsp[-2]));
+ }
+
+ break;
+
+
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (&yylloc, context, scanner, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (&yylloc, context, scanner, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+ yyerror_range[1] = yylloc;
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, context, scanner);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ yyerror_range[1] = yylsp[1-yylen];
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, yylsp, context, scanner);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+ the lookahead. YYLOC is available though. */
+ YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
+ *++yylsp = yyloc;
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, context, scanner, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, context, scanner);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yylsp, context, scanner);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ return yyresult;
+}
+
+
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context, context->getScanner());
+}
diff --git a/gfx/angle/checkout/src/compiler/translator/glslang_tab.h b/gfx/angle/checkout/src/compiler/translator/glslang_tab.h
new file mode 100644
index 0000000000..5ffee8a4c5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/glslang_tab.h
@@ -0,0 +1,284 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED
+#define YY_YY_GLSLANG_TAB_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+/* "%code requires" blocks. */
+
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+#define YYLTYPE_IS_TRIVIAL 1
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+enum yytokentype
+{
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ UINT_TYPE = 268,
+ BREAK = 269,
+ CONTINUE = 270,
+ DO = 271,
+ ELSE = 272,
+ FOR = 273,
+ IF = 274,
+ DISCARD = 275,
+ RETURN = 276,
+ SWITCH = 277,
+ CASE = 278,
+ DEFAULT = 279,
+ BVEC2 = 280,
+ BVEC3 = 281,
+ BVEC4 = 282,
+ IVEC2 = 283,
+ IVEC3 = 284,
+ IVEC4 = 285,
+ VEC2 = 286,
+ VEC3 = 287,
+ VEC4 = 288,
+ UVEC2 = 289,
+ UVEC3 = 290,
+ UVEC4 = 291,
+ MATRIX2 = 292,
+ MATRIX3 = 293,
+ MATRIX4 = 294,
+ IN_QUAL = 295,
+ OUT_QUAL = 296,
+ INOUT_QUAL = 297,
+ UNIFORM = 298,
+ BUFFER = 299,
+ VARYING = 300,
+ MATRIX2x3 = 301,
+ MATRIX3x2 = 302,
+ MATRIX2x4 = 303,
+ MATRIX4x2 = 304,
+ MATRIX3x4 = 305,
+ MATRIX4x3 = 306,
+ CENTROID = 307,
+ FLAT = 308,
+ SMOOTH = 309,
+ READONLY = 310,
+ WRITEONLY = 311,
+ COHERENT = 312,
+ RESTRICT = 313,
+ VOLATILE = 314,
+ SHARED = 315,
+ STRUCT = 316,
+ VOID_TYPE = 317,
+ WHILE = 318,
+ SAMPLER2D = 319,
+ SAMPLERCUBE = 320,
+ SAMPLER_EXTERNAL_OES = 321,
+ SAMPLER2DRECT = 322,
+ SAMPLER2DARRAY = 323,
+ ISAMPLER2D = 324,
+ ISAMPLER3D = 325,
+ ISAMPLERCUBE = 326,
+ ISAMPLER2DARRAY = 327,
+ USAMPLER2D = 328,
+ USAMPLER3D = 329,
+ USAMPLERCUBE = 330,
+ USAMPLER2DARRAY = 331,
+ SAMPLER2DMS = 332,
+ ISAMPLER2DMS = 333,
+ USAMPLER2DMS = 334,
+ SAMPLER2DMSARRAY = 335,
+ ISAMPLER2DMSARRAY = 336,
+ USAMPLER2DMSARRAY = 337,
+ SAMPLER3D = 338,
+ SAMPLER3DRECT = 339,
+ SAMPLER2DSHADOW = 340,
+ SAMPLERCUBESHADOW = 341,
+ SAMPLER2DARRAYSHADOW = 342,
+ SAMPLEREXTERNAL2DY2YEXT = 343,
+ IMAGE2D = 344,
+ IIMAGE2D = 345,
+ UIMAGE2D = 346,
+ IMAGE3D = 347,
+ IIMAGE3D = 348,
+ UIMAGE3D = 349,
+ IMAGE2DARRAY = 350,
+ IIMAGE2DARRAY = 351,
+ UIMAGE2DARRAY = 352,
+ IMAGECUBE = 353,
+ IIMAGECUBE = 354,
+ UIMAGECUBE = 355,
+ ATOMICUINT = 356,
+ LAYOUT = 357,
+ YUVCSCSTANDARDEXT = 358,
+ YUVCSCSTANDARDEXTCONSTANT = 359,
+ IDENTIFIER = 360,
+ TYPE_NAME = 361,
+ FLOATCONSTANT = 362,
+ INTCONSTANT = 363,
+ UINTCONSTANT = 364,
+ BOOLCONSTANT = 365,
+ FIELD_SELECTION = 366,
+ LEFT_OP = 367,
+ RIGHT_OP = 368,
+ INC_OP = 369,
+ DEC_OP = 370,
+ LE_OP = 371,
+ GE_OP = 372,
+ EQ_OP = 373,
+ NE_OP = 374,
+ AND_OP = 375,
+ OR_OP = 376,
+ XOR_OP = 377,
+ MUL_ASSIGN = 378,
+ DIV_ASSIGN = 379,
+ ADD_ASSIGN = 380,
+ MOD_ASSIGN = 381,
+ LEFT_ASSIGN = 382,
+ RIGHT_ASSIGN = 383,
+ AND_ASSIGN = 384,
+ XOR_ASSIGN = 385,
+ OR_ASSIGN = 386,
+ SUB_ASSIGN = 387,
+ LEFT_PAREN = 388,
+ RIGHT_PAREN = 389,
+ LEFT_BRACKET = 390,
+ RIGHT_BRACKET = 391,
+ LEFT_BRACE = 392,
+ RIGHT_BRACE = 393,
+ DOT = 394,
+ COMMA = 395,
+ COLON = 396,
+ EQUAL = 397,
+ SEMICOLON = 398,
+ BANG = 399,
+ DASH = 400,
+ TILDE = 401,
+ PLUS = 402,
+ STAR = 403,
+ SLASH = 404,
+ PERCENT = 405,
+ LEFT_ANGLE = 406,
+ RIGHT_ANGLE = 407,
+ VERTICAL_BAR = 408,
+ CARET = 409,
+ AMPERSAND = 410,
+ QUESTION = 411
+};
+#endif
+
+/* Value type. */
+#if !defined YYSTYPE && !defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+
+ struct
+ {
+ union
+ {
+ const char *string; // pool allocated.
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ const TSymbol *symbol;
+ } lex;
+ struct
+ {
+ TOperator op;
+ union
+ {
+ TIntermNode *intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped *intermTypedNode;
+ TIntermAggregate *intermAggregate;
+ TIntermBlock *intermBlock;
+ TIntermDeclaration *intermDeclaration;
+ TIntermFunctionPrototype *intermFunctionPrototype;
+ TIntermSwitch *intermSwitch;
+ TIntermCase *intermCase;
+ };
+ union
+ {
+ TVector<unsigned int> *arraySizes;
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction *function;
+ TFunctionLookup *functionLookup;
+ TParameter param;
+ TDeclarator *declarator;
+ TDeclaratorList *declaratorList;
+ TFieldList *fieldList;
+ TQualifierWrapperBase *qualifierWrapper;
+ TTypeQualifierBuilder *typeQualifierBuilder;
+ };
+ } interm;
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type. */
+#if !defined YYLTYPE && !defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+int yyparse(TParseContext *context, void *scanner);
+
+#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */
diff --git a/gfx/angle/checkout/src/compiler/translator/length_limits.h b/gfx/angle/checkout/src/compiler/translator/length_limits.h
new file mode 100644
index 0000000000..fcda639d71
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/length_limits.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2011-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// length_limits.h
+//
+
+#ifndef COMPILER_TRANSLATOR_LENGTHLIMITS_H_
+#define COMPILER_TRANSLATOR_LENGTHLIMITS_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+// These constants are factored out from the rest of the headers to
+// make it easier to reference them from the compiler sources.
+
+namespace sh
+{
+
+size_t GetGlobalMaxTokenSize(ShShaderSpec spec);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp
new file mode 100644
index 0000000000..25a52983a3
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/AddAndTrueToLoopCondition.h"
+
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// An AST traverser that rewrites for and while loops by replacing "condition" with
+// "condition && true" to work around condition bug on Intel Mac.
+class AddAndTrueToLoopConditionTraverser : public TIntermTraverser
+{
+ public:
+ AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {}
+
+ bool visitLoop(Visit, TIntermLoop *loop) override
+ {
+ // do-while loop doesn't have this bug.
+ if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile)
+ {
+ return true;
+ }
+
+ // For loop may not have a condition.
+ if (loop->getCondition() == nullptr)
+ {
+ return true;
+ }
+
+ // Constant true.
+ TIntermTyped *trueValue = CreateBoolNode(true);
+
+ // CONDITION && true.
+ TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue);
+ loop->setCondition(andOp);
+
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void AddAndTrueToLoopCondition(TIntermNode *root)
+{
+ AddAndTrueToLoopConditionTraverser traverser;
+ root->traverse(&traverser);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h
new file mode 100644
index 0000000000..3a9efc2133
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Rewrite condition in for and while loops to work around driver bug on Intel Mac.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_ADDANDTRUETOLOOPCONDITION_H_
+#define COMPILER_TRANSLATOR_TREEOPS_ADDANDTRUETOLOOPCONDITION_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void AddAndTrueToLoopCondition(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_ADDANDTRUETOLOOPCONDITION_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp
new file mode 100644
index 0000000000..636ce37506
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// AddDefaultReturnStatements.cpp: Add default return statements to functions that do not end in a
+// return.
+//
+
+#include "compiler/translator/tree_ops/AddDefaultReturnStatements.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool NeedsReturnStatement(TIntermFunctionDefinition *node, TType *returnType)
+{
+ *returnType = node->getFunctionPrototype()->getType();
+ if (returnType->getBasicType() == EbtVoid)
+ {
+ return false;
+ }
+
+ TIntermBlock *bodyNode = node->getBody();
+ TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode();
+ if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+} // anonymous namespace
+
+void AddDefaultReturnStatements(TIntermBlock *root)
+{
+ TType returnType;
+ for (TIntermNode *node : *root->getSequence())
+ {
+ TIntermFunctionDefinition *definition = node->getAsFunctionDefinition();
+ if (definition != nullptr && NeedsReturnStatement(definition, &returnType))
+ {
+ TIntermBranch *branch = new TIntermBranch(EOpReturn, CreateZeroNode(returnType));
+
+ TIntermBlock *bodyNode = definition->getBody();
+ bodyNode->getSequence()->push_back(branch);
+ }
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h
new file mode 100644
index 0000000000..6d537978f5
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// AddDefaultReturnStatements.h: Add default return statements to functions that do not end in a
+// return.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_ADDDEFAULTRETURNSTATEMENTS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_ADDDEFAULTRETURNSTATEMENTS_H_
+
+class TIntermBlock;
+
+namespace sh
+{
+
+void AddDefaultReturnStatements(TIntermBlock *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_ADDDEFAULTRETURNSTATEMENTS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp
new file mode 100644
index 0000000000..824908b0e6
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp
@@ -0,0 +1,228 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The ArrayReturnValueToOutParameter function changes return values of an array type to out
+// parameters in function definitions, prototypes, and call sites.
+
+#include "compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h"
+
+#include <map>
+
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kReturnValueVariableName("angle_return");
+
+class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root, TSymbolTable *symbolTable);
+
+ private:
+ ArrayReturnValueToOutParameterTraverser(TSymbolTable *symbolTable);
+
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBranch(Visit visit, TIntermBranch *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ TIntermAggregate *createReplacementCall(TIntermAggregate *originalCall,
+ TIntermTyped *returnValueTarget);
+
+ // Set when traversal is inside a function with array return value.
+ TIntermFunctionDefinition *mFunctionWithArrayReturnValue;
+
+ struct ChangedFunction
+ {
+ const TVariable *returnValueVariable;
+ const TFunction *func;
+ };
+
+ // Map from function symbol ids to the changed function.
+ std::map<int, ChangedFunction> mChangedFunctions;
+};
+
+TIntermAggregate *ArrayReturnValueToOutParameterTraverser::createReplacementCall(
+ TIntermAggregate *originalCall,
+ TIntermTyped *returnValueTarget)
+{
+ TIntermSequence *replacementArguments = new TIntermSequence();
+ TIntermSequence *originalArguments = originalCall->getSequence();
+ for (auto &arg : *originalArguments)
+ {
+ replacementArguments->push_back(arg);
+ }
+ replacementArguments->push_back(returnValueTarget);
+ ASSERT(originalCall->getFunction());
+ const TSymbolUniqueId &originalId = originalCall->getFunction()->uniqueId();
+ TIntermAggregate *replacementCall = TIntermAggregate::CreateFunctionCall(
+ *mChangedFunctions[originalId.get()].func, replacementArguments);
+ replacementCall->setLine(originalCall->getLine());
+ return replacementCall;
+}
+
+void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam(symbolTable);
+ root->traverse(&arrayReturnValueToOutParam);
+ arrayReturnValueToOutParam.updateTree();
+}
+
+ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser(
+ TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable), mFunctionWithArrayReturnValue(nullptr)
+{}
+
+bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition(
+ Visit visit,
+ TIntermFunctionDefinition *node)
+{
+ if (node->getFunctionPrototype()->isArray() && visit == PreVisit)
+ {
+ // Replacing the function header is done on visitFunctionPrototype().
+ mFunctionWithArrayReturnValue = node;
+ }
+ if (visit == PostVisit)
+ {
+ mFunctionWithArrayReturnValue = nullptr;
+ }
+ return true;
+}
+
+void ArrayReturnValueToOutParameterTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ if (node->isArray())
+ {
+ // Replace the whole prototype node with another node that has the out parameter
+ // added. Also set the function to return void.
+ const TSymbolUniqueId &functionId = node->getFunction()->uniqueId();
+ if (mChangedFunctions.find(functionId.get()) == mChangedFunctions.end())
+ {
+ TType *returnValueVariableType = new TType(node->getType());
+ returnValueVariableType->setQualifier(EvqOut);
+ ChangedFunction changedFunction;
+ changedFunction.returnValueVariable =
+ new TVariable(mSymbolTable, kReturnValueVariableName, returnValueVariableType,
+ SymbolType::AngleInternal);
+ TFunction *func = new TFunction(mSymbolTable, node->getFunction()->name(),
+ node->getFunction()->symbolType(),
+ StaticType::GetBasic<EbtVoid>(), false);
+ for (size_t i = 0; i < node->getFunction()->getParamCount(); ++i)
+ {
+ func->addParameter(node->getFunction()->getParam(i));
+ }
+ func->addParameter(changedFunction.returnValueVariable);
+ changedFunction.func = func;
+ mChangedFunctions[functionId.get()] = changedFunction;
+ }
+ TIntermFunctionPrototype *replacement =
+ new TIntermFunctionPrototype(mChangedFunctions[functionId.get()].func);
+ replacement->setLine(node->getLine());
+
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ }
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ ASSERT(!node->isArray() || node->getOp() != EOpCallInternalRawFunction);
+ if (visit == PreVisit && node->isArray() && node->getOp() == EOpCallFunctionInAST)
+ {
+ // Handle call sites where the returned array is not assigned.
+ // Examples where f() is a function returning an array:
+ // 1. f();
+ // 2. another_array == f();
+ // 3. another_function(f());
+ // 4. return f();
+ // Cases 2 to 4 are already converted to simpler cases by
+ // SeparateExpressionsReturningArrays, so we only need to worry about the case where a
+ // function call returning an array forms an expression by itself.
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ if (parentBlock)
+ {
+ // replace
+ // f();
+ // with
+ // type s0[size]; f(s0);
+ TIntermSequence replacements;
+
+ // type s0[size];
+ TIntermDeclaration *returnValueDeclaration = nullptr;
+ TVariable *returnValue = DeclareTempVariable(mSymbolTable, new TType(node->getType()),
+ EvqTemporary, &returnValueDeclaration);
+ replacements.push_back(returnValueDeclaration);
+
+ // f(s0);
+ TIntermSymbol *returnValueSymbol = CreateTempSymbolNode(returnValue);
+ replacements.push_back(createReplacementCall(node, returnValueSymbol));
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
+ }
+ return false;
+ }
+ return true;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (mFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn)
+ {
+ // Instead of returning a value, assign to the out parameter and then return.
+ TIntermSequence replacements;
+
+ TIntermTyped *expression = node->getExpression();
+ ASSERT(expression != nullptr);
+ const TSymbolUniqueId &functionId =
+ mFunctionWithArrayReturnValue->getFunction()->uniqueId();
+ ASSERT(mChangedFunctions.find(functionId.get()) != mChangedFunctions.end());
+ TIntermSymbol *returnValueSymbol =
+ new TIntermSymbol(mChangedFunctions[functionId.get()].returnValueVariable);
+ TIntermBinary *replacementAssignment =
+ new TIntermBinary(EOpAssign, returnValueSymbol, expression);
+ replacementAssignment->setLine(expression->getLine());
+ replacements.push_back(replacementAssignment);
+
+ TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr);
+ replacementBranch->setLine(node->getLine());
+ replacements.push_back(replacementBranch);
+
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements));
+ }
+ return false;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (node->getOp() == EOpAssign && node->getLeft()->isArray())
+ {
+ TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
+ ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpCallInternalRawFunction);
+ if (rightAgg != nullptr && rightAgg->getOp() == EOpCallFunctionInAST)
+ {
+ TIntermAggregate *replacementCall = createReplacementCall(rightAgg, node->getLeft());
+ queueReplacement(replacementCall, OriginalNode::IS_DROPPED);
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ ArrayReturnValueToOutParameterTraverser::apply(root, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h
new file mode 100644
index 0000000000..9ceb02c76a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The ArrayReturnValueToOutParameter function changes return values of an array type to out
+// parameters in function definitions, prototypes and call sites.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_ARRAYRETURNVALUETOOUTPARAMETER_H_
+#define COMPILER_TRANSLATOR_TREEOPS_ARRAYRETURNVALUETOOUTPARAMETER_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_ARRAYRETURNVALUETOOUTPARAMETER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp
new file mode 100644
index 0000000000..19f53a7383
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp
@@ -0,0 +1,107 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
+// may record a variable as aliasing another. Sometimes the alias information gets garbled
+// so we work around this issue by breaking the aliasing chain in inner loops.
+
+#include "BreakVariableAliasingInInnerLoops.h"
+
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+// A HLSL compiler developer gave us more details on the root cause and the workaround needed:
+// The root problem is that if the HLSL compiler is applying aliasing information even on
+// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
+// that comes from a series of assignments, possibly with swizzled or ternary operators with
+// known conditionals, where the source is before the loop.
+// So, a workaround is to add a +0 term to variables the first time they are assigned to in
+// an inner loop (if they are declared in an outside scope, otherwise there is no need).
+// This will break the aliasing chain.
+
+// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
+// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
+// assignment don't need a workaround.
+
+namespace sh
+{
+
+namespace
+{
+
+class AliasingBreaker : public TIntermTraverser
+{
+ public:
+ AliasingBreaker() : TIntermTraverser(true, false, true) {}
+
+ protected:
+ bool visitBinary(Visit visit, TIntermBinary *binary)
+ {
+ if (visit != PreVisit)
+ {
+ return false;
+ }
+
+ if (mLoopLevel < 2 || !binary->isAssignment())
+ {
+ return true;
+ }
+
+ TIntermTyped *B = binary->getRight();
+ TType type = B->getType();
+
+ if (!type.isScalar() && !type.isVector() && !type.isMatrix())
+ {
+ return true;
+ }
+
+ if (type.isArray() || IsSampler(type.getBasicType()))
+ {
+ return true;
+ }
+
+ // We have a scalar / vector / matrix assignment with loop depth 2.
+ // Transform it from
+ // A = B
+ // to
+ // A = (B + typeof<B>(0));
+
+ TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, CreateZeroNode(type));
+ bPlusZero->setLine(B->getLine());
+
+ binary->replaceChildNode(B, bPlusZero);
+
+ return true;
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop)
+ {
+ if (visit == PreVisit)
+ {
+ mLoopLevel++;
+ }
+ else
+ {
+ ASSERT(mLoopLevel > 0);
+ mLoopLevel--;
+ }
+
+ return true;
+ }
+
+ private:
+ int mLoopLevel = 0;
+};
+
+} // anonymous namespace
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root)
+{
+ AliasingBreaker breaker;
+ root->traverse(&breaker);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h
new file mode 100644
index 0000000000..cdbdb7aa96
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
+// may record a variable as aliasing another. Sometimes the alias information gets garbled
+// so we work around this issue by breaking the aliasing chain in inner loops.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_BREAKVARIABLEALIASINGININNERLOOPS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_BREAKVARIABLEALIASINGININNERLOOPS_H_
+
+class TIntermNode;
+
+namespace sh
+{
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_BREAKVARIABLEALIASINGININNERLOOPS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp
new file mode 100644
index 0000000000..d721160a32
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp
@@ -0,0 +1,54 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClampFragDepth.cpp: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0].
+// The clamping is run at the very end of shader execution, and is only performed if the shader
+// statically accesses gl_FragDepth.
+//
+
+#include "compiler/translator/tree_ops/ClampFragDepth.h"
+
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+#include "compiler/translator/tree_util/FindSymbolNode.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
+
+namespace sh
+{
+
+void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ // Only clamp gl_FragDepth if it's used in the shader.
+ if (!FindSymbolNode(root, ImmutableString("gl_FragDepth")))
+ {
+ return;
+ }
+
+ TIntermSymbol *fragDepthNode = new TIntermSymbol(BuiltInVariable::gl_FragDepth());
+
+ TIntermTyped *minFragDepthNode = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+
+ TConstantUnion *maxFragDepthConstant = new TConstantUnion();
+ maxFragDepthConstant->setFConst(1.0);
+ TIntermConstantUnion *maxFragDepthNode =
+ new TIntermConstantUnion(maxFragDepthConstant, TType(EbtFloat, EbpHigh, EvqConst));
+
+ // clamp(gl_FragDepth, 0.0, 1.0)
+ TIntermSequence *clampArguments = new TIntermSequence();
+ clampArguments->push_back(fragDepthNode->deepCopy());
+ clampArguments->push_back(minFragDepthNode);
+ clampArguments->push_back(maxFragDepthNode);
+ TIntermTyped *clampedFragDepth =
+ CreateBuiltInFunctionCallNode("clamp", clampArguments, *symbolTable, 100);
+
+ // gl_FragDepth = clamp(gl_FragDepth, 0.0, 1.0)
+ TIntermBinary *assignFragDepth = new TIntermBinary(EOpAssign, fragDepthNode, clampedFragDepth);
+
+ RunAtTheEndOfShader(root, assignFragDepth, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h
new file mode 100644
index 0000000000..70d1f7336a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClampFragDepth.h: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0].
+// The clamping is run at the very end of shader execution, and is only performed if the shader
+// statically accesses gl_FragDepth.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_CLAMPFRAGDEPTH_H_
+#define COMPILER_TRANSLATOR_TREEOPS_CLAMPFRAGDEPTH_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_CLAMPFRAGDEPTH_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp
new file mode 100644
index 0000000000..3966aabd83
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClampPointSize.cpp: Limit the value that is written to gl_PointSize.
+//
+
+#include "compiler/translator/tree_ops/ClampPointSize.h"
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+#include "compiler/translator/tree_util/FindSymbolNode.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
+
+namespace sh
+{
+
+void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable)
+{
+ // Only clamp gl_PointSize if it's used in the shader.
+ if (!FindSymbolNode(root, ImmutableString("gl_PointSize")))
+ {
+ return;
+ }
+
+ TIntermSymbol *pointSizeNode = new TIntermSymbol(BuiltInVariable::gl_PointSize());
+
+ TConstantUnion *maxPointSizeConstant = new TConstantUnion();
+ maxPointSizeConstant->setFConst(maxPointSize);
+ TIntermConstantUnion *maxPointSizeNode =
+ new TIntermConstantUnion(maxPointSizeConstant, TType(EbtFloat, EbpHigh, EvqConst));
+
+ // min(gl_PointSize, maxPointSize)
+ TIntermSequence *minArguments = new TIntermSequence();
+ minArguments->push_back(pointSizeNode->deepCopy());
+ minArguments->push_back(maxPointSizeNode);
+ TIntermTyped *clampedPointSize =
+ CreateBuiltInFunctionCallNode("min", minArguments, *symbolTable, 100);
+
+ // gl_PointSize = min(gl_PointSize, maxPointSize)
+ TIntermBinary *assignPointSize = new TIntermBinary(EOpAssign, pointSizeNode, clampedPointSize);
+
+ RunAtTheEndOfShader(root, assignPointSize, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h
new file mode 100644
index 0000000000..5bc7cd4d43
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClampPointSize.h: Limit the value that is written to gl_PointSize.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_CLAMPPOINTSIZE_H_
+#define COMPILER_TRANSLATOR_TREEOPS_CLAMPPOINTSIZE_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_CLAMPPOINTSIZE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp
new file mode 100644
index 0000000000..91ffe5966a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp
@@ -0,0 +1,186 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Applies the necessary AST transformations to support multiview rendering through instancing.
+// Check the header file For more information.
+//
+
+#include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h"
+
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_ops/InitializeVariables.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+#include "compiler/translator/tree_util/FindMain.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kViewIDVariableName("ViewID_OVR");
+constexpr const ImmutableString kInstanceIDVariableName("InstanceID");
+constexpr const ImmutableString kMultiviewBaseViewLayerIndexVariableName(
+ "multiviewBaseViewLayerIndex");
+
+// Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence.
+void InitializeViewIDAndInstanceID(const TVariable *viewID,
+ const TVariable *instanceID,
+ unsigned numberOfViews,
+ const TSymbolTable &symbolTable,
+ TIntermSequence *initializers)
+{
+ // Create an unsigned numberOfViews node.
+ TConstantUnion *numberOfViewsUnsignedConstant = new TConstantUnion();
+ numberOfViewsUnsignedConstant->setUConst(numberOfViews);
+ TIntermConstantUnion *numberOfViewsUint =
+ new TIntermConstantUnion(numberOfViewsUnsignedConstant, TType(EbtUInt, EbpHigh, EvqConst));
+
+ // Create a uint(gl_InstanceID) node.
+ TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence();
+ glInstanceIDSymbolCastArguments->push_back(new TIntermSymbol(BuiltInVariable::gl_InstanceID()));
+ TIntermAggregate *glInstanceIDAsUint = TIntermAggregate::CreateConstructor(
+ TType(EbtUInt, EbpHigh, EvqTemporary), glInstanceIDSymbolCastArguments);
+
+ // Create a uint(gl_InstanceID) / numberOfViews node.
+ TIntermBinary *normalizedInstanceID =
+ new TIntermBinary(EOpDiv, glInstanceIDAsUint, numberOfViewsUint);
+
+ // Create an int(uint(gl_InstanceID) / numberOfViews) node.
+ TIntermSequence *normalizedInstanceIDCastArguments = new TIntermSequence();
+ normalizedInstanceIDCastArguments->push_back(normalizedInstanceID);
+ TIntermAggregate *normalizedInstanceIDAsInt = TIntermAggregate::CreateConstructor(
+ TType(EbtInt, EbpHigh, EvqTemporary), normalizedInstanceIDCastArguments);
+
+ // Create an InstanceID = int(uint(gl_InstanceID) / numberOfViews) node.
+ TIntermBinary *instanceIDInitializer =
+ new TIntermBinary(EOpAssign, new TIntermSymbol(instanceID), normalizedInstanceIDAsInt);
+ initializers->push_back(instanceIDInitializer);
+
+ // Create a uint(gl_InstanceID) % numberOfViews node.
+ TIntermBinary *normalizedViewID =
+ new TIntermBinary(EOpIMod, glInstanceIDAsUint->deepCopy(), numberOfViewsUint->deepCopy());
+
+ // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node.
+ TIntermBinary *viewIDInitializer =
+ new TIntermBinary(EOpAssign, new TIntermSymbol(viewID), normalizedViewID);
+ initializers->push_back(viewIDInitializer);
+}
+
+// Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is
+// added to the end of the initializers' sequence.
+void SelectViewIndexInVertexShader(const TVariable *viewID,
+ const TVariable *multiviewBaseViewLayerIndex,
+ TIntermSequence *initializers,
+ const TSymbolTable &symbolTable)
+{
+ // Create an int(ViewID_OVR) node.
+ TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence();
+ viewIDSymbolCastArguments->push_back(new TIntermSymbol(viewID));
+ TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor(
+ TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments);
+
+ // Create a gl_ViewportIndex node.
+ TIntermSymbol *viewportIndexSymbol = new TIntermSymbol(BuiltInVariable::gl_ViewportIndex());
+
+ // Create a { gl_ViewportIndex = int(ViewID_OVR) } node.
+ TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock();
+ viewportIndexInitializerInBlock->appendStatement(
+ new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt));
+
+ // Create a gl_Layer node.
+ TIntermSymbol *layerSymbol = new TIntermSymbol(BuiltInVariable::gl_LayerVS());
+
+ // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node
+ TIntermBinary *sumOfViewIDAndBaseViewIndex = new TIntermBinary(
+ EOpAdd, viewIDAsInt->deepCopy(), new TIntermSymbol(multiviewBaseViewLayerIndex));
+
+ // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node.
+ TIntermBlock *layerInitializerInBlock = new TIntermBlock();
+ layerInitializerInBlock->appendStatement(
+ new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex));
+
+ // Create a node to compare whether the base view index uniform is less than zero.
+ TIntermBinary *multiviewBaseViewLayerIndexZeroComparison =
+ new TIntermBinary(EOpLessThan, new TIntermSymbol(multiviewBaseViewLayerIndex),
+ CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst)));
+
+ // Create an if-else statement to select the code path.
+ TIntermIfElse *multiviewBranch =
+ new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison,
+ viewportIndexInitializerInBlock, layerInitializerInBlock);
+
+ initializers->push_back(multiviewBranch);
+}
+
+} // namespace
+
+void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
+ unsigned numberOfViews,
+ GLenum shaderType,
+ ShCompileOptions compileOptions,
+ ShShaderOutput shaderOutput,
+ TSymbolTable *symbolTable)
+{
+ ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER);
+
+ TQualifier viewIDQualifier = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn;
+ const TVariable *viewID =
+ new TVariable(symbolTable, kViewIDVariableName,
+ new TType(EbtUInt, EbpHigh, viewIDQualifier), SymbolType::AngleInternal);
+
+ DeclareGlobalVariable(root, viewID);
+ ReplaceVariable(root, BuiltInVariable::gl_ViewID_OVR(), viewID);
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of
+ // InstanceID and ViewID.
+ const TType *instanceIDVariableType = StaticType::Get<EbtInt, EbpHigh, EvqGlobal, 1, 1>();
+ const TVariable *instanceID =
+ new TVariable(symbolTable, kInstanceIDVariableName, instanceIDVariableType,
+ SymbolType::AngleInternal);
+ DeclareGlobalVariable(root, instanceID);
+ ReplaceVariable(root, BuiltInVariable::gl_InstanceID(), instanceID);
+
+ TIntermSequence *initializers = new TIntermSequence();
+ InitializeViewIDAndInstanceID(viewID, instanceID, numberOfViews, *symbolTable,
+ initializers);
+
+ // The AST transformation which adds the expression to select the viewport index should
+ // be done only for the GLSL and ESSL output.
+ const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u;
+ // Assert that if the view is selected in the vertex shader, then the output is
+ // either GLSL or ESSL.
+ ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput));
+ if (selectView)
+ {
+ // Add a uniform to switch between side-by-side and layered rendering.
+ const TType *baseLayerIndexVariableType =
+ StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
+ const TVariable *multiviewBaseViewLayerIndex =
+ new TVariable(symbolTable, kMultiviewBaseViewLayerIndexVariableName,
+ baseLayerIndexVariableType, SymbolType::AngleInternal);
+ DeclareGlobalVariable(root, multiviewBaseViewLayerIndex);
+
+ // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's
+ // initialization.
+ SelectViewIndexInVertexShader(viewID, multiviewBaseViewLayerIndex, initializers,
+ *symbolTable);
+ }
+
+ // Insert initializers at the beginning of main().
+ TIntermBlock *initializersBlock = new TIntermBlock();
+ initializersBlock->getSequence()->swap(*initializers);
+ TIntermBlock *mainBody = FindMainBody(root);
+ mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock);
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h
new file mode 100644
index 0000000000..9501ea58b3
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Regardless of the shader type, the following AST transformations are applied:
+// - Add declaration of View_ID_OVR.
+// - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and
+// declare it as a flat varying.
+//
+// If the shader type is a vertex shader, the following AST transformations are applied:
+// - Replace every occurrence of gl_InstanceID with InstanceID, mark InstanceID as internal and set
+// its qualifier to EvqTemporary.
+// - Add initializers of ViewID_OVR and InstanceID to the beginning of the body of main. The pass
+// should be executed before any variables get collected so that usage of gl_InstanceID is recorded.
+// - If the output is ESSL or GLSL and the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is
+// enabled, the expression
+// "if (multiviewBaseViewLayerIndex < 0) {
+// gl_ViewportIndex = int(ViewID_OVR);
+// } else {
+// gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex;
+// }"
+// is added after ViewID and InstanceID are initialized. Also, MultiviewRenderPath is added as a
+// uniform.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
+#define COMPILER_TRANSLATOR_TREEOPS_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "angle_gl.h"
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
+ unsigned numberOfViews,
+ GLenum shaderType,
+ ShCompileOptions compileOptions,
+ ShShaderOutput shaderOutput,
+ TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
new file mode 100644
index 0000000000..8f48d3e352
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
+// function that is called in the beginning of main(). This enables initialization of globals with
+// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
+// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
+// done after DeferGlobalInitializers is run. Note that it's important that the function definition
+// is at the end of the shader, as some globals may be declared after main().
+//
+// It can also initialize all uninitialized globals.
+//
+
+#include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
+
+#include <vector>
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_ops/InitializeVariables.h"
+#include "compiler/translator/tree_util/FindMain.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kInitGlobalsString("initGlobals");
+
+void GetDeferredInitializers(TIntermDeclaration *declaration,
+ bool initializeUninitializedGlobals,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *deferredInitializersOut,
+ std::vector<const TVariable *> *variablesToReplaceOut,
+ TSymbolTable *symbolTable)
+{
+ // SeparateDeclarations should have already been run.
+ ASSERT(declaration->getSequence()->size() == 1);
+
+ TIntermNode *declarator = declaration->getSequence()->back();
+ TIntermBinary *init = declarator->getAsBinaryNode();
+ if (init)
+ {
+ TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
+ ASSERT(symbolNode);
+ TIntermTyped *expression = init->getRight();
+
+ if (expression->getQualifier() != EvqConst || !expression->hasConstantValue())
+ {
+ // For variables which are not constant, defer their real initialization until
+ // after we initialize uniforms.
+ // Deferral is done also in any cases where the variable can not be converted to a
+ // constant union, since otherwise there's a chance that HLSL output will generate extra
+ // statements from the initializer expression.
+
+ // Change const global to a regular global if its initialization is deferred.
+ // This can happen if ANGLE has not been able to fold the constant expression used
+ // as an initializer.
+ ASSERT(symbolNode->getQualifier() == EvqConst ||
+ symbolNode->getQualifier() == EvqGlobal);
+ if (symbolNode->getQualifier() == EvqConst)
+ {
+ variablesToReplaceOut->push_back(&symbolNode->variable());
+ }
+
+ TIntermBinary *deferredInit =
+ new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
+ deferredInitializersOut->push_back(deferredInit);
+
+ // Remove the initializer from the global scope and just declare the global instead.
+ declaration->replaceChildNode(init, symbolNode);
+ }
+ }
+ else if (initializeUninitializedGlobals)
+ {
+ TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
+ ASSERT(symbolNode);
+
+ // Ignore ANGLE internal variables and nameless declarations.
+ if (symbolNode->variable().symbolType() == SymbolType::AngleInternal ||
+ symbolNode->variable().symbolType() == SymbolType::Empty)
+ return;
+
+ if (symbolNode->getQualifier() == EvqGlobal)
+ {
+ TIntermSequence *initCode = CreateInitCode(symbolNode, canUseLoopsToInitialize,
+ highPrecisionSupported, symbolTable);
+ deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(),
+ initCode->end());
+ }
+ }
+}
+
+void InsertInitCallToMain(TIntermBlock *root,
+ TIntermSequence *deferredInitializers,
+ TSymbolTable *symbolTable)
+{
+ TIntermBlock *initGlobalsBlock = new TIntermBlock();
+ initGlobalsBlock->getSequence()->swap(*deferredInitializers);
+
+ TFunction *initGlobalsFunction =
+ new TFunction(symbolTable, kInitGlobalsString, SymbolType::AngleInternal,
+ StaticType::GetBasic<EbtVoid>(), false);
+
+ TIntermFunctionPrototype *initGlobalsFunctionPrototype =
+ CreateInternalFunctionPrototypeNode(*initGlobalsFunction);
+ root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype);
+ TIntermFunctionDefinition *initGlobalsFunctionDefinition =
+ CreateInternalFunctionDefinitionNode(*initGlobalsFunction, initGlobalsBlock);
+ root->appendStatement(initGlobalsFunctionDefinition);
+
+ TIntermAggregate *initGlobalsCall =
+ TIntermAggregate::CreateFunctionCall(*initGlobalsFunction, new TIntermSequence());
+
+ TIntermBlock *mainBody = FindMainBody(root);
+ mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall);
+}
+
+} // namespace
+
+void DeferGlobalInitializers(TIntermBlock *root,
+ bool initializeUninitializedGlobals,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TSymbolTable *symbolTable)
+{
+ TIntermSequence *deferredInitializers = new TIntermSequence();
+ std::vector<const TVariable *> variablesToReplace;
+
+ // Loop over all global statements and process the declarations. This is simpler than using a
+ // traverser.
+ for (TIntermNode *statement : *root->getSequence())
+ {
+ TIntermDeclaration *declaration = statement->getAsDeclarationNode();
+ if (declaration)
+ {
+ GetDeferredInitializers(declaration, initializeUninitializedGlobals,
+ canUseLoopsToInitialize, highPrecisionSupported,
+ deferredInitializers, &variablesToReplace, symbolTable);
+ }
+ }
+
+ // Add the function with initialization and the call to that.
+ if (!deferredInitializers->empty())
+ {
+ InsertInitCallToMain(root, deferredInitializers, symbolTable);
+ }
+
+ // Replace constant variables with non-constant global variables.
+ for (const TVariable *var : variablesToReplace)
+ {
+ TType *replacementType = new TType(var->getType());
+ replacementType->setQualifier(EvqGlobal);
+ TVariable *replacement =
+ new TVariable(symbolTable, var->name(), replacementType, var->symbolType());
+ ReplaceVariable(root, var, replacement);
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h
new file mode 100644
index 0000000000..b0e4547857
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
+// function that is called in the beginning of main(). This enables initialization of globals with
+// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
+// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
+// done after DeferGlobalInitializers is run. Note that it's important that the function definition
+// is at the end of the shader, as some globals may be declared after main().
+//
+// It can also initialize all uninitialized globals.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_DEFERGLOBALINITIALIZERS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_DEFERGLOBALINITIALIZERS_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void DeferGlobalInitializers(TIntermBlock *root,
+ bool initializeUninitializedGlobals,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_DEFERGLOBALINITIALIZERS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp
new file mode 100644
index 0000000000..d562136999
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp
@@ -0,0 +1,131 @@
+//
+// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// gl_FragColor needs to broadcast to all color buffers in ES2 if
+// GL_EXT_draw_buffers is explicitly enabled in a fragment shader.
+//
+// We emulate this by replacing all gl_FragColor with gl_FragData[0], and in the end
+// of main() function, assigning gl_FragData[1], ..., gl_FragData[maxDrawBuffers-1]
+// with gl_FragData[0].
+//
+
+#include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h"
+
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kGlFragDataString("gl_FragData");
+
+class GLFragColorBroadcastTraverser : public TIntermTraverser
+{
+ public:
+ GLFragColorBroadcastTraverser(int maxDrawBuffers, TSymbolTable *symbolTable, int shaderVersion)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mGLFragColorUsed(false),
+ mMaxDrawBuffers(maxDrawBuffers),
+ mShaderVersion(shaderVersion)
+ {}
+
+ void broadcastGLFragColor(TIntermBlock *root);
+
+ bool isGLFragColorUsed() const { return mGLFragColorUsed; }
+
+ protected:
+ void visitSymbol(TIntermSymbol *node) override;
+
+ TIntermBinary *constructGLFragDataNode(int index) const;
+ TIntermBinary *constructGLFragDataAssignNode(int index) const;
+
+ private:
+ bool mGLFragColorUsed;
+ int mMaxDrawBuffers;
+ const int mShaderVersion;
+};
+
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const
+{
+ TIntermSymbol *symbol =
+ ReferenceBuiltInVariable(kGlFragDataString, *mSymbolTable, mShaderVersion);
+ TIntermTyped *indexNode = CreateIndexNode(index);
+
+ TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode);
+ return binary;
+}
+
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const
+{
+ TIntermTyped *fragDataIndex = constructGLFragDataNode(index);
+ TIntermTyped *fragDataZero = constructGLFragDataNode(0);
+
+ return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero);
+}
+
+void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
+{
+ if (node->variable().symbolType() == SymbolType::BuiltIn && node->getName() == "gl_FragColor")
+ {
+ queueReplacement(constructGLFragDataNode(0), OriginalNode::IS_DROPPED);
+ mGLFragColorUsed = true;
+ }
+}
+
+void GLFragColorBroadcastTraverser::broadcastGLFragColor(TIntermBlock *root)
+{
+ ASSERT(mMaxDrawBuffers > 1);
+ if (!mGLFragColorUsed)
+ {
+ return;
+ }
+
+ TIntermBlock *broadcastBlock = new TIntermBlock();
+ // Now insert statements
+ // gl_FragData[1] = gl_FragData[0];
+ // ...
+ // gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
+ for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
+ {
+ broadcastBlock->appendStatement(constructGLFragDataAssignNode(colorIndex));
+ }
+ RunAtTheEndOfShader(root, broadcastBlock, mSymbolTable);
+}
+
+} // namespace
+
+void EmulateGLFragColorBroadcast(TIntermBlock *root,
+ int maxDrawBuffers,
+ std::vector<sh::OutputVariable> *outputVariables,
+ TSymbolTable *symbolTable,
+ int shaderVersion)
+{
+ ASSERT(maxDrawBuffers > 1);
+ GLFragColorBroadcastTraverser traverser(maxDrawBuffers, symbolTable, shaderVersion);
+ root->traverse(&traverser);
+ if (traverser.isGLFragColorUsed())
+ {
+ traverser.updateTree();
+ traverser.broadcastGLFragColor(root);
+ for (auto &var : *outputVariables)
+ {
+ if (var.name == "gl_FragColor")
+ {
+ // TODO(zmo): Find a way to keep the original variable information.
+ var.name = "gl_FragData";
+ var.mappedName = "gl_FragData";
+ var.arraySizes.push_back(maxDrawBuffers);
+ ASSERT(var.arraySizes.size() == 1u);
+ }
+ }
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h
new file mode 100644
index 0000000000..f6bf549bac
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Emulate gl_FragColor broadcast behaviors in ES2 where
+// GL_EXT_draw_buffers is explicitly enabled in a fragment shader.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_EMULATEGLFRAGCOLORBROADCAST_H_
+#define COMPILER_TRANSLATOR_TREEOPS_EMULATEGLFRAGCOLORBROADCAST_H_
+
+#include <vector>
+
+namespace sh
+{
+struct OutputVariable;
+class TIntermBlock;
+class TSymbolTable;
+
+// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function,
+// assign gl_FragData[1] ... gl_FragData[maxDrawBuffers - 1] with gl_FragData[0].
+// If gl_FragColor is in outputVariables, it is replaced by gl_FragData.
+void EmulateGLFragColorBroadcast(TIntermBlock *root,
+ int maxDrawBuffers,
+ std::vector<OutputVariable> *outputVariables,
+ TSymbolTable *symbolTable,
+ int shaderVersion);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_EMULATEGLFRAGCOLORBROADCAST_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp
new file mode 100644
index 0000000000..8134ea79c3
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp
@@ -0,0 +1,213 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// EmulateGLDrawID is an AST traverser to convert the gl_DrawID builtin
+// to a uniform int
+//
+// EmulateGLBaseVertex is an AST traverser to convert the gl_BaseVertex builtin
+// to a uniform int
+//
+// EmulateGLBaseInstance is an AST traverser to convert the gl_BaseInstance builtin
+// to a uniform int
+//
+
+#include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kEmulatedGLDrawIDName("angle_DrawID");
+
+class FindGLDrawIDTraverser : public TIntermTraverser
+{
+ public:
+ FindGLDrawIDTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {}
+
+ const TVariable *getGLDrawIDBuiltinVariable() { return mVariable; }
+
+ protected:
+ void visitSymbol(TIntermSymbol *node) override
+ {
+ if (&node->variable() == BuiltInVariable::gl_DrawID() ||
+ &node->variable() == BuiltInVariable::gl_DrawIDESSL1())
+ {
+ mVariable = &node->variable();
+ }
+ }
+
+ private:
+ const TVariable *mVariable;
+};
+
+constexpr const ImmutableString kEmulatedGLBaseVertexName("angle_BaseVertex");
+
+class FindGLBaseVertexTraverser : public TIntermTraverser
+{
+ public:
+ FindGLBaseVertexTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {}
+
+ const TVariable *getGLBaseVertexBuiltinVariable() { return mVariable; }
+
+ protected:
+ void visitSymbol(TIntermSymbol *node) override
+ {
+ if (&node->variable() == BuiltInVariable::gl_BaseVertex())
+ {
+ mVariable = &node->variable();
+ }
+ }
+
+ private:
+ const TVariable *mVariable;
+};
+
+constexpr const ImmutableString kEmulatedGLBaseInstanceName("angle_BaseInstance");
+
+class FindGLBaseInstanceTraverser : public TIntermTraverser
+{
+ public:
+ FindGLBaseInstanceTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {}
+
+ const TVariable *getGLBaseInstanceBuiltinVariable() { return mVariable; }
+
+ protected:
+ void visitSymbol(TIntermSymbol *node) override
+ {
+ if (&node->variable() == BuiltInVariable::gl_BaseInstance())
+ {
+ mVariable = &node->variable();
+ }
+ }
+
+ private:
+ const TVariable *mVariable;
+};
+
+} // namespace
+
+void EmulateGLDrawID(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ std::vector<sh::Uniform> *uniforms,
+ bool shouldCollect)
+{
+ FindGLDrawIDTraverser traverser;
+ root->traverse(&traverser);
+ const TVariable *builtInVariable = traverser.getGLDrawIDBuiltinVariable();
+ if (builtInVariable)
+ {
+ const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
+ const TVariable *drawID =
+ new TVariable(symbolTable, kEmulatedGLDrawIDName, type, SymbolType::AngleInternal);
+
+ // AngleInternal variables don't get collected
+ if (shouldCollect)
+ {
+ Uniform uniform;
+ uniform.name = kEmulatedGLDrawIDName.data();
+ uniform.mappedName = kEmulatedGLDrawIDName.data();
+ uniform.type = GLVariableType(*type);
+ uniform.precision = GLVariablePrecision(*type);
+ uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable);
+ uniform.active = true;
+ uniform.binding = type->getLayoutQualifier().binding;
+ uniform.location = type->getLayoutQualifier().location;
+ uniform.offset = type->getLayoutQualifier().offset;
+ uniform.readonly = type->getMemoryQualifier().readonly;
+ uniform.writeonly = type->getMemoryQualifier().writeonly;
+ uniforms->push_back(uniform);
+ }
+
+ DeclareGlobalVariable(root, drawID);
+ ReplaceVariable(root, builtInVariable, drawID);
+ }
+}
+
+void EmulateGLBaseVertex(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ std::vector<sh::Uniform> *uniforms,
+ bool shouldCollect)
+{
+ FindGLBaseVertexTraverser traverser;
+ root->traverse(&traverser);
+ const TVariable *builtInVariable = traverser.getGLBaseVertexBuiltinVariable();
+ if (builtInVariable)
+ {
+ const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
+ const TVariable *baseVertex =
+ new TVariable(symbolTable, kEmulatedGLBaseVertexName, type, SymbolType::AngleInternal);
+
+ // AngleInternal variables don't get collected
+ if (shouldCollect)
+ {
+ Uniform uniform;
+ uniform.name = kEmulatedGLBaseVertexName.data();
+ uniform.mappedName = kEmulatedGLBaseVertexName.data();
+ uniform.type = GLVariableType(*type);
+ uniform.precision = GLVariablePrecision(*type);
+ uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable);
+ uniform.active = true;
+ uniform.binding = type->getLayoutQualifier().binding;
+ uniform.location = type->getLayoutQualifier().location;
+ uniform.offset = type->getLayoutQualifier().offset;
+ uniform.readonly = type->getMemoryQualifier().readonly;
+ uniform.writeonly = type->getMemoryQualifier().writeonly;
+ uniforms->push_back(uniform);
+ }
+
+ DeclareGlobalVariable(root, baseVertex);
+ ReplaceVariable(root, builtInVariable, baseVertex);
+ }
+}
+
+void EmulateGLBaseInstance(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ std::vector<sh::Uniform> *uniforms,
+ bool shouldCollect)
+{
+ FindGLBaseInstanceTraverser traverser;
+ root->traverse(&traverser);
+ const TVariable *builtInVariable = traverser.getGLBaseInstanceBuiltinVariable();
+ if (builtInVariable)
+ {
+ const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
+ const TVariable *baseInstance = new TVariable(symbolTable, kEmulatedGLBaseInstanceName,
+ type, SymbolType::AngleInternal);
+
+ // AngleInternal variables don't get collected
+ if (shouldCollect)
+ {
+ Uniform uniform;
+ uniform.name = kEmulatedGLBaseInstanceName.data();
+ uniform.mappedName = kEmulatedGLBaseInstanceName.data();
+ uniform.type = GLVariableType(*type);
+ uniform.precision = GLVariablePrecision(*type);
+ uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable);
+ uniform.active = true;
+ uniform.binding = type->getLayoutQualifier().binding;
+ uniform.location = type->getLayoutQualifier().location;
+ uniform.offset = type->getLayoutQualifier().offset;
+ uniform.readonly = type->getMemoryQualifier().readonly;
+ uniform.writeonly = type->getMemoryQualifier().writeonly;
+ uniforms->push_back(uniform);
+ }
+
+ DeclareGlobalVariable(root, baseInstance);
+ ReplaceVariable(root, builtInVariable, baseInstance);
+ }
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h
new file mode 100644
index 0000000000..8134db9873
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h
@@ -0,0 +1,47 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// EmulateGLDrawID is an AST traverser to convert the gl_DrawID builtin
+// to a uniform int
+//
+// EmulateGLBaseVertex is an AST traverser to convert the gl_BaseVertex builtin
+// to a uniform int
+//
+// EmulateGLBaseInstance is an AST traverser to convert the gl_BaseInstance builtin
+// to a uniform int
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_EMULATEMULTIDRAWSHADERBUILTINS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_EMULATEMULTIDRAWSHADERBUILTINS_H_
+
+#include <GLSLANG/ShaderLang.h>
+#include <vector>
+
+#include "compiler/translator/HashNames.h"
+
+namespace sh
+{
+struct Uniform;
+class TIntermBlock;
+class TSymbolTable;
+
+void EmulateGLDrawID(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ std::vector<sh::Uniform> *uniforms,
+ bool shouldCollect);
+
+void EmulateGLBaseVertex(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ std::vector<sh::Uniform> *uniforms,
+ bool shouldCollect);
+
+void EmulateGLBaseInstance(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ std::vector<sh::Uniform> *uniforms,
+ bool shouldCollect);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_EMULATEMULTIDRAWSHADERBUILTINS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp
new file mode 100644
index 0000000000..ba19bd112e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp
@@ -0,0 +1,776 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/EmulatePrecision.h"
+
+#include "compiler/translator/FunctionLookup.h"
+
+#include <memory>
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kParamXName("x");
+constexpr const ImmutableString kParamYName("y");
+constexpr const ImmutableString kAngleFrmString("angle_frm");
+constexpr const ImmutableString kAngleFrlString("angle_frl");
+
+class RoundingHelperWriter : angle::NonCopyable
+{
+ public:
+ static RoundingHelperWriter *createHelperWriter(const ShShaderOutput outputLanguage);
+
+ void writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion);
+ void writeCompoundAssignmentHelper(TInfoSinkBase &sink,
+ const char *lType,
+ const char *rType,
+ const char *opStr,
+ const char *opNameStr);
+
+ virtual ~RoundingHelperWriter() {}
+
+ protected:
+ RoundingHelperWriter(const ShShaderOutput outputLanguage) : mOutputLanguage(outputLanguage) {}
+ RoundingHelperWriter() = delete;
+
+ const ShShaderOutput mOutputLanguage;
+
+ private:
+ virtual std::string getTypeString(const char *glslType) = 0;
+ virtual void writeFloatRoundingHelpers(TInfoSinkBase &sink) = 0;
+ virtual void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) = 0;
+ virtual void writeMatrixRoundingHelper(TInfoSinkBase &sink,
+ const unsigned int columns,
+ const unsigned int rows,
+ const char *functionName) = 0;
+};
+
+class RoundingHelperWriterGLSL : public RoundingHelperWriter
+{
+ public:
+ RoundingHelperWriterGLSL(const ShShaderOutput outputLanguage)
+ : RoundingHelperWriter(outputLanguage)
+ {}
+
+ private:
+ std::string getTypeString(const char *glslType) override;
+ void writeFloatRoundingHelpers(TInfoSinkBase &sink) override;
+ void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override;
+ void writeMatrixRoundingHelper(TInfoSinkBase &sink,
+ const unsigned int columns,
+ const unsigned int rows,
+ const char *functionName) override;
+};
+
+class RoundingHelperWriterESSL : public RoundingHelperWriterGLSL
+{
+ public:
+ RoundingHelperWriterESSL(const ShShaderOutput outputLanguage)
+ : RoundingHelperWriterGLSL(outputLanguage)
+ {}
+
+ private:
+ std::string getTypeString(const char *glslType) override;
+};
+
+class RoundingHelperWriterHLSL : public RoundingHelperWriter
+{
+ public:
+ RoundingHelperWriterHLSL(const ShShaderOutput outputLanguage)
+ : RoundingHelperWriter(outputLanguage)
+ {}
+
+ private:
+ std::string getTypeString(const char *glslType) override;
+ void writeFloatRoundingHelpers(TInfoSinkBase &sink) override;
+ void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override;
+ void writeMatrixRoundingHelper(TInfoSinkBase &sink,
+ const unsigned int columns,
+ const unsigned int rows,
+ const char *functionName) override;
+};
+
+RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage)
+{
+ ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage));
+ switch (outputLanguage)
+ {
+ case SH_HLSL_4_1_OUTPUT:
+ return new RoundingHelperWriterHLSL(outputLanguage);
+ case SH_ESSL_OUTPUT:
+ return new RoundingHelperWriterESSL(outputLanguage);
+ default:
+ return new RoundingHelperWriterGLSL(outputLanguage);
+ }
+}
+
+void RoundingHelperWriter::writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion)
+{
+ // Write the angle_frm functions that round floating point numbers to
+ // half precision, and angle_frl functions that round them to minimum lowp
+ // precision.
+
+ writeFloatRoundingHelpers(sink);
+ writeVectorRoundingHelpers(sink, 2);
+ writeVectorRoundingHelpers(sink, 3);
+ writeVectorRoundingHelpers(sink, 4);
+ if (shaderVersion > 100)
+ {
+ for (unsigned int columns = 2; columns <= 4; ++columns)
+ {
+ for (unsigned int rows = 2; rows <= 4; ++rows)
+ {
+ writeMatrixRoundingHelper(sink, columns, rows, "angle_frm");
+ writeMatrixRoundingHelper(sink, columns, rows, "angle_frl");
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int size = 2; size <= 4; ++size)
+ {
+ writeMatrixRoundingHelper(sink, size, size, "angle_frm");
+ writeMatrixRoundingHelper(sink, size, size, "angle_frl");
+ }
+ }
+}
+
+void RoundingHelperWriter::writeCompoundAssignmentHelper(TInfoSinkBase &sink,
+ const char *lType,
+ const char *rType,
+ const char *opStr,
+ const char *opNameStr)
+{
+ std::string lTypeStr = getTypeString(lType);
+ std::string rTypeStr = getTypeString(rType);
+
+ // Note that y should be passed through angle_frm at the function call site,
+ // but x can't be passed through angle_frm there since it is an inout parameter.
+ // So only pass x and the result through angle_frm here.
+ // clang-format off
+ sink <<
+ lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n"
+ " x = angle_frm(angle_frm(x) " << opStr << " y);\n"
+ " return x;\n"
+ "}\n";
+ sink <<
+ lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n"
+ " x = angle_frl(angle_frl(x) " << opStr << " y);\n"
+ " return x;\n"
+ "}\n";
+ // clang-format on
+}
+
+std::string RoundingHelperWriterGLSL::getTypeString(const char *glslType)
+{
+ return glslType;
+}
+
+std::string RoundingHelperWriterESSL::getTypeString(const char *glslType)
+{
+ std::stringstream typeStrStr = sh::InitializeStream<std::stringstream>();
+ typeStrStr << "highp " << glslType;
+ return typeStrStr.str();
+}
+
+void RoundingHelperWriterGLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink)
+{
+ // Unoptimized version of angle_frm for single floats:
+ //
+ // int webgl_maxNormalExponent(in int exponentBits)
+ // {
+ // int possibleExponents = int(exp2(float(exponentBits)));
+ // int exponentBias = possibleExponents / 2 - 1;
+ // int allExponentBitsOne = possibleExponents - 1;
+ // return (allExponentBitsOne - 1) - exponentBias;
+ // }
+ //
+ // float angle_frm(in float x)
+ // {
+ // int mantissaBits = 10;
+ // int exponentBits = 5;
+ // float possibleMantissas = exp2(float(mantissaBits));
+ // float mantissaMax = 2.0 - 1.0 / possibleMantissas;
+ // int maxNE = webgl_maxNormalExponent(exponentBits);
+ // float max = exp2(float(maxNE)) * mantissaMax;
+ // if (x > max)
+ // {
+ // return max;
+ // }
+ // if (x < -max)
+ // {
+ // return -max;
+ // }
+ // float exponent = floor(log2(abs(x)));
+ // if (abs(x) == 0.0 || exponent < -float(maxNE))
+ // {
+ // return 0.0 * sign(x)
+ // }
+ // x = x * exp2(-(exponent - float(mantissaBits)));
+ // x = sign(x) * floor(abs(x));
+ // return x * exp2(exponent - float(mantissaBits));
+ // }
+
+ // All numbers with a magnitude less than 2^-15 are subnormal, and are
+ // flushed to zero.
+
+ // Note the constant numbers below:
+ // a) 65504 is the maximum possible mantissa (1.1111111111 in binary) times
+ // 2^15, the maximum normal exponent.
+ // b) 10.0 is the number of mantissa bits.
+ // c) -25.0 is the minimum normal half-float exponent -15.0 minus the number
+ // of mantissa bits.
+ // d) + 1e-30 is to make sure the argument of log2() won't be zero. It can
+ // only affect the result of log2 on x where abs(x) < 1e-22. Since these
+ // numbers will be flushed to zero either way (2^-15 is the smallest
+ // normal positive number), this does not introduce any error.
+
+ std::string floatType = getTypeString("float");
+
+ // clang-format off
+ sink <<
+ floatType << " angle_frm(in " << floatType << " x) {\n"
+ " x = clamp(x, -65504.0, 65504.0);\n"
+ " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n"
+ " bool isNonZero = (exponent >= -25.0);\n"
+ " x = x * exp2(-exponent);\n"
+ " x = sign(x) * floor(abs(x));\n"
+ " return x * exp2(exponent) * float(isNonZero);\n"
+ "}\n";
+
+ sink <<
+ floatType << " angle_frl(in " << floatType << " x) {\n"
+ " x = clamp(x, -2.0, 2.0);\n"
+ " x = x * 256.0;\n"
+ " x = sign(x) * floor(abs(x));\n"
+ " return x * 0.00390625;\n"
+ "}\n";
+ // clang-format on
+}
+
+void RoundingHelperWriterGLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink,
+ const unsigned int size)
+{
+ std::stringstream vecTypeStrStr = sh::InitializeStream<std::stringstream>();
+ vecTypeStrStr << "vec" << size;
+ std::string vecType = getTypeString(vecTypeStrStr.str().c_str());
+
+ // clang-format off
+ sink <<
+ vecType << " angle_frm(in " << vecType << " v) {\n"
+ " v = clamp(v, -65504.0, 65504.0);\n"
+ " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n"
+ " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n"
+ " v = v * exp2(-exponent);\n"
+ " v = sign(v) * floor(abs(v));\n"
+ " return v * exp2(exponent) * vec" << size << "(isNonZero);\n"
+ "}\n";
+
+ sink <<
+ vecType << " angle_frl(in " << vecType << " v) {\n"
+ " v = clamp(v, -2.0, 2.0);\n"
+ " v = v * 256.0;\n"
+ " v = sign(v) * floor(abs(v));\n"
+ " return v * 0.00390625;\n"
+ "}\n";
+ // clang-format on
+}
+
+void RoundingHelperWriterGLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink,
+ const unsigned int columns,
+ const unsigned int rows,
+ const char *functionName)
+{
+ std::stringstream matTypeStrStr = sh::InitializeStream<std::stringstream>();
+ matTypeStrStr << "mat" << columns;
+ if (rows != columns)
+ {
+ matTypeStrStr << "x" << rows;
+ }
+ std::string matType = getTypeString(matTypeStrStr.str().c_str());
+
+ sink << matType << " " << functionName << "(in " << matType << " m) {\n"
+ << " " << matType << " rounded;\n";
+
+ for (unsigned int i = 0; i < columns; ++i)
+ {
+ sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
+ }
+
+ sink << " return rounded;\n"
+ "}\n";
+}
+
+static const char *GetHLSLTypeStr(const char *floatTypeStr)
+{
+ if (strcmp(floatTypeStr, "float") == 0)
+ {
+ return "float";
+ }
+ if (strcmp(floatTypeStr, "vec2") == 0)
+ {
+ return "float2";
+ }
+ if (strcmp(floatTypeStr, "vec3") == 0)
+ {
+ return "float3";
+ }
+ if (strcmp(floatTypeStr, "vec4") == 0)
+ {
+ return "float4";
+ }
+ if (strcmp(floatTypeStr, "mat2") == 0)
+ {
+ return "float2x2";
+ }
+ if (strcmp(floatTypeStr, "mat3") == 0)
+ {
+ return "float3x3";
+ }
+ if (strcmp(floatTypeStr, "mat4") == 0)
+ {
+ return "float4x4";
+ }
+ if (strcmp(floatTypeStr, "mat2x3") == 0)
+ {
+ return "float2x3";
+ }
+ if (strcmp(floatTypeStr, "mat2x4") == 0)
+ {
+ return "float2x4";
+ }
+ if (strcmp(floatTypeStr, "mat3x2") == 0)
+ {
+ return "float3x2";
+ }
+ if (strcmp(floatTypeStr, "mat3x4") == 0)
+ {
+ return "float3x4";
+ }
+ if (strcmp(floatTypeStr, "mat4x2") == 0)
+ {
+ return "float4x2";
+ }
+ if (strcmp(floatTypeStr, "mat4x3") == 0)
+ {
+ return "float4x3";
+ }
+ UNREACHABLE();
+ return nullptr;
+}
+
+std::string RoundingHelperWriterHLSL::getTypeString(const char *glslType)
+{
+ return GetHLSLTypeStr(glslType);
+}
+
+void RoundingHelperWriterHLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink)
+{
+ // In HLSL scalars are the same as 1-vectors.
+ writeVectorRoundingHelpers(sink, 1);
+}
+
+void RoundingHelperWriterHLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink,
+ const unsigned int size)
+{
+ std::stringstream vecTypeStrStr = sh::InitializeStream<std::stringstream>();
+ vecTypeStrStr << "float" << size;
+ std::string vecType = vecTypeStrStr.str();
+
+ // clang-format off
+ sink <<
+ vecType << " angle_frm(" << vecType << " v) {\n"
+ " v = clamp(v, -65504.0, 65504.0);\n"
+ " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n"
+ " bool" << size << " isNonZero = exponent < -25.0;\n"
+ " v = v * exp2(-exponent);\n"
+ " v = sign(v) * floor(abs(v));\n"
+ " return v * exp2(exponent) * (float" << size << ")(isNonZero);\n"
+ "}\n";
+
+ sink <<
+ vecType << " angle_frl(" << vecType << " v) {\n"
+ " v = clamp(v, -2.0, 2.0);\n"
+ " v = v * 256.0;\n"
+ " v = sign(v) * floor(abs(v));\n"
+ " return v * 0.00390625;\n"
+ "}\n";
+ // clang-format on
+}
+
+void RoundingHelperWriterHLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink,
+ const unsigned int columns,
+ const unsigned int rows,
+ const char *functionName)
+{
+ std::stringstream matTypeStrStr = sh::InitializeStream<std::stringstream>();
+ matTypeStrStr << "float" << columns << "x" << rows;
+ std::string matType = matTypeStrStr.str();
+
+ sink << matType << " " << functionName << "(" << matType << " m) {\n"
+ << " " << matType << " rounded;\n";
+
+ for (unsigned int i = 0; i < columns; ++i)
+ {
+ sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
+ }
+
+ sink << " return rounded;\n"
+ "}\n";
+}
+
+bool canRoundFloat(const TType &type)
+{
+ return type.getBasicType() == EbtFloat && !type.isArray() &&
+ (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
+}
+
+bool ParentUsesResult(TIntermNode *parent, TIntermTyped *node)
+{
+ if (!parent)
+ {
+ return false;
+ }
+
+ TIntermBlock *blockParent = parent->getAsBlock();
+ // If the parent is a block, the result is not assigned anywhere,
+ // so rounding it is not needed. In particular, this can avoid a lot of
+ // unnecessary rounding of unused return values of assignment.
+ if (blockParent)
+ {
+ return false;
+ }
+ TIntermBinary *binaryParent = parent->getAsBinaryNode();
+ if (binaryParent && binaryParent->getOp() == EOpComma && (binaryParent->getRight() != node))
+ {
+ return false;
+ }
+ return true;
+}
+
+bool ParentConstructorTakesCareOfRounding(TIntermNode *parent, TIntermTyped *node)
+{
+ if (!parent)
+ {
+ return false;
+ }
+ TIntermAggregate *parentConstructor = parent->getAsAggregate();
+ if (!parentConstructor || parentConstructor->getOp() != EOpConstruct)
+ {
+ return false;
+ }
+ if (parentConstructor->getPrecision() != node->getPrecision())
+ {
+ return false;
+ }
+ return canRoundFloat(parentConstructor->getType());
+}
+
+} // namespace
+
+EmulatePrecision::EmulatePrecision(TSymbolTable *symbolTable)
+ : TLValueTrackingTraverser(true, true, true, symbolTable), mDeclaringVariables(false)
+{}
+
+void EmulatePrecision::visitSymbol(TIntermSymbol *node)
+{
+ TIntermNode *parent = getParentNode();
+ if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) &&
+ !ParentConstructorTakesCareOfRounding(parent, node) && !mDeclaringVariables &&
+ !isLValueRequiredHere())
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+ }
+}
+
+bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node)
+{
+ bool visitChildren = true;
+
+ TOperator op = node->getOp();
+
+ // RHS of initialize is not being declared.
+ if (op == EOpInitialize && visit == InVisit)
+ mDeclaringVariables = false;
+
+ if ((op == EOpIndexDirectStruct) && visit == InVisit)
+ visitChildren = false;
+
+ if (visit != PreVisit)
+ return visitChildren;
+
+ const TType &type = node->getType();
+ bool roundFloat = canRoundFloat(type);
+
+ if (roundFloat)
+ {
+ switch (op)
+ {
+ // Math operators that can result in a float may need to apply rounding to the return
+ // value. Note that in the case of assignment, the rounding is applied to its return
+ // value here, not the value being assigned.
+ case EOpAssign:
+ case EOpAdd:
+ case EOpSub:
+ case EOpMul:
+ case EOpDiv:
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ {
+ TIntermNode *parent = getParentNode();
+ if (!ParentUsesResult(parent, node) ||
+ ParentConstructorTakesCareOfRounding(parent, node))
+ {
+ break;
+ }
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+ break;
+ }
+
+ // Compound assignment cases need to replace the operator with a function call.
+ case EOpAddAssign:
+ {
+ mEmulateCompoundAdd.insert(
+ TypePair(type.getBuiltInTypeNameString(),
+ node->getRight()->getType().getBuiltInTypeNameString()));
+ TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+ node->getLeft(), node->getRight(), "add");
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ break;
+ }
+ case EOpSubAssign:
+ {
+ mEmulateCompoundSub.insert(
+ TypePair(type.getBuiltInTypeNameString(),
+ node->getRight()->getType().getBuiltInTypeNameString()));
+ TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+ node->getLeft(), node->getRight(), "sub");
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ break;
+ }
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ {
+ mEmulateCompoundMul.insert(
+ TypePair(type.getBuiltInTypeNameString(),
+ node->getRight()->getType().getBuiltInTypeNameString()));
+ TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+ node->getLeft(), node->getRight(), "mul");
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ break;
+ }
+ case EOpDivAssign:
+ {
+ mEmulateCompoundDiv.insert(
+ TypePair(type.getBuiltInTypeNameString(),
+ node->getRight()->getType().getBuiltInTypeNameString()));
+ TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+ node->getLeft(), node->getRight(), "div");
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ break;
+ }
+ default:
+ // The rest of the binary operations should not need precision emulation.
+ break;
+ }
+ }
+ return visitChildren;
+}
+
+bool EmulatePrecision::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ // Variable or interface block declaration.
+ if (visit == PreVisit)
+ {
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ return true;
+}
+
+bool EmulatePrecision::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+ return false;
+}
+
+bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (visit != PreVisit)
+ return true;
+
+ // User-defined function return values are not rounded. The calculations that produced
+ // the value inside the function definition should have been rounded.
+ TOperator op = node->getOp();
+ if (op == EOpCallInternalRawFunction || op == EOpCallFunctionInAST ||
+ (op == EOpConstruct && node->getBasicType() == EbtStruct))
+ {
+ return true;
+ }
+
+ TIntermNode *parent = getParentNode();
+ if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) &&
+ !ParentConstructorTakesCareOfRounding(parent, node))
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+ }
+ return true;
+}
+
+bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
+{
+ switch (node->getOp())
+ {
+ case EOpNegative:
+ case EOpLogicalNot:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpLogicalNotComponentWise:
+ break;
+ default:
+ if (canRoundFloat(node->getType()) && visit == PreVisit)
+ {
+ TIntermNode *replacement = createRoundingFunctionCallNode(node);
+ queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+ }
+ break;
+ }
+
+ return true;
+}
+
+void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink,
+ const int shaderVersion,
+ const ShShaderOutput outputLanguage)
+{
+ std::unique_ptr<RoundingHelperWriter> roundingHelperWriter(
+ RoundingHelperWriter::createHelperWriter(outputLanguage));
+
+ roundingHelperWriter->writeCommonRoundingHelpers(sink, shaderVersion);
+
+ EmulationSet::const_iterator it;
+ for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++)
+ roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "+", "add");
+ for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++)
+ roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "-", "sub");
+ for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++)
+ roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "/", "div");
+ for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++)
+ roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "*", "mul");
+}
+
+// static
+bool EmulatePrecision::SupportedInLanguage(const ShShaderOutput outputLanguage)
+{
+ switch (outputLanguage)
+ {
+ case SH_HLSL_4_1_OUTPUT:
+ case SH_ESSL_OUTPUT:
+ return true;
+ default:
+ // Other languages not yet supported
+ return (outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
+ sh::IsGLSL130OrNewer(outputLanguage));
+ }
+}
+
+const TFunction *EmulatePrecision::getInternalFunction(const ImmutableString &functionName,
+ const TType &returnType,
+ TIntermSequence *arguments,
+ const TVector<const TVariable *> &parameters,
+ bool knownToNotHaveSideEffects)
+{
+ ImmutableString mangledName = TFunctionLookup::GetMangledName(functionName.data(), *arguments);
+ if (mInternalFunctions.find(mangledName) == mInternalFunctions.end())
+ {
+ TFunction *func = new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal,
+ new TType(returnType), knownToNotHaveSideEffects);
+ ASSERT(parameters.size() == arguments->size());
+ for (size_t i = 0; i < parameters.size(); ++i)
+ {
+ func->addParameter(parameters[i]);
+ }
+ mInternalFunctions[mangledName] = func;
+ }
+ return mInternalFunctions[mangledName];
+}
+
+TIntermAggregate *EmulatePrecision::createRoundingFunctionCallNode(TIntermTyped *roundedChild)
+{
+ const ImmutableString *roundFunctionName = &kAngleFrmString;
+ if (roundedChild->getPrecision() == EbpLow)
+ roundFunctionName = &kAngleFrlString;
+ TIntermSequence *arguments = new TIntermSequence();
+ arguments->push_back(roundedChild);
+
+ TVector<const TVariable *> parameters;
+ TType *paramType = new TType(roundedChild->getType());
+ paramType->setPrecision(EbpHigh);
+ paramType->setQualifier(EvqIn);
+ parameters.push_back(new TVariable(mSymbolTable, kParamXName,
+ static_cast<const TType *>(paramType),
+ SymbolType::AngleInternal));
+
+ return TIntermAggregate::CreateRawFunctionCall(
+ *getInternalFunction(*roundFunctionName, roundedChild->getType(), arguments, parameters,
+ true),
+ arguments);
+}
+
+TIntermAggregate *EmulatePrecision::createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
+ TIntermTyped *right,
+ const char *opNameStr)
+{
+ std::stringstream strstr = sh::InitializeStream<std::stringstream>();
+ if (left->getPrecision() == EbpMedium)
+ strstr << "angle_compound_" << opNameStr << "_frm";
+ else
+ strstr << "angle_compound_" << opNameStr << "_frl";
+ ImmutableString functionName = ImmutableString(strstr.str());
+ TIntermSequence *arguments = new TIntermSequence();
+ arguments->push_back(left);
+ arguments->push_back(right);
+
+ TVector<const TVariable *> parameters;
+ TType *leftParamType = new TType(left->getType());
+ leftParamType->setPrecision(EbpHigh);
+ leftParamType->setQualifier(EvqOut);
+ parameters.push_back(new TVariable(mSymbolTable, kParamXName,
+ static_cast<const TType *>(leftParamType),
+ SymbolType::AngleInternal));
+ TType *rightParamType = new TType(right->getType());
+ rightParamType->setPrecision(EbpHigh);
+ rightParamType->setQualifier(EvqIn);
+ parameters.push_back(new TVariable(mSymbolTable, kParamYName,
+ static_cast<const TType *>(rightParamType),
+ SymbolType::AngleInternal));
+
+ return TIntermAggregate::CreateRawFunctionCall(
+ *getInternalFunction(functionName, left->getType(), arguments, parameters, false),
+ arguments);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h
new file mode 100644
index 0000000000..10501fa1d0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h
@@ -0,0 +1,85 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_EMULATE_PRECISION_H_
+#define COMPILER_TRANSLATOR_TREEOPS_EMULATE_PRECISION_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "common/angleutils.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+// This class gathers all compound assignments from the AST and can then write
+// the functions required for their precision emulation. This way there is no
+// need to write a huge number of variations of the emulated compound assignment
+// to every translated shader with emulation enabled.
+
+namespace sh
+{
+
+class EmulatePrecision : public TLValueTrackingTraverser
+{
+ public:
+ EmulatePrecision(TSymbolTable *symbolTable);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+
+ void writeEmulationHelpers(TInfoSinkBase &sink,
+ const int shaderVersion,
+ const ShShaderOutput outputLanguage);
+
+ static bool SupportedInLanguage(const ShShaderOutput outputLanguage);
+
+ private:
+ struct TypePair
+ {
+ TypePair(const char *l, const char *r) : lType(l), rType(r) {}
+
+ const char *lType;
+ const char *rType;
+ };
+
+ struct TypePairComparator
+ {
+ bool operator()(const TypePair &l, const TypePair &r) const
+ {
+ if (l.lType == r.lType)
+ return l.rType < r.rType;
+ return l.lType < r.lType;
+ }
+ };
+
+ const TFunction *getInternalFunction(const ImmutableString &functionName,
+ const TType &returnType,
+ TIntermSequence *arguments,
+ const TVector<const TVariable *> &parameters,
+ bool knownToNotHaveSideEffects);
+ TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild);
+ TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
+ TIntermTyped *right,
+ const char *opNameStr);
+
+ typedef std::set<TypePair, TypePairComparator> EmulationSet;
+ EmulationSet mEmulateCompoundAdd;
+ EmulationSet mEmulateCompoundSub;
+ EmulationSet mEmulateCompoundMul;
+ EmulationSet mEmulateCompoundDiv;
+
+ // Map from mangled name to function.
+ TMap<ImmutableString, const TFunction *> mInternalFunctions;
+
+ bool mDeclaringVariables;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_EMULATE_PRECISION_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp
new file mode 100644
index 0000000000..73791c1ce1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp
@@ -0,0 +1,145 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of the integer pow expressions HLSL bug workaround.
+// See header for more info.
+
+#include "compiler/translator/tree_ops/ExpandIntegerPowExpressions.h"
+
+#include <cmath>
+#include <cstdlib>
+
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root, TSymbolTable *symbolTable);
+
+ private:
+ Traverser(TSymbolTable *symbolTable);
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ void nextIteration();
+
+ bool mFound = false;
+};
+
+// static
+void Traverser::Apply(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ Traverser traverser(symbolTable);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.mFound)
+ {
+ traverser.updateTree();
+ }
+ } while (traverser.mFound);
+}
+
+Traverser::Traverser(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable)
+{}
+
+void Traverser::nextIteration()
+{
+ mFound = false;
+}
+
+bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mFound)
+ {
+ return false;
+ }
+
+ // Test 0: skip non-pow operators.
+ if (node->getOp() != EOpPow)
+ {
+ return true;
+ }
+
+ const TIntermSequence *sequence = node->getSequence();
+ ASSERT(sequence->size() == 2u);
+ const TIntermConstantUnion *constantExponent = sequence->at(1)->getAsConstantUnion();
+
+ // Test 1: check for a single constant.
+ if (!constantExponent || constantExponent->getNominalSize() != 1)
+ {
+ return true;
+ }
+
+ float exponentValue = constantExponent->getConstantValue()->getFConst();
+
+ // Test 2: exponentValue is in the problematic range.
+ if (exponentValue < -5.0f || exponentValue > 9.0f)
+ {
+ return true;
+ }
+
+ // Test 3: exponentValue is integer or pretty close to an integer.
+ if (std::abs(exponentValue - std::round(exponentValue)) > 0.0001f)
+ {
+ return true;
+ }
+
+ // Test 4: skip -1, 0, and 1
+ int exponent = static_cast<int>(std::round(exponentValue));
+ int n = std::abs(exponent);
+ if (n < 2)
+ {
+ return true;
+ }
+
+ // Potential problem case detected, apply workaround.
+
+ TIntermTyped *lhs = sequence->at(0)->getAsTyped();
+ ASSERT(lhs);
+
+ TIntermDeclaration *lhsVariableDeclaration = nullptr;
+ TVariable *lhsVariable =
+ DeclareTempVariable(mSymbolTable, lhs, EvqTemporary, &lhsVariableDeclaration);
+ insertStatementInParentBlock(lhsVariableDeclaration);
+
+ // Create a chain of n-1 multiples.
+ TIntermTyped *current = CreateTempSymbolNode(lhsVariable);
+ for (int i = 1; i < n; ++i)
+ {
+ TIntermBinary *mul = new TIntermBinary(EOpMul, current, CreateTempSymbolNode(lhsVariable));
+ mul->setLine(node->getLine());
+ current = mul;
+ }
+
+ // For negative pow, compute the reciprocal of the positive pow.
+ if (exponent < 0)
+ {
+ TConstantUnion *oneVal = new TConstantUnion();
+ oneVal->setFConst(1.0f);
+ TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
+ TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current);
+ current = div;
+ }
+
+ queueReplacement(current, OriginalNode::IS_DROPPED);
+ mFound = true;
+ return false;
+}
+
+} // anonymous namespace
+
+void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ Traverser::Apply(root, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h
new file mode 100644
index 0000000000..7ee5adab3c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This mutating tree traversal works around a bug in the HLSL compiler optimizer with "pow" that
+// manifests under the following conditions:
+//
+// - If pow() has a literal exponent value
+// - ... and this value is integer or within 10e-6 of an integer
+// - ... and it is in {-4, -3, -2, 2, 3, 4, 5, 6, 7, 8}
+//
+// The workaround is to replace the pow with a series of multiplies.
+// See http://anglebug.com/851
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_EXPANDINTEGERPOWEXPRESSIONS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_EXPANDINTEGERPOWEXPRESSIONS_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_EXPANDINTEGERPOWEXPRESSIONS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp
new file mode 100644
index 0000000000..5d57e1e716
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FoldExpressions.cpp: Fold expressions. This may fold expressions so that the qualifier of the
+// folded node differs from the qualifier of the original expression, so it needs to be done after
+// parsing and validation of qualifiers is complete. Expressions that are folded:
+// 1. Ternary ops with a constant condition.
+// 2. Sequence aka comma ops where the left side has no side effects.
+// 3. Any expressions containing any of the above.
+
+#include "compiler/translator/tree_ops/FoldExpressions.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class FoldExpressionsTraverser : public TIntermTraverser
+{
+ public:
+ FoldExpressionsTraverser(TDiagnostics *diagnostics)
+ : TIntermTraverser(true, false, false), mDiagnostics(diagnostics), mDidReplace(false)
+ {}
+
+ bool didReplace() { return mDidReplace; }
+
+ void nextIteration() { mDidReplace = false; }
+
+ protected:
+ bool visitTernary(Visit visit, TIntermTernary *node) override
+ {
+ TIntermTyped *folded = node->fold(mDiagnostics);
+ if (folded != node)
+ {
+ queueReplacement(folded, OriginalNode::IS_DROPPED);
+ mDidReplace = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ TIntermTyped *folded = node->fold(mDiagnostics);
+ if (folded != node)
+ {
+ queueReplacement(folded, OriginalNode::IS_DROPPED);
+ mDidReplace = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override
+ {
+ TIntermTyped *folded = node->fold(mDiagnostics);
+ if (folded != node)
+ {
+ queueReplacement(folded, OriginalNode::IS_DROPPED);
+ mDidReplace = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override
+ {
+ TIntermTyped *folded = node->fold(mDiagnostics);
+ if (folded != node)
+ {
+ queueReplacement(folded, OriginalNode::IS_DROPPED);
+ mDidReplace = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visitSwizzle(Visit visit, TIntermSwizzle *node) override
+ {
+ TIntermTyped *folded = node->fold(mDiagnostics);
+ if (folded != node)
+ {
+ queueReplacement(folded, OriginalNode::IS_DROPPED);
+ mDidReplace = true;
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ TDiagnostics *mDiagnostics;
+ bool mDidReplace;
+};
+
+} // anonymous namespace
+
+void FoldExpressions(TIntermBlock *root, TDiagnostics *diagnostics)
+{
+ FoldExpressionsTraverser traverser(diagnostics);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ } while (traverser.didReplace());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h
new file mode 100644
index 0000000000..42d026afb8
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FoldExpressions.h: Fold expressions. This may fold expressions so that the qualifier of the
+// folded node differs from the qualifier of the original expression, so it needs to be done after
+// parsing and validation of qualifiers is complete. Expressions that are folded: 1. Ternary ops
+// with a constant condition.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_FOLDEXPRESSIONS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_FOLDEXPRESSIONS_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TDiagnostics;
+
+void FoldExpressions(TIntermBlock *root, TDiagnostics *diagnostics);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_FOLDEXPRESSIONS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp
new file mode 100644
index 0000000000..21b0bed658
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp
@@ -0,0 +1,311 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/InitializeVariables.h"
+
+#include "angle_gl.h"
+#include "common/debug.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/FindMain.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable);
+
+void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable);
+
+TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
+{
+ TIntermTyped *zero = CreateZeroNode(initializedNode->getType());
+ return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
+}
+
+void AddZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ if (initializedNode->isArray())
+ {
+ AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported,
+ initSequenceOut, symbolTable);
+ }
+ else if (initializedNode->getType().isStructureContainingArrays() ||
+ initializedNode->getType().isNamelessStruct())
+ {
+ AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported,
+ initSequenceOut, symbolTable);
+ }
+ else
+ {
+ initSequenceOut->push_back(CreateZeroInitAssignment(initializedNode));
+ }
+}
+
+void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ ASSERT(initializedNode->getBasicType() == EbtStruct);
+ const TStructure *structType = initializedNode->getType().getStruct();
+ for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
+ {
+ TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
+ initializedNode->deepCopy(), CreateIndexNode(i));
+ // Structs can't be defined inside structs, so the type of a struct field can't be a
+ // nameless struct.
+ ASSERT(!element->getType().isNamelessStruct());
+ AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported,
+ initSequenceOut, symbolTable);
+ }
+}
+
+void AddArrayZeroInitStatementList(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i)
+ {
+ TIntermBinary *element =
+ new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
+ AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported,
+ initSequenceOut, symbolTable);
+ }
+}
+
+void AddArrayZeroInitForLoop(const TIntermTyped *initializedNode,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ ASSERT(initializedNode->isArray());
+ const TType *mediumpIndexType = StaticType::Get<EbtInt, EbpMedium, EvqTemporary, 1, 1>();
+ const TType *highpIndexType = StaticType::Get<EbtInt, EbpHigh, EvqTemporary, 1, 1>();
+ TVariable *indexVariable =
+ CreateTempVariable(symbolTable, highPrecisionSupported ? highpIndexType : mediumpIndexType);
+
+ TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexVariable);
+ TIntermDeclaration *indexInit =
+ CreateTempInitDeclarationNode(indexVariable, CreateZeroNode(indexVariable->getType()));
+ TIntermConstantUnion *arraySizeNode = CreateIndexNode(initializedNode->getOutermostArraySize());
+ TIntermBinary *indexSmallerThanSize =
+ new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode);
+ TIntermUnary *indexIncrement =
+ new TIntermUnary(EOpPreIncrement, indexSymbolNode->deepCopy(), nullptr);
+
+ TIntermBlock *forLoopBody = new TIntermBlock();
+ TIntermSequence *forLoopBodySeq = forLoopBody->getSequence();
+
+ TIntermBinary *element = new TIntermBinary(EOpIndexIndirect, initializedNode->deepCopy(),
+ indexSymbolNode->deepCopy());
+ AddZeroInitSequence(element, true, highPrecisionSupported, forLoopBodySeq, symbolTable);
+
+ TIntermLoop *forLoop =
+ new TIntermLoop(ELoopFor, indexInit, indexSmallerThanSize, indexIncrement, forLoopBody);
+ initSequenceOut->push_back(forLoop);
+}
+
+void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ // The array elements are assigned one by one to keep the AST compatible with ESSL 1.00 which
+ // doesn't have array assignment. We'll do this either with a for loop or just a list of
+ // statements assigning to each array index. Note that it is important to have the array init in
+ // the right order to workaround http://crbug.com/709317
+ bool isSmallArray = initializedNode->getOutermostArraySize() <= 1u ||
+ (initializedNode->getBasicType() != EbtStruct &&
+ !initializedNode->getType().isArrayOfArrays() &&
+ initializedNode->getOutermostArraySize() <= 3u);
+ if (initializedNode->getQualifier() == EvqFragData ||
+ initializedNode->getQualifier() == EvqFragmentOut || isSmallArray ||
+ !canUseLoopsToInitialize)
+ {
+ // Fragment outputs should not be indexed by non-constant indices.
+ // Also it doesn't make sense to use loops to initialize very small arrays.
+ AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize,
+ highPrecisionSupported, initSequenceOut, symbolTable);
+ }
+ else
+ {
+ AddArrayZeroInitForLoop(initializedNode, highPrecisionSupported, initSequenceOut,
+ symbolTable);
+ }
+}
+
+void InsertInitCode(TIntermSequence *mainBody,
+ const InitVariableList &variables,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported)
+{
+ for (const auto &var : variables)
+ {
+ // Note that tempVariableName will reference a short-lived char array here - that's fine
+ // since we're only using it to find symbols.
+ ImmutableString tempVariableName(var.name.c_str(), var.name.length());
+
+ TIntermTyped *initializedSymbol = nullptr;
+ if (var.isBuiltIn())
+ {
+ initializedSymbol =
+ ReferenceBuiltInVariable(tempVariableName, *symbolTable, shaderVersion);
+ if (initializedSymbol->getQualifier() == EvqFragData &&
+ !IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers))
+ {
+ // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
+ // written to.
+ // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up
+ // with a good way to do it. Right now "gl_FragData" in symbol table is initialized
+ // to have the array size of MaxDrawBuffers, and the initialization happens before
+ // the shader sets the extensions it is using.
+ initializedSymbol =
+ new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0));
+ }
+ }
+ else
+ {
+ initializedSymbol = ReferenceGlobalVariable(tempVariableName, *symbolTable);
+ }
+ ASSERT(initializedSymbol != nullptr);
+
+ TIntermSequence *initCode = CreateInitCode(initializedSymbol, canUseLoopsToInitialize,
+ highPrecisionSupported, symbolTable);
+ mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
+ }
+}
+
+class InitializeLocalsTraverser : public TIntermTraverser
+{
+ public:
+ InitializeLocalsTraverser(int shaderVersion,
+ TSymbolTable *symbolTable,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mShaderVersion(shaderVersion),
+ mCanUseLoopsToInitialize(canUseLoopsToInitialize),
+ mHighPrecisionSupported(highPrecisionSupported)
+ {}
+
+ protected:
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
+ {
+ for (TIntermNode *declarator : *node->getSequence())
+ {
+ if (!mInGlobalScope && !declarator->getAsBinaryNode())
+ {
+ TIntermSymbol *symbol = declarator->getAsSymbolNode();
+ ASSERT(symbol);
+ if (symbol->variable().symbolType() == SymbolType::Empty)
+ {
+ continue;
+ }
+
+ // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
+ // support array constructors or assigning arrays.
+ bool arrayConstructorUnavailable =
+ (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
+ mShaderVersion == 100;
+ // Nameless struct constructors can't be referred to, so they also need to be
+ // initialized one element at a time.
+ // TODO(oetuaho): Check if it makes sense to initialize using a loop, even if we
+ // could use an initializer. It could at least reduce code size for very large
+ // arrays, but could hurt runtime performance.
+ if (arrayConstructorUnavailable || symbol->getType().isNamelessStruct())
+ {
+ // SimplifyLoopConditions should have been run so the parent node of this node
+ // should not be a loop.
+ ASSERT(getParentNode()->getAsLoopNode() == nullptr);
+ // SeparateDeclarations should have already been run, so we don't need to worry
+ // about further declarators in this declaration depending on the effects of
+ // this declarator.
+ ASSERT(node->getSequence()->size() == 1);
+ insertStatementsInParentBlock(
+ TIntermSequence(), *CreateInitCode(symbol, mCanUseLoopsToInitialize,
+ mHighPrecisionSupported, mSymbolTable));
+ }
+ else
+ {
+ TIntermBinary *init =
+ new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
+ queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
+ }
+ }
+ }
+ return false;
+ }
+
+ private:
+ int mShaderVersion;
+ bool mCanUseLoopsToInitialize;
+ bool mHighPrecisionSupported;
+};
+
+} // namespace
+
+TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TSymbolTable *symbolTable)
+{
+ TIntermSequence *initCode = new TIntermSequence();
+ AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, highPrecisionSupported,
+ initCode, symbolTable);
+ return initCode;
+}
+
+void InitializeUninitializedLocals(TIntermBlock *root,
+ int shaderVersion,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TSymbolTable *symbolTable)
+{
+ InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize,
+ highPrecisionSupported);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+void InitializeVariables(TIntermBlock *root,
+ const InitVariableList &vars,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported)
+{
+ TIntermBlock *body = FindMainBody(root);
+ InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior,
+ canUseLoopsToInitialize, highPrecisionSupported);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h
new file mode 100644
index 0000000000..06695f93c9
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_INITIALIZEVARIABLES_H_
+#define COMPILER_TRANSLATOR_TREEOPS_INITIALIZEVARIABLES_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+class TSymbolTable;
+
+typedef std::vector<sh::ShaderVariable> InitVariableList;
+
+// For all of the functions below: If canUseLoopsToInitialize is set, for loops are used instead of
+// a large number of initializers where it can make sense, such as for initializing large arrays.
+
+// Return a sequence of assignment operations to initialize "initializedSymbol". initializedSymbol
+// may be an array, struct or any combination of these, as long as it contains only basic types.
+TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TSymbolTable *symbolTable);
+
+// Initialize all uninitialized local variables, so that undefined behavior is avoided.
+void InitializeUninitializedLocals(TIntermBlock *root,
+ int shaderVersion,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported,
+ TSymbolTable *symbolTable);
+
+// This function can initialize all the types that CreateInitCode is able to initialize. All
+// variables must be globals which can be found in the symbol table. For now it is used for the
+// following two scenarios:
+// 1. Initializing gl_Position;
+// 2. Initializing output variables referred to in the shader source.
+// Note: The type of each lvalue in an initializer is retrieved from the symbol table. gl_FragData
+// requires special handling because the number of indices which can be initialized is determined by
+// enabled extensions.
+void InitializeVariables(TIntermBlock *root,
+ const InitVariableList &vars,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ bool canUseLoopsToInitialize,
+ bool highPrecisionSupported);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_INITIALIZEVARIABLES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp
new file mode 100644
index 0000000000..9c544491ec
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp
@@ -0,0 +1,101 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NameEmbeddedUniformStructs: Gives nameless uniform struct internal names.
+//
+
+#include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h"
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+namespace
+{
+// This traverser translates embedded uniform structs into a specifier and declaration.
+// This makes the declarations easier to move into uniform blocks.
+class Traverser : public TIntermTraverser
+{
+ public:
+ explicit Traverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable)
+ {}
+
+ bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
+ {
+ ASSERT(visit == PreVisit);
+
+ if (!mInGlobalScope)
+ {
+ return false;
+ }
+
+ const TIntermSequence &sequence = *(decl->getSequence());
+ ASSERT(sequence.size() == 1);
+ TIntermTyped *declarator = sequence.front()->getAsTyped();
+ const TType &type = declarator->getType();
+
+ if (type.isStructSpecifier() && type.getQualifier() == EvqUniform)
+ {
+ const TStructure *structure = type.getStruct();
+
+ if (structure->symbolType() == SymbolType::Empty)
+ {
+ doReplacement(decl, declarator, structure);
+ }
+ }
+
+ return false;
+ }
+
+ private:
+ void doReplacement(TIntermDeclaration *decl,
+ TIntermTyped *declarator,
+ const TStructure *oldStructure)
+ {
+ // struct <structName> { ... };
+ TStructure *structure = new TStructure(mSymbolTable, kEmptyImmutableString,
+ &oldStructure->fields(), SymbolType::AngleInternal);
+ TType *namedType = new TType(structure, true);
+ namedType->setQualifier(EvqGlobal);
+
+ TVariable *structVariable =
+ new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
+ TIntermSymbol *structDeclarator = new TIntermSymbol(structVariable);
+ TIntermDeclaration *structDeclaration = new TIntermDeclaration;
+ structDeclaration->appendDeclarator(structDeclarator);
+
+ TIntermSequence *newSequence = new TIntermSequence;
+ newSequence->push_back(structDeclaration);
+
+ // uniform <structName> <structUniformName>;
+ TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
+ if (asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty)
+ {
+ TIntermDeclaration *namedDecl = new TIntermDeclaration;
+ TType *uniformType = new TType(structure, false);
+ uniformType->setQualifier(EvqUniform);
+
+ TVariable *newVar = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
+ asSymbol->variable().symbolType());
+ TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
+ namedDecl->appendDeclarator(newSymbol);
+
+ newSequence->push_back(namedDecl);
+ }
+
+ mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence);
+ }
+};
+} // anonymous namespace
+
+void NameEmbeddedStructUniforms(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ Traverser nameStructs(symbolTable);
+ root->traverse(&nameStructs);
+ nameStructs.updateTree();
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h
new file mode 100644
index 0000000000..0ada189501
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h
@@ -0,0 +1,25 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NameEmbeddedUniformStructs: Gives nameless uniform struct internal names.
+//
+// For example:
+// uniform struct { int a; } uni;
+// becomes:
+// struct s1 { int a; };
+// uniform s1 uni;
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_NAMEEMBEDDEDUNIFORMSTRUCTS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_NAMEEMBEDDEDUNIFORMSTRUCTS_H_
+
+namespace sh
+{
+class TIntermBlock;
+class TSymbolTable;
+void NameEmbeddedStructUniforms(TIntermBlock *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_NAMEEMBEDDEDUNIFORMSTRUCTS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp
new file mode 100644
index 0000000000..7dd756ca2d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// PruneEmptyCases.cpp: The PruneEmptyCases function prunes cases that are followed by nothing from
+// the AST.
+
+#include "compiler/translator/tree_ops/PruneEmptyCases.h"
+
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool AreEmptyBlocks(TIntermSequence *statements);
+
+bool IsEmptyBlock(TIntermNode *node)
+{
+ TIntermBlock *asBlock = node->getAsBlock();
+ if (asBlock)
+ {
+ return AreEmptyBlocks(asBlock->getSequence());
+ }
+ // Empty declarations should have already been pruned, otherwise they would need to be handled
+ // here. Note that declarations for struct types do contain a nameless child node.
+ ASSERT(node->getAsDeclarationNode() == nullptr ||
+ !node->getAsDeclarationNode()->getSequence()->empty());
+ // Pure literal statements should also already be pruned.
+ ASSERT(node->getAsConstantUnion() == nullptr);
+ return false;
+}
+
+// Return true if all statements in "statements" consist only of empty blocks and no-op statements.
+// Returns true also if there are no statements.
+bool AreEmptyBlocks(TIntermSequence *statements)
+{
+ for (size_t i = 0u; i < statements->size(); ++i)
+ {
+ if (!IsEmptyBlock(statements->at(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+class PruneEmptyCasesTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermBlock *root);
+
+ private:
+ PruneEmptyCasesTraverser();
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+};
+
+void PruneEmptyCasesTraverser::apply(TIntermBlock *root)
+{
+ PruneEmptyCasesTraverser prune;
+ root->traverse(&prune);
+ prune.updateTree();
+}
+
+PruneEmptyCasesTraverser::PruneEmptyCasesTraverser() : TIntermTraverser(true, false, false) {}
+
+bool PruneEmptyCasesTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+ // This may mutate the statementList, but that's okay, since traversal has not yet reached
+ // there.
+ TIntermBlock *statementList = node->getStatementList();
+ TIntermSequence *statements = statementList->getSequence();
+
+ // Iterate block children in reverse order. Cases that are only followed by other cases or empty
+ // blocks are marked for pruning.
+ size_t i = statements->size();
+ size_t lastNoOpInStatementList = i;
+ while (i > 0)
+ {
+ --i;
+ TIntermNode *statement = statements->at(i);
+ if (statement->getAsCaseNode() || IsEmptyBlock(statement))
+ {
+ lastNoOpInStatementList = i;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (lastNoOpInStatementList == 0)
+ {
+ // Remove the entire switch statement, extracting the init expression if needed.
+ TIntermTyped *init = node->getInit();
+ if (init->hasSideEffects())
+ {
+ queueReplacement(init, OriginalNode::IS_DROPPED);
+ }
+ else
+ {
+ TIntermSequence emptyReplacement;
+ ASSERT(getParentNode()->getAsBlock());
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(),
+ node, emptyReplacement));
+ }
+ return false;
+ }
+ if (lastNoOpInStatementList < statements->size())
+ {
+ statements->erase(statements->begin() + lastNoOpInStatementList, statements->end());
+ }
+
+ return true;
+}
+
+} // namespace
+
+void PruneEmptyCases(TIntermBlock *root)
+{
+ PruneEmptyCasesTraverser::apply(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h
new file mode 100644
index 0000000000..0b88ac181c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// PruneEmptyCases.h: The PruneEmptyCases function prunes cases that are followed by nothing from
+// the AST.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_PRUNEEMPTYCASES_H_
+#define COMPILER_TRANSLATOR_TREEOPS_PRUNEEMPTYCASES_H_
+
+namespace sh
+{
+class TIntermBlock;
+
+void PruneEmptyCases(TIntermBlock *root);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_PRUNEEMPTYCASES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp
new file mode 100644
index 0000000000..620c3f481b
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp
@@ -0,0 +1,166 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// PruneNoOps.cpp: The PruneNoOps function prunes:
+// 1. Empty declarations "int;". Empty declarators will be pruned as well, so for example:
+// int , a;
+// is turned into
+// int a;
+// 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.
+
+#include "compiler/translator/tree_ops/PruneNoOps.h"
+
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool IsNoOp(TIntermNode *node)
+{
+ if (node->getAsConstantUnion() != nullptr)
+ {
+ return true;
+ }
+ bool isEmptyDeclaration = node->getAsDeclarationNode() != nullptr &&
+ node->getAsDeclarationNode()->getSequence()->empty();
+ if (isEmptyDeclaration)
+ {
+ return true;
+ }
+ return false;
+}
+
+class PruneNoOpsTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermBlock *root, TSymbolTable *symbolTable);
+
+ private:
+ PruneNoOpsTraverser(TSymbolTable *symbolTable);
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *loop) override;
+};
+
+void PruneNoOpsTraverser::apply(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ PruneNoOpsTraverser prune(symbolTable);
+ root->traverse(&prune);
+ prune.updateTree();
+}
+
+PruneNoOpsTraverser::PruneNoOpsTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable)
+{}
+
+bool PruneNoOpsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ TIntermSequence *sequence = node->getSequence();
+ if (sequence->size() >= 1)
+ {
+ TIntermSymbol *declaratorSymbol = sequence->front()->getAsSymbolNode();
+ // Prune declarations without a variable name, unless it's an interface block declaration.
+ if (declaratorSymbol != nullptr &&
+ declaratorSymbol->variable().symbolType() == SymbolType::Empty &&
+ !declaratorSymbol->isInterfaceBlock())
+ {
+ if (sequence->size() > 1)
+ {
+ // Generate a replacement that will remove the empty declarator in the beginning of
+ // a declarator list. Example of a declaration that will be changed:
+ // float, a;
+ // will be changed to
+ // float a;
+ // This applies also to struct declarations.
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(node, declaratorSymbol, emptyReplacement));
+ }
+ else if (declaratorSymbol->getBasicType() != EbtStruct)
+ {
+ // If there are entirely empty non-struct declarations, they result in
+ // TIntermDeclaration nodes without any children in the parsing stage. These are
+ // handled in visitBlock and visitLoop.
+ UNREACHABLE();
+ }
+ else if (declaratorSymbol->getQualifier() != EvqGlobal &&
+ declaratorSymbol->getQualifier() != EvqTemporary)
+ {
+ // Single struct declarations may just declare the struct type and no variables, so
+ // they should not be pruned. Here we handle an empty struct declaration with a
+ // qualifier, for example like this:
+ // const struct a { int i; };
+ // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so we
+ // convert the declaration to a regular struct declaration. This is okay, since ESSL
+ // 1.00 spec section 4.1.8 says about structs that "The optional qualifiers only
+ // apply to any declarators, and are not part of the type being defined for name."
+
+ // Create a new variable to use in the declarator so that the variable and node
+ // types are kept consistent.
+ TType *type = new TType(declaratorSymbol->getType());
+ if (mInGlobalScope)
+ {
+ type->setQualifier(EvqGlobal);
+ }
+ else
+ {
+ type->setQualifier(EvqTemporary);
+ }
+ TVariable *variable =
+ new TVariable(mSymbolTable, kEmptyImmutableString, type, SymbolType::Empty);
+ queueReplacementWithParent(node, declaratorSymbol, new TIntermSymbol(variable),
+ OriginalNode::IS_DROPPED);
+ }
+ }
+ }
+ return false;
+}
+
+bool PruneNoOpsTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+ TIntermSequence *statements = node->getSequence();
+
+ for (TIntermNode *statement : *statements)
+ {
+ if (IsNoOp(statement))
+ {
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(node, statement, emptyReplacement));
+ }
+ }
+
+ return true;
+}
+
+bool PruneNoOpsTraverser::visitLoop(Visit visit, TIntermLoop *loop)
+{
+ TIntermTyped *expr = loop->getExpression();
+ if (expr != nullptr && IsNoOp(expr))
+ {
+ loop->setExpression(nullptr);
+ }
+ TIntermNode *init = loop->getInit();
+ if (init != nullptr && IsNoOp(init))
+ {
+ loop->setInit(nullptr);
+ }
+
+ return true;
+}
+
+} // namespace
+
+void PruneNoOps(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ PruneNoOpsTraverser::apply(root, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h
new file mode 100644
index 0000000000..83a6c66589
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// PruneNoOps.h: The PruneNoOps function prunes:
+// 1. Empty declarations "int;". Empty declarators will be pruned as well, so for example:
+// int , a;
+// is turned into
+// int a;
+// 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.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_PRUNENOOPS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_PRUNENOOPS_H_
+
+namespace sh
+{
+class TIntermBlock;
+class TSymbolTable;
+
+void PruneNoOps(TIntermBlock *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_PRUNENOOPS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
new file mode 100644
index 0000000000..9e7b0a0330
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// During parsing, all constant expressions are folded to constant union nodes. The expressions that
+// have been folded may have had precision qualifiers, which should affect the precision of the
+// consuming operation. If the folded constant union nodes are written to output as such they won't
+// have any precision qualifiers, and their effect on the precision of the consuming operation is
+// lost.
+//
+// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants
+// and hoists the constants outside the containing expression as precision qualified named variables
+// in case that is required for correct precision propagation.
+//
+
+#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class RecordConstantPrecisionTraverser : public TIntermTraverser
+{
+ public:
+ RecordConstantPrecisionTraverser(TSymbolTable *symbolTable);
+
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+
+ void nextIteration();
+
+ bool foundHigherPrecisionConstant() const { return mFoundHigherPrecisionConstant; }
+
+ protected:
+ bool operandAffectsParentOperationPrecision(TIntermTyped *operand);
+
+ bool mFoundHigherPrecisionConstant;
+};
+
+RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable), mFoundHigherPrecisionConstant(false)
+{}
+
+bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand)
+{
+ if (getParentNode()->getAsCaseNode() || getParentNode()->getAsBlock())
+ {
+ return false;
+ }
+
+ const TIntermBinary *parentAsBinary = getParentNode()->getAsBinaryNode();
+ if (parentAsBinary != nullptr)
+ {
+ // If the constant is assigned or is used to initialize a variable, or if it's an index,
+ // its precision has no effect.
+ switch (parentAsBinary->getOp())
+ {
+ case EOpInitialize:
+ case EOpAssign:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexIndirect:
+ return false;
+ default:
+ break;
+ }
+
+ TIntermTyped *otherOperand = parentAsBinary->getRight();
+ if (otherOperand == operand)
+ {
+ otherOperand = parentAsBinary->getLeft();
+ }
+ // If the precision of the other child is at least as high as the precision of the constant,
+ // the precision of the constant has no effect.
+ if (otherOperand->getAsConstantUnion() == nullptr &&
+ otherOperand->getPrecision() >= operand->getPrecision())
+ {
+ return false;
+ }
+ }
+
+ TIntermAggregate *parentAsAggregate = getParentNode()->getAsAggregate();
+ if (parentAsAggregate != nullptr)
+ {
+ if (!parentAsAggregate->gotPrecisionFromChildren())
+ {
+ // This can be either:
+ // * a call to an user-defined function
+ // * a call to a texture function
+ // * some other kind of aggregate
+ // In any of these cases the constant precision has no effect.
+ return false;
+ }
+ if (parentAsAggregate->isConstructor() && parentAsAggregate->getBasicType() == EbtBool)
+ {
+ return false;
+ }
+ // If the precision of operands does affect the result, but the precision of any of the
+ // other children has a precision that's at least as high as the precision of the constant,
+ // the precision of the constant has no effect.
+ TIntermSequence *parameters = parentAsAggregate->getSequence();
+ for (TIntermNode *parameter : *parameters)
+ {
+ const TIntermTyped *typedParameter = parameter->getAsTyped();
+ if (parameter != operand && typedParameter != nullptr &&
+ parameter->getAsConstantUnion() == nullptr &&
+ typedParameter->getPrecision() >= operand->getPrecision())
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ if (mFoundHigherPrecisionConstant)
+ return;
+
+ // If the constant has lowp or undefined precision, it can't increase the precision of consuming
+ // operations.
+ if (node->getPrecision() < EbpMedium)
+ return;
+
+ // It's possible the node has no effect on the precision of the consuming expression, depending
+ // on the consuming expression, and the precision of the other parameters of the expression.
+ if (!operandAffectsParentOperationPrecision(node))
+ return;
+
+ // Make the constant a precision-qualified named variable to make sure it affects the precision
+ // of the consuming expression.
+ TIntermDeclaration *variableDeclaration = nullptr;
+ TVariable *variable = DeclareTempVariable(mSymbolTable, node, EvqConst, &variableDeclaration);
+ insertStatementInParentBlock(variableDeclaration);
+ queueReplacement(CreateTempSymbolNode(variable), OriginalNode::IS_DROPPED);
+ mFoundHigherPrecisionConstant = true;
+}
+
+void RecordConstantPrecisionTraverser::nextIteration()
+{
+ mFoundHigherPrecisionConstant = false;
+}
+
+} // namespace
+
+void RecordConstantPrecision(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ RecordConstantPrecisionTraverser traverser(symbolTable);
+ // Iterate as necessary, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundHigherPrecisionConstant())
+ traverser.updateTree();
+ } while (traverser.foundHigherPrecisionConstant());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h
new file mode 100644
index 0000000000..5b15db5e48
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// During parsing, all constant expressions are folded to constant union nodes. The expressions that
+// have been folded may have had precision qualifiers, which should affect the precision of the
+// consuming operation. If the folded constant union nodes are written to output as such they won't
+// have any precision qualifiers, and their effect on the precision of the consuming operation is
+// lost.
+//
+// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants
+// and hoists the constants outside the containing expression as precision qualified named variables
+// in case that is required for correct precision propagation.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_
+#define COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_
+
+namespace sh
+{
+class TIntermNode;
+class TSymbolTable;
+
+void RecordConstantPrecision(TIntermNode *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp
new file mode 100644
index 0000000000..dd700246db
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp
@@ -0,0 +1,87 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/RegenerateStructNames.h"
+
+#include "common/debug.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+
+namespace sh
+{
+
+namespace
+{
+constexpr const ImmutableString kPrefix("_webgl_struct_");
+} // anonymous namespace
+
+void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol)
+{
+ ASSERT(symbol);
+ const TType &type = symbol->getType();
+ const TStructure *userType = type.getStruct();
+ if (!userType)
+ return;
+
+ if (userType->symbolType() == SymbolType::BuiltIn ||
+ userType->symbolType() == SymbolType::Empty)
+ {
+ // Built-in struct or nameless struct, do not touch it.
+ return;
+ }
+
+ int uniqueId = userType->uniqueId().get();
+
+ ASSERT(mScopeDepth > 0);
+ if (mScopeDepth == 1)
+ {
+ // If a struct is defined at global scope, we don't map its name.
+ // This is because at global level, the struct might be used to
+ // declare a uniform, so the same name needs to stay the same for
+ // vertex/fragment shaders. However, our mapping uses internal ID,
+ // which will be different for the same struct in vertex/fragment
+ // shaders.
+ // This is OK because names for any structs defined in other scopes
+ // will begin with "_webgl", which is reserved. So there will be
+ // no conflicts among unmapped struct names from global scope and
+ // mapped struct names from other scopes.
+ // However, we need to keep track of these global structs, so if a
+ // variable is used in a local scope, we don't try to modify the
+ // struct name through that variable.
+ mDeclaredGlobalStructs.insert(uniqueId);
+ return;
+ }
+ if (mDeclaredGlobalStructs.count(uniqueId) > 0)
+ return;
+ // Map {name} to _webgl_struct_{uniqueId}_{name}.
+ if (userType->name().beginsWith(kPrefix))
+ {
+ // The name has already been regenerated.
+ return;
+ }
+ ImmutableStringBuilder tmp(kPrefix.length() + sizeof(uniqueId) * 2u + 1u +
+ userType->name().length());
+ tmp << kPrefix;
+ tmp.appendHex(uniqueId);
+ tmp << '_' << userType->name();
+
+ // TODO(oetuaho): Add another mechanism to change symbol names so that the const_cast is not
+ // needed.
+ const_cast<TStructure *>(userType)->setName(tmp);
+}
+
+bool RegenerateStructNames::visitBlock(Visit, TIntermBlock *block)
+{
+ ++mScopeDepth;
+ TIntermSequence &sequence = *(block->getSequence());
+ for (TIntermNode *node : sequence)
+ {
+ node->traverse(this);
+ }
+ --mScopeDepth;
+ return false;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h
new file mode 100644
index 0000000000..4c53cd50e8
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REGENERATESTRUCTNAMES_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REGENERATESTRUCTNAMES_H_
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+#include <set>
+
+namespace sh
+{
+
+class RegenerateStructNames : public TIntermTraverser
+{
+ public:
+ RegenerateStructNames(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable), mScopeDepth(0)
+ {}
+
+ protected:
+ void visitSymbol(TIntermSymbol *) override;
+ bool visitBlock(Visit, TIntermBlock *block) override;
+
+ private:
+ // Indicating the depth of the current scope.
+ // The global scope is 1.
+ int mScopeDepth;
+
+ // If a struct's declared globally, push its ID in this set.
+ std::set<int> mDeclaredGlobalStructs;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REGENERATESTRUCTNAMES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp
new file mode 100644
index 0000000000..473159f89c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveArrayLengthMethod.cpp:
+// Fold array length expressions, including cases where the "this" node has side effects.
+// Example:
+// int i = (a = b).length();
+// int j = (func()).length();
+// becomes:
+// (a = b);
+// int i = <constant array length>;
+// func();
+// int j = <constant array length>;
+//
+// Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps
+// have been done to expressions containing calls of the array length method.
+//
+// Does nothing to length method calls done on runtime-sized arrays.
+
+#include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class RemoveArrayLengthTraverser : public TIntermTraverser
+{
+ public:
+ RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {}
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+
+ void nextIteration() { mFoundArrayLength = false; }
+
+ bool foundArrayLength() const { return mFoundArrayLength; }
+
+ private:
+ bool mFoundArrayLength;
+};
+
+bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ // The only case where we leave array length() in place is for runtime-sized arrays.
+ if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray())
+ {
+ mFoundArrayLength = true;
+ if (!node->getOperand()->hasSideEffects())
+ {
+ queueReplacement(node->fold(nullptr), OriginalNode::IS_DROPPED);
+ return false;
+ }
+ insertStatementInParentBlock(node->getOperand()->deepCopy());
+ TConstantUnion *constArray = new TConstantUnion[1];
+ constArray->setIConst(node->getOperand()->getOutermostArraySize());
+ queueReplacement(new TIntermConstantUnion(constArray, node->getType()),
+ OriginalNode::IS_DROPPED);
+ return false;
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+void RemoveArrayLengthMethod(TIntermBlock *root)
+{
+ RemoveArrayLengthTraverser traverser;
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundArrayLength())
+ traverser.updateTree();
+ } while (traverser.foundArrayLength());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h
new file mode 100644
index 0000000000..6376828749
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveArrayLengthMethod.h:
+// Fold array length expressions, including cases where the "this" node has side effects.
+// Example:
+// int i = (a = b).length();
+// int j = (func()).length();
+// becomes:
+// (a = b);
+// int i = <constant array length>;
+// func();
+// int j = <constant array length>;
+//
+// Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps
+// have been done to expressions containing calls of the array length method.
+//
+// Does nothing to length method calls done on runtime-sized arrays.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEARRAYLENGTHMETHOD_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REMOVEARRAYLENGTHMETHOD_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+
+void RemoveArrayLengthMethod(TIntermBlock *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEARRAYLENGTHMETHOD_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp
new file mode 100644
index 0000000000..879d29eba0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp
@@ -0,0 +1,543 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of non-SSBO vectors and
+// matrices, replacing them with calls to functions that choose which component to return or write.
+// We don't need to consider dynamic indexing in SSBO since it can be directly as part of the offset
+// of RWByteAddressBuffer.
+//
+
+#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const TType *kIndexType = StaticType::Get<EbtInt, EbpHigh, EvqIn, 1, 1>();
+
+constexpr const ImmutableString kBaseName("base");
+constexpr const ImmutableString kIndexName("index");
+constexpr const ImmutableString kValueName("value");
+
+std::string GetIndexFunctionName(const TType &type, bool write)
+{
+ TInfoSinkBase nameSink;
+ nameSink << "dyn_index_";
+ if (write)
+ {
+ nameSink << "write_";
+ }
+ if (type.isMatrix())
+ {
+ nameSink << "mat" << type.getCols() << "x" << type.getRows();
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtInt:
+ nameSink << "ivec";
+ break;
+ case EbtBool:
+ nameSink << "bvec";
+ break;
+ case EbtUInt:
+ nameSink << "uvec";
+ break;
+ case EbtFloat:
+ nameSink << "vec";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ nameSink << type.getNominalSize();
+ }
+ return nameSink.str();
+}
+
+TIntermConstantUnion *CreateIntConstantNode(int i)
+{
+ TConstantUnion *constant = new TConstantUnion();
+ constant->setIConst(i);
+ return new TIntermConstantUnion(constant, TType(EbtInt, EbpHigh));
+}
+
+TIntermTyped *EnsureSignedInt(TIntermTyped *node)
+{
+ if (node->getBasicType() == EbtInt)
+ return node;
+
+ TIntermSequence *arguments = new TIntermSequence();
+ arguments->push_back(node);
+ return TIntermAggregate::CreateConstructor(TType(EbtInt), arguments);
+}
+
+TType *GetFieldType(const TType &indexedType)
+{
+ if (indexedType.isMatrix())
+ {
+ TType *fieldType = new TType(indexedType.getBasicType(), indexedType.getPrecision());
+ fieldType->setPrimarySize(static_cast<unsigned char>(indexedType.getRows()));
+ return fieldType;
+ }
+ else
+ {
+ return new TType(indexedType.getBasicType(), indexedType.getPrecision());
+ }
+}
+
+const TType *GetBaseType(const TType &type, bool write)
+{
+ TType *baseType = new TType(type);
+ // Conservatively use highp here, even if the indexed type is not highp. That way the code can't
+ // end up using mediump version of an indexing function for a highp value, if both mediump and
+ // highp values are being indexed in the shader. For HLSL precision doesn't matter, but in
+ // principle this code could be used with multiple backends.
+ baseType->setPrecision(EbpHigh);
+ baseType->setQualifier(EvqInOut);
+ if (!write)
+ baseType->setQualifier(EvqIn);
+ return baseType;
+}
+
+// Generate a read or write function for one field in a vector/matrix.
+// Out-of-range indices are clamped. This is consistent with how ANGLE handles out-of-range
+// indices in other places.
+// Note that indices can be either int or uint. We create only int versions of the functions,
+// and convert uint indices to int at the call site.
+// read function example:
+// float dyn_index_vec2(in vec2 base, in int index)
+// {
+// switch(index)
+// {
+// case (0):
+// return base[0];
+// case (1):
+// return base[1];
+// default:
+// break;
+// }
+// if (index < 0)
+// return base[0];
+// return base[1];
+// }
+// write function example:
+// void dyn_index_write_vec2(inout vec2 base, in int index, in float value)
+// {
+// switch(index)
+// {
+// case (0):
+// base[0] = value;
+// return;
+// case (1):
+// base[1] = value;
+// return;
+// default:
+// break;
+// }
+// if (index < 0)
+// {
+// base[0] = value;
+// return;
+// }
+// base[1] = value;
+// }
+// Note that else is not used in above functions to avoid the RewriteElseBlocks transformation.
+TIntermFunctionDefinition *GetIndexFunctionDefinition(const TType &type,
+ bool write,
+ const TFunction &func,
+ TSymbolTable *symbolTable)
+{
+ ASSERT(!type.isArray());
+
+ int numCases = 0;
+ if (type.isMatrix())
+ {
+ numCases = type.getCols();
+ }
+ else
+ {
+ numCases = type.getNominalSize();
+ }
+
+ std::string functionName = GetIndexFunctionName(type, write);
+ TIntermFunctionPrototype *prototypeNode = CreateInternalFunctionPrototypeNode(func);
+
+ TIntermSymbol *baseParam = new TIntermSymbol(func.getParam(0));
+ TIntermSymbol *indexParam = new TIntermSymbol(func.getParam(1));
+ TIntermSymbol *valueParam = nullptr;
+ if (write)
+ {
+ valueParam = new TIntermSymbol(func.getParam(2));
+ }
+
+ TIntermBlock *statementList = new TIntermBlock();
+ for (int i = 0; i < numCases; ++i)
+ {
+ TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i));
+ statementList->getSequence()->push_back(caseNode);
+
+ TIntermBinary *indexNode =
+ new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(i));
+ if (write)
+ {
+ TIntermBinary *assignNode =
+ new TIntermBinary(EOpAssign, indexNode, valueParam->deepCopy());
+ statementList->getSequence()->push_back(assignNode);
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
+ statementList->getSequence()->push_back(returnNode);
+ }
+ else
+ {
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, indexNode);
+ statementList->getSequence()->push_back(returnNode);
+ }
+ }
+
+ // Default case
+ TIntermCase *defaultNode = new TIntermCase(nullptr);
+ statementList->getSequence()->push_back(defaultNode);
+ TIntermBranch *breakNode = new TIntermBranch(EOpBreak, nullptr);
+ statementList->getSequence()->push_back(breakNode);
+
+ TIntermSwitch *switchNode = new TIntermSwitch(indexParam->deepCopy(), statementList);
+
+ TIntermBlock *bodyNode = new TIntermBlock();
+ bodyNode->getSequence()->push_back(switchNode);
+
+ TIntermBinary *cond =
+ new TIntermBinary(EOpLessThan, indexParam->deepCopy(), CreateIntConstantNode(0));
+
+ // Two blocks: one accesses (either reads or writes) the first element and returns,
+ // the other accesses the last element.
+ TIntermBlock *useFirstBlock = new TIntermBlock();
+ TIntermBlock *useLastBlock = new TIntermBlock();
+ TIntermBinary *indexFirstNode =
+ new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(0));
+ TIntermBinary *indexLastNode =
+ new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(numCases - 1));
+ if (write)
+ {
+ TIntermBinary *assignFirstNode =
+ new TIntermBinary(EOpAssign, indexFirstNode, valueParam->deepCopy());
+ useFirstBlock->getSequence()->push_back(assignFirstNode);
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
+ useFirstBlock->getSequence()->push_back(returnNode);
+
+ TIntermBinary *assignLastNode =
+ new TIntermBinary(EOpAssign, indexLastNode, valueParam->deepCopy());
+ useLastBlock->getSequence()->push_back(assignLastNode);
+ }
+ else
+ {
+ TIntermBranch *returnFirstNode = new TIntermBranch(EOpReturn, indexFirstNode);
+ useFirstBlock->getSequence()->push_back(returnFirstNode);
+
+ TIntermBranch *returnLastNode = new TIntermBranch(EOpReturn, indexLastNode);
+ useLastBlock->getSequence()->push_back(returnLastNode);
+ }
+ TIntermIfElse *ifNode = new TIntermIfElse(cond, useFirstBlock, nullptr);
+ bodyNode->getSequence()->push_back(ifNode);
+ bodyNode->getSequence()->push_back(useLastBlock);
+
+ TIntermFunctionDefinition *indexingFunction =
+ new TIntermFunctionDefinition(prototypeNode, bodyNode);
+ return indexingFunction;
+}
+
+class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser
+{
+ public:
+ RemoveDynamicIndexingTraverser(TSymbolTable *symbolTable,
+ PerformanceDiagnostics *perfDiagnostics);
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ void insertHelperDefinitions(TIntermNode *root);
+
+ void nextIteration();
+
+ bool usedTreeInsertion() const { return mUsedTreeInsertion; }
+
+ protected:
+ // Maps of types that are indexed to the indexing function ids used for them. Note that these
+ // can not store multiple variants of the same type with different precisions - only one
+ // precision gets stored.
+ std::map<TType, TFunction *> mIndexedVecAndMatrixTypes;
+ std::map<TType, TFunction *> mWrittenVecAndMatrixTypes;
+
+ bool mUsedTreeInsertion;
+
+ // When true, the traverser will remove side effects from any indexing expression.
+ // This is done so that in code like
+ // V[j++][i]++.
+ // where V is an array of vectors, j++ will only be evaluated once.
+ bool mRemoveIndexSideEffectsInSubtree;
+
+ PerformanceDiagnostics *mPerfDiagnostics;
+};
+
+RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser(
+ TSymbolTable *symbolTable,
+ PerformanceDiagnostics *perfDiagnostics)
+ : TLValueTrackingTraverser(true, false, false, symbolTable),
+ mUsedTreeInsertion(false),
+ mRemoveIndexSideEffectsInSubtree(false),
+ mPerfDiagnostics(perfDiagnostics)
+{}
+
+void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root)
+{
+ TIntermBlock *rootBlock = root->getAsBlock();
+ ASSERT(rootBlock != nullptr);
+ TIntermSequence insertions;
+ for (auto &type : mIndexedVecAndMatrixTypes)
+ {
+ insertions.push_back(
+ GetIndexFunctionDefinition(type.first, false, *type.second, mSymbolTable));
+ }
+ for (auto &type : mWrittenVecAndMatrixTypes)
+ {
+ insertions.push_back(
+ GetIndexFunctionDefinition(type.first, true, *type.second, mSymbolTable));
+ }
+ rootBlock->insertChildNodes(0, insertions);
+}
+
+// Create a call to dyn_index_*() based on an indirect indexing op node
+TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node,
+ TIntermTyped *index,
+ TFunction *indexingFunction)
+{
+ ASSERT(node->getOp() == EOpIndexIndirect);
+ TIntermSequence *arguments = new TIntermSequence();
+ arguments->push_back(node->getLeft());
+ arguments->push_back(index);
+
+ TIntermAggregate *indexingCall =
+ TIntermAggregate::CreateFunctionCall(*indexingFunction, arguments);
+ indexingCall->setLine(node->getLine());
+ return indexingCall;
+}
+
+TIntermAggregate *CreateIndexedWriteFunctionCall(TIntermBinary *node,
+ TVariable *index,
+ TVariable *writtenValue,
+ TFunction *indexedWriteFunction)
+{
+ ASSERT(node->getOp() == EOpIndexIndirect);
+ TIntermSequence *arguments = new TIntermSequence();
+ // Deep copy the child nodes so that two pointers to the same node don't end up in the tree.
+ arguments->push_back(node->getLeft()->deepCopy());
+ arguments->push_back(CreateTempSymbolNode(index));
+ arguments->push_back(CreateTempSymbolNode(writtenValue));
+
+ TIntermAggregate *indexedWriteCall =
+ TIntermAggregate::CreateFunctionCall(*indexedWriteFunction, arguments);
+ indexedWriteCall->setLine(node->getLine());
+ return indexedWriteCall;
+}
+
+bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (mUsedTreeInsertion)
+ return false;
+
+ if (node->getOp() == EOpIndexIndirect)
+ {
+ if (mRemoveIndexSideEffectsInSubtree)
+ {
+ ASSERT(node->getRight()->hasSideEffects());
+ // In case we're just removing index side effects, convert
+ // v_expr[index_expr]
+ // to this:
+ // int s0 = index_expr; v_expr[s0];
+ // Now v_expr[s0] can be safely executed several times without unintended side effects.
+ TIntermDeclaration *indexVariableDeclaration = nullptr;
+ TVariable *indexVariable = DeclareTempVariable(mSymbolTable, node->getRight(),
+ EvqTemporary, &indexVariableDeclaration);
+ insertStatementInParentBlock(indexVariableDeclaration);
+ mUsedTreeInsertion = true;
+
+ // Replace the index with the temp variable
+ TIntermSymbol *tempIndex = CreateTempSymbolNode(indexVariable);
+ queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED);
+ }
+ else if (IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(node))
+ {
+ mPerfDiagnostics->warning(node->getLine(),
+ "Performance: dynamic indexing of vectors and "
+ "matrices is emulated and can be slow.",
+ "[]");
+ bool write = isLValueRequiredHere();
+
+#if defined(ANGLE_ENABLE_ASSERTS)
+ // Make sure that IntermNodePatternMatcher is consistent with the slightly differently
+ // implemented checks in this traverser.
+ IntermNodePatternMatcher matcher(
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue);
+ ASSERT(matcher.match(node, getParentNode(), isLValueRequiredHere()) == write);
+#endif
+
+ const TType &type = node->getLeft()->getType();
+ ImmutableString indexingFunctionName(GetIndexFunctionName(type, false));
+ TFunction *indexingFunction = nullptr;
+ if (mIndexedVecAndMatrixTypes.find(type) == mIndexedVecAndMatrixTypes.end())
+ {
+ indexingFunction =
+ new TFunction(mSymbolTable, indexingFunctionName, SymbolType::AngleInternal,
+ GetFieldType(type), true);
+ indexingFunction->addParameter(new TVariable(
+ mSymbolTable, kBaseName, GetBaseType(type, false), SymbolType::AngleInternal));
+ indexingFunction->addParameter(
+ new TVariable(mSymbolTable, kIndexName, kIndexType, SymbolType::AngleInternal));
+ mIndexedVecAndMatrixTypes[type] = indexingFunction;
+ }
+ else
+ {
+ indexingFunction = mIndexedVecAndMatrixTypes[type];
+ }
+
+ if (write)
+ {
+ // Convert:
+ // v_expr[index_expr]++;
+ // to this:
+ // int s0 = index_expr; float s1 = dyn_index(v_expr, s0); s1++;
+ // dyn_index_write(v_expr, s0, s1);
+ // This works even if index_expr has some side effects.
+ if (node->getLeft()->hasSideEffects())
+ {
+ // If v_expr has side effects, those need to be removed before proceeding.
+ // Otherwise the side effects of v_expr would be evaluated twice.
+ // The only case where an l-value can have side effects is when it is
+ // indexing. For example, it can be V[j++] where V is an array of vectors.
+ mRemoveIndexSideEffectsInSubtree = true;
+ return true;
+ }
+
+ TIntermBinary *leftBinary = node->getLeft()->getAsBinaryNode();
+ if (leftBinary != nullptr &&
+ IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(leftBinary))
+ {
+ // This is a case like:
+ // mat2 m;
+ // m[a][b]++;
+ // Process the child node m[a] first.
+ return true;
+ }
+
+ // TODO(oetuaho@nvidia.com): This is not optimal if the expression using the value
+ // only writes it and doesn't need the previous value. http://anglebug.com/1116
+
+ TFunction *indexedWriteFunction = nullptr;
+ if (mWrittenVecAndMatrixTypes.find(type) == mWrittenVecAndMatrixTypes.end())
+ {
+ ImmutableString functionName(
+ GetIndexFunctionName(node->getLeft()->getType(), true));
+ indexedWriteFunction =
+ new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal,
+ StaticType::GetBasic<EbtVoid>(), false);
+ indexedWriteFunction->addParameter(new TVariable(mSymbolTable, kBaseName,
+ GetBaseType(type, true),
+ SymbolType::AngleInternal));
+ indexedWriteFunction->addParameter(new TVariable(
+ mSymbolTable, kIndexName, kIndexType, SymbolType::AngleInternal));
+ TType *valueType = GetFieldType(type);
+ valueType->setQualifier(EvqIn);
+ indexedWriteFunction->addParameter(new TVariable(
+ mSymbolTable, kValueName, static_cast<const TType *>(valueType),
+ SymbolType::AngleInternal));
+ mWrittenVecAndMatrixTypes[type] = indexedWriteFunction;
+ }
+ else
+ {
+ indexedWriteFunction = mWrittenVecAndMatrixTypes[type];
+ }
+
+ TIntermSequence insertionsBefore;
+ TIntermSequence insertionsAfter;
+
+ // Store the index in a temporary signed int variable.
+ // s0 = index_expr;
+ TIntermTyped *indexInitializer = EnsureSignedInt(node->getRight());
+ TIntermDeclaration *indexVariableDeclaration = nullptr;
+ TVariable *indexVariable = DeclareTempVariable(
+ mSymbolTable, indexInitializer, EvqTemporary, &indexVariableDeclaration);
+ insertionsBefore.push_back(indexVariableDeclaration);
+
+ // s1 = dyn_index(v_expr, s0);
+ TIntermAggregate *indexingCall = CreateIndexFunctionCall(
+ node, CreateTempSymbolNode(indexVariable), indexingFunction);
+ TIntermDeclaration *fieldVariableDeclaration = nullptr;
+ TVariable *fieldVariable = DeclareTempVariable(
+ mSymbolTable, indexingCall, EvqTemporary, &fieldVariableDeclaration);
+ insertionsBefore.push_back(fieldVariableDeclaration);
+
+ // dyn_index_write(v_expr, s0, s1);
+ TIntermAggregate *indexedWriteCall = CreateIndexedWriteFunctionCall(
+ node, indexVariable, fieldVariable, indexedWriteFunction);
+ insertionsAfter.push_back(indexedWriteCall);
+ insertStatementsInParentBlock(insertionsBefore, insertionsAfter);
+
+ // replace the node with s1
+ queueReplacement(CreateTempSymbolNode(fieldVariable), OriginalNode::IS_DROPPED);
+ mUsedTreeInsertion = true;
+ }
+ else
+ {
+ // The indexed value is not being written, so we can simply convert
+ // v_expr[index_expr]
+ // into
+ // dyn_index(v_expr, index_expr)
+ // If the index_expr is unsigned, we'll convert it to signed.
+ ASSERT(!mRemoveIndexSideEffectsInSubtree);
+ TIntermAggregate *indexingCall = CreateIndexFunctionCall(
+ node, EnsureSignedInt(node->getRight()), indexingFunction);
+ queueReplacement(indexingCall, OriginalNode::IS_DROPPED);
+ }
+ }
+ }
+ return !mUsedTreeInsertion;
+}
+
+void RemoveDynamicIndexingTraverser::nextIteration()
+{
+ mUsedTreeInsertion = false;
+ mRemoveIndexSideEffectsInSubtree = false;
+}
+
+} // namespace
+
+void RemoveDynamicIndexing(TIntermNode *root,
+ TSymbolTable *symbolTable,
+ PerformanceDiagnostics *perfDiagnostics)
+{
+ RemoveDynamicIndexingTraverser traverser(symbolTable, perfDiagnostics);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ } while (traverser.usedTreeInsertion());
+ // TODO(oetuaho@nvidia.com): It might be nicer to add the helper definitions also in the middle
+ // of traversal. Now the tree ends up in an inconsistent state in the middle, since there are
+ // function call nodes with no corresponding definition nodes. This needs special handling in
+ // TIntermLValueTrackingTraverser, and creates intricacies that are not easily apparent from a
+ // superficial reading of the code.
+ traverser.insertHelperDefinitions(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h
new file mode 100644
index 0000000000..500c88ed12
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of non-SSBO vectors and
+// matrices, replacing them with calls to functions that choose which component to return or write.
+// We don't need to consider dynamic indexing in SSBO since it can be directly as part of the offset
+// of RWByteAddressBuffer.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+class PerformanceDiagnostics;
+
+void RemoveDynamicIndexing(TIntermNode *root,
+ TSymbolTable *symbolTable,
+ PerformanceDiagnostics *perfDiagnostics);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp
new file mode 100644
index 0000000000..e40fe95929
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h"
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// An AST traverser that removes invariant declaration for input in fragment shader
+// when GLSL >= 4.20 and for output in vertex shader when GLSL < 4.2.
+class RemoveInvariantDeclarationTraverser : public TIntermTraverser
+{
+ public:
+ RemoveInvariantDeclarationTraverser() : TIntermTraverser(true, false, false) {}
+
+ private:
+ bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override
+ {
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement));
+ return false;
+ }
+};
+
+} // anonymous namespace
+
+void RemoveInvariantDeclaration(TIntermNode *root)
+{
+ RemoveInvariantDeclarationTraverser traverser;
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h
new file mode 100644
index 0000000000..3281014ad0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEINVARIANTDECLARATION_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REMOVEINVARIANTDECLARATION_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void RemoveInvariantDeclaration(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEINVARIANTDECLARATION_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp
new file mode 100644
index 0000000000..c270ff0f4a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp
@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
+// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
+// OpenGL drivers.
+//
+
+#include "compiler/translator/tree_ops/RemovePow.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool IsProblematicPow(TIntermTyped *node)
+{
+ TIntermAggregate *agg = node->getAsAggregate();
+ if (agg != nullptr && agg->getOp() == EOpPow)
+ {
+ ASSERT(agg->getSequence()->size() == 2);
+ return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr;
+ }
+ return false;
+}
+
+// Traverser that converts all pow operations simultaneously.
+class RemovePowTraverser : public TIntermTraverser
+{
+ public:
+ RemovePowTraverser(TSymbolTable *symbolTable);
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ void nextIteration() { mNeedAnotherIteration = false; }
+ bool needAnotherIteration() const { return mNeedAnotherIteration; }
+
+ protected:
+ bool mNeedAnotherIteration;
+};
+
+RemovePowTraverser::RemovePowTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable), mNeedAnotherIteration(false)
+{}
+
+bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (IsProblematicPow(node))
+ {
+ TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
+ TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
+
+ TIntermSequence *logArgs = new TIntermSequence();
+ logArgs->push_back(x);
+ TIntermTyped *log = CreateBuiltInFunctionCallNode("log2", logArgs, *mSymbolTable, 100);
+ log->setLine(node->getLine());
+
+ TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
+ TIntermBinary *mul = new TIntermBinary(op, y, log);
+ mul->setLine(node->getLine());
+
+ TIntermSequence *expArgs = new TIntermSequence();
+ expArgs->push_back(mul);
+ TIntermTyped *exp = CreateBuiltInFunctionCallNode("exp2", expArgs, *mSymbolTable, 100);
+ exp->setLine(node->getLine());
+
+ queueReplacement(exp, OriginalNode::IS_DROPPED);
+
+ // If the x parameter also needs to be replaced, we need to do that in another traversal,
+ // since it's parent node will change in a way that's not handled correctly by updateTree().
+ if (IsProblematicPow(x))
+ {
+ mNeedAnotherIteration = true;
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+void RemovePow(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ RemovePowTraverser traverser(symbolTable);
+ // Iterate as necessary, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ } while (traverser.needAnotherIteration());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h
new file mode 100644
index 0000000000..bb0e990656
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
+// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
+// OpenGL drivers.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEPOW_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REMOVEPOW_H_
+
+namespace sh
+{
+class TIntermNode;
+class TSymbolTable;
+
+void RemovePow(TIntermNode *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEPOW_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp
new file mode 100644
index 0000000000..9af46770f8
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp
@@ -0,0 +1,270 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveSwitchFallThrough.cpp: Remove fall-through from switch statements.
+// Note that it is unsafe to do further AST transformations on the AST generated
+// by this function. It leaves duplicate nodes in the AST making replacements
+// unreliable.
+
+#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class RemoveSwitchFallThroughTraverser : public TIntermTraverser
+{
+ public:
+ static TIntermBlock *removeFallThrough(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics);
+
+ private:
+ RemoveSwitchFallThroughTraverser(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+ bool visitBinary(Visit, TIntermBinary *node) override;
+ bool visitUnary(Visit, TIntermUnary *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+ bool visitSwizzle(Visit, TIntermSwizzle *node) override;
+ bool visitIfElse(Visit visit, TIntermIfElse *node) override;
+ bool visitSwitch(Visit, TIntermSwitch *node) override;
+ bool visitCase(Visit, TIntermCase *node) override;
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+ bool visitBlock(Visit, TIntermBlock *node) override;
+ bool visitLoop(Visit, TIntermLoop *node) override;
+ bool visitBranch(Visit, TIntermBranch *node) override;
+
+ void outputSequence(TIntermSequence *sequence, size_t startIndex);
+ void handlePreviousCase();
+
+ TIntermBlock *mStatementList;
+ TIntermBlock *mStatementListOut;
+ bool mLastStatementWasBreak;
+ TIntermBlock *mPreviousCase;
+ std::vector<TIntermBlock *> mCasesSharingBreak;
+ PerformanceDiagnostics *mPerfDiagnostics;
+};
+
+TIntermBlock *RemoveSwitchFallThroughTraverser::removeFallThrough(
+ TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics)
+{
+ RemoveSwitchFallThroughTraverser rm(statementList, perfDiagnostics);
+ ASSERT(statementList);
+ statementList->traverse(&rm);
+ ASSERT(rm.mPreviousCase || statementList->getSequence()->empty());
+ if (!rm.mLastStatementWasBreak && rm.mPreviousCase)
+ {
+ // Make sure that there's a branch at the end of the final case inside the switch statement.
+ // This also ensures that any cases that fall through to the final case will get the break.
+ TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr);
+ rm.mPreviousCase->getSequence()->push_back(finalBreak);
+ rm.mLastStatementWasBreak = true;
+ }
+ rm.handlePreviousCase();
+ return rm.mStatementListOut;
+}
+
+RemoveSwitchFallThroughTraverser::RemoveSwitchFallThroughTraverser(
+ TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics)
+ : TIntermTraverser(true, false, false),
+ mStatementList(statementList),
+ mLastStatementWasBreak(false),
+ mPreviousCase(nullptr),
+ mPerfDiagnostics(perfDiagnostics)
+{
+ mStatementListOut = new TIntermBlock();
+}
+
+void RemoveSwitchFallThroughTraverser::visitSymbol(TIntermSymbol *node)
+{
+ // Note that this assumes that switch statements which don't begin by a case statement
+ // have already been weeded out in validation.
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+}
+
+void RemoveSwitchFallThroughTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ // Conditions of case labels are not traversed, so this is a constant statement like "0;".
+ // These are no-ops so there's no need to add them back to the statement list. Should have
+ // already been pruned out of the AST, in fact.
+ UNREACHABLE();
+}
+
+bool RemoveSwitchFallThroughTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitBinary(Visit, TIntermBinary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitUnary(Visit, TIntermUnary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitTernary(Visit, TIntermTernary *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitSwizzle(Visit, TIntermSwizzle *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitIfElse(Visit, TIntermIfElse *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitSwitch(Visit, TIntermSwitch *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ // Don't go into nested switch statements
+ return false;
+}
+
+void RemoveSwitchFallThroughTraverser::outputSequence(TIntermSequence *sequence, size_t startIndex)
+{
+ for (size_t i = startIndex; i < sequence->size(); ++i)
+ {
+ mStatementListOut->getSequence()->push_back(sequence->at(i));
+ }
+}
+
+void RemoveSwitchFallThroughTraverser::handlePreviousCase()
+{
+ if (mPreviousCase)
+ mCasesSharingBreak.push_back(mPreviousCase);
+ if (mLastStatementWasBreak)
+ {
+ for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
+ {
+ ASSERT(!mCasesSharingBreak.at(i)->getSequence()->empty());
+ if (mCasesSharingBreak.at(i)->getSequence()->size() == 1)
+ {
+ // Fall-through is allowed in case the label has no statements.
+ outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0);
+ }
+ else
+ {
+ // Include all the statements that this case can fall through under the same label.
+ if (mCasesSharingBreak.size() > i + 1u)
+ {
+ mPerfDiagnostics->warning(mCasesSharingBreak.at(i)->getLine(),
+ "Performance: non-empty fall-through cases in "
+ "switch statements generate extra code.",
+ "switch");
+ }
+ for (size_t j = i; j < mCasesSharingBreak.size(); ++j)
+ {
+ size_t startIndex =
+ j > i ? 1 : 0; // Add the label only from the first sequence.
+ outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex);
+ }
+ }
+ }
+ mCasesSharingBreak.clear();
+ }
+ mLastStatementWasBreak = false;
+ mPreviousCase = nullptr;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitCase(Visit, TIntermCase *node)
+{
+ handlePreviousCase();
+ mPreviousCase = new TIntermBlock();
+ mPreviousCase->getSequence()->push_back(node);
+ mPreviousCase->setLine(node->getLine());
+ // Don't traverse the condition of the case statement
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool DoesBlockAlwaysBreak(TIntermBlock *node)
+{
+ if (node->getSequence()->empty())
+ {
+ return false;
+ }
+
+ TIntermBlock *lastStatementAsBlock = node->getSequence()->back()->getAsBlock();
+ if (lastStatementAsBlock)
+ {
+ return DoesBlockAlwaysBreak(lastStatementAsBlock);
+ }
+
+ TIntermBranch *lastStatementAsBranch = node->getSequence()->back()->getAsBranchNode();
+ return lastStatementAsBranch != nullptr;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitBlock(Visit, TIntermBlock *node)
+{
+ if (node != mStatementList)
+ {
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = DoesBlockAlwaysBreak(node);
+ return false;
+ }
+ return true;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitLoop(Visit, TIntermLoop *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ mLastStatementWasBreak = false;
+ return false;
+}
+
+bool RemoveSwitchFallThroughTraverser::visitBranch(Visit, TIntermBranch *node)
+{
+ mPreviousCase->getSequence()->push_back(node);
+ // TODO: Verify that accepting return or continue statements here doesn't cause problems.
+ mLastStatementWasBreak = true;
+ return false;
+}
+
+} // anonymous namespace
+
+TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics)
+{
+ return RemoveSwitchFallThroughTraverser::removeFallThrough(statementList, perfDiagnostics);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h
new file mode 100644
index 0000000000..58cad0c856
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveSwitchFallThrough.h: Remove fall-through from switch statements.
+// Note that it is unsafe to do further AST transformations on the AST generated
+// by this function. It leaves duplicate nodes in the AST making replacements
+// unreliable.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVESWITCHFALLTHROUGH_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REMOVESWITCHFALLTHROUGH_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class PerformanceDiagnostics;
+
+// When given a statementList from a switch AST node, return an updated
+// statementList that has fall-through removed.
+TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVESWITCHFALLTHROUGH_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp
new file mode 100644
index 0000000000..28471a309d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp
@@ -0,0 +1,371 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveUnreferencedVariables.cpp:
+// Drop variables that are declared but never referenced in the AST. This avoids adding unnecessary
+// initialization code for them. Also removes unreferenced struct types.
+//
+
+#include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h"
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class CollectVariableRefCountsTraverser : public TIntermTraverser
+{
+ public:
+ CollectVariableRefCountsTraverser();
+
+ using RefCountMap = std::unordered_map<int, unsigned int>;
+ RefCountMap &getSymbolIdRefCounts() { return mSymbolIdRefCounts; }
+ RefCountMap &getStructIdRefCounts() { return mStructIdRefCounts; }
+
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+
+ private:
+ void incrementStructTypeRefCount(const TType &type);
+
+ RefCountMap mSymbolIdRefCounts;
+
+ // Structure reference counts are counted from symbols, constructors, function calls, function
+ // return values and from interface block and structure fields. We need to track both function
+ // calls and function return values since there's a compiler option not to prune unused
+ // functions. The type of a constant union may also be a struct, but statements that are just a
+ // constant union are always pruned, and if the constant union is used somehow it will get
+ // counted by something else.
+ RefCountMap mStructIdRefCounts;
+};
+
+CollectVariableRefCountsTraverser::CollectVariableRefCountsTraverser()
+ : TIntermTraverser(true, false, false)
+{}
+
+void CollectVariableRefCountsTraverser::incrementStructTypeRefCount(const TType &type)
+{
+ if (type.isInterfaceBlock())
+ {
+ const auto *block = type.getInterfaceBlock();
+ ASSERT(block);
+
+ // We can end up incrementing ref counts of struct types referenced from an interface block
+ // multiple times for the same block. This doesn't matter, because interface blocks can't be
+ // pruned so we'll never do the reverse operation.
+ for (const auto &field : block->fields())
+ {
+ ASSERT(!field->type()->isInterfaceBlock());
+ incrementStructTypeRefCount(*field->type());
+ }
+ return;
+ }
+
+ const auto *structure = type.getStruct();
+ if (structure != nullptr)
+ {
+ auto structIter = mStructIdRefCounts.find(structure->uniqueId().get());
+ if (structIter == mStructIdRefCounts.end())
+ {
+ mStructIdRefCounts[structure->uniqueId().get()] = 1u;
+
+ for (const auto &field : structure->fields())
+ {
+ incrementStructTypeRefCount(*field->type());
+ }
+
+ return;
+ }
+ ++(structIter->second);
+ }
+}
+
+void CollectVariableRefCountsTraverser::visitSymbol(TIntermSymbol *node)
+{
+ incrementStructTypeRefCount(node->getType());
+
+ auto iter = mSymbolIdRefCounts.find(node->uniqueId().get());
+ if (iter == mSymbolIdRefCounts.end())
+ {
+ mSymbolIdRefCounts[node->uniqueId().get()] = 1u;
+ return;
+ }
+ ++(iter->second);
+}
+
+bool CollectVariableRefCountsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ // This tracks struct references in both function calls and constructors.
+ incrementStructTypeRefCount(node->getType());
+ return true;
+}
+
+void CollectVariableRefCountsTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+ incrementStructTypeRefCount(node->getType());
+ size_t paramCount = node->getFunction()->getParamCount();
+ for (size_t i = 0; i < paramCount; ++i)
+ {
+ incrementStructTypeRefCount(node->getFunction()->getParam(i)->getType());
+ }
+}
+
+// Traverser that removes all unreferenced variables on one traversal.
+class RemoveUnreferencedVariablesTraverser : public TIntermTraverser
+{
+ public:
+ RemoveUnreferencedVariablesTraverser(
+ CollectVariableRefCountsTraverser::RefCountMap *symbolIdRefCounts,
+ CollectVariableRefCountsTraverser::RefCountMap *structIdRefCounts,
+ TSymbolTable *symbolTable);
+
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ // Traverse loop and block nodes in reverse order. Note that this traverser does not track
+ // parent block positions, so insertStatementInParentBlock is unusable!
+ void traverseBlock(TIntermBlock *block) override;
+ void traverseLoop(TIntermLoop *loop) override;
+
+ private:
+ void removeVariableDeclaration(TIntermDeclaration *node, TIntermTyped *declarator);
+ void decrementStructTypeRefCount(const TType &type);
+
+ CollectVariableRefCountsTraverser::RefCountMap *mSymbolIdRefCounts;
+ CollectVariableRefCountsTraverser::RefCountMap *mStructIdRefCounts;
+ bool mRemoveReferences;
+};
+
+RemoveUnreferencedVariablesTraverser::RemoveUnreferencedVariablesTraverser(
+ CollectVariableRefCountsTraverser::RefCountMap *symbolIdRefCounts,
+ CollectVariableRefCountsTraverser::RefCountMap *structIdRefCounts,
+ TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable),
+ mSymbolIdRefCounts(symbolIdRefCounts),
+ mStructIdRefCounts(structIdRefCounts),
+ mRemoveReferences(false)
+{}
+
+void RemoveUnreferencedVariablesTraverser::decrementStructTypeRefCount(const TType &type)
+{
+ auto *structure = type.getStruct();
+ if (structure != nullptr)
+ {
+ ASSERT(mStructIdRefCounts->find(structure->uniqueId().get()) != mStructIdRefCounts->end());
+ unsigned int structRefCount = --(*mStructIdRefCounts)[structure->uniqueId().get()];
+
+ if (structRefCount == 0)
+ {
+ for (const auto &field : structure->fields())
+ {
+ decrementStructTypeRefCount(*field->type());
+ }
+ }
+ }
+}
+
+void RemoveUnreferencedVariablesTraverser::removeVariableDeclaration(TIntermDeclaration *node,
+ TIntermTyped *declarator)
+{
+ if (declarator->getType().isStructSpecifier() && !declarator->getType().isNamelessStruct())
+ {
+ unsigned int structId = declarator->getType().getStruct()->uniqueId().get();
+ unsigned int structRefCountInThisDeclarator = 1u;
+ if (declarator->getAsBinaryNode() &&
+ declarator->getAsBinaryNode()->getRight()->getAsAggregate())
+ {
+ ASSERT(declarator->getAsBinaryNode()->getLeft()->getType().getStruct() ==
+ declarator->getType().getStruct());
+ ASSERT(declarator->getAsBinaryNode()->getRight()->getType().getStruct() ==
+ declarator->getType().getStruct());
+ structRefCountInThisDeclarator = 2u;
+ }
+ if ((*mStructIdRefCounts)[structId] > structRefCountInThisDeclarator)
+ {
+ // If this declaration declares a named struct type that is used elsewhere, we need to
+ // keep it. We can still change the declarator though so that it doesn't declare an
+ // unreferenced variable.
+
+ // Note that since we're not removing the entire declaration, the struct's reference
+ // count will end up being one less than the correct refcount. But since the struct
+ // declaration is kept, the incorrect refcount can't cause any other problems.
+
+ if (declarator->getAsSymbolNode() &&
+ declarator->getAsSymbolNode()->variable().symbolType() == SymbolType::Empty)
+ {
+ // Already an empty declaration - nothing to do.
+ return;
+ }
+ TVariable *emptyVariable =
+ new TVariable(mSymbolTable, kEmptyImmutableString, new TType(declarator->getType()),
+ SymbolType::Empty);
+ queueReplacementWithParent(node, declarator, new TIntermSymbol(emptyVariable),
+ OriginalNode::IS_DROPPED);
+ return;
+ }
+ }
+
+ if (getParentNode()->getAsBlock())
+ {
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement));
+ }
+ else
+ {
+ ASSERT(getParentNode()->getAsLoopNode());
+ queueReplacement(nullptr, OriginalNode::IS_DROPPED);
+ }
+}
+
+bool RemoveUnreferencedVariablesTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ if (visit == PreVisit)
+ {
+ // SeparateDeclarations should have already been run.
+ ASSERT(node->getSequence()->size() == 1u);
+
+ TIntermTyped *declarator = node->getSequence()->back()->getAsTyped();
+ ASSERT(declarator);
+
+ // We can only remove variables that are not a part of the shader interface.
+ TQualifier qualifier = declarator->getQualifier();
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal && qualifier != EvqConst)
+ {
+ return true;
+ }
+
+ bool canRemoveVariable = false;
+ TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
+ if (symbolNode != nullptr)
+ {
+ canRemoveVariable = (*mSymbolIdRefCounts)[symbolNode->uniqueId().get()] == 1u ||
+ symbolNode->variable().symbolType() == SymbolType::Empty;
+ }
+ TIntermBinary *initNode = declarator->getAsBinaryNode();
+ if (initNode != nullptr)
+ {
+ ASSERT(initNode->getLeft()->getAsSymbolNode());
+ int symbolId = initNode->getLeft()->getAsSymbolNode()->uniqueId().get();
+ canRemoveVariable =
+ (*mSymbolIdRefCounts)[symbolId] == 1u && !initNode->getRight()->hasSideEffects();
+ }
+
+ if (canRemoveVariable)
+ {
+ removeVariableDeclaration(node, declarator);
+ mRemoveReferences = true;
+ }
+ return true;
+ }
+ ASSERT(visit == PostVisit);
+ mRemoveReferences = false;
+ return true;
+}
+
+void RemoveUnreferencedVariablesTraverser::visitSymbol(TIntermSymbol *node)
+{
+ if (mRemoveReferences)
+ {
+ ASSERT(mSymbolIdRefCounts->find(node->uniqueId().get()) != mSymbolIdRefCounts->end());
+ --(*mSymbolIdRefCounts)[node->uniqueId().get()];
+
+ decrementStructTypeRefCount(node->getType());
+ }
+}
+
+bool RemoveUnreferencedVariablesTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (visit == PreVisit && mRemoveReferences)
+ {
+ decrementStructTypeRefCount(node->getType());
+ }
+ return true;
+}
+
+void RemoveUnreferencedVariablesTraverser::traverseBlock(TIntermBlock *node)
+{
+ // We traverse blocks in reverse order. This way reference counts can be decremented when
+ // removing initializers, and variables that become unused when initializers are removed can be
+ // removed on the same traversal.
+
+ ScopedNodeInTraversalPath addToPath(this, node);
+
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = visitBlock(PreVisit, node);
+
+ if (visit)
+ {
+ for (auto iter = sequence->rbegin(); iter != sequence->rend(); ++iter)
+ {
+ (*iter)->traverse(this);
+ if (visit && inVisit)
+ {
+ if ((iter + 1) != sequence->rend())
+ visit = visitBlock(InVisit, node);
+ }
+ }
+ }
+
+ if (visit && postVisit)
+ visitBlock(PostVisit, node);
+}
+
+void RemoveUnreferencedVariablesTraverser::traverseLoop(TIntermLoop *node)
+{
+ // We traverse loops in reverse order as well. The loop body gets traversed before the init
+ // node.
+
+ ScopedNodeInTraversalPath addToPath(this, node);
+
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitLoop(PreVisit, node);
+
+ if (visit)
+ {
+ // We don't need to traverse loop expressions or conditions since they can't be declarations
+ // in the AST (loops which have a declaration in their condition get transformed in the
+ // parsing stage).
+ ASSERT(node->getExpression() == nullptr ||
+ node->getExpression()->getAsDeclarationNode() == nullptr);
+ ASSERT(node->getCondition() == nullptr ||
+ node->getCondition()->getAsDeclarationNode() == nullptr);
+
+ if (node->getBody())
+ node->getBody()->traverse(this);
+
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ }
+
+ if (visit && postVisit)
+ visitLoop(PostVisit, node);
+}
+
+} // namespace
+
+void RemoveUnreferencedVariables(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ CollectVariableRefCountsTraverser collector;
+ root->traverse(&collector);
+ RemoveUnreferencedVariablesTraverser traverser(&collector.getSymbolIdRefCounts(),
+ &collector.getStructIdRefCounts(), symbolTable);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h
new file mode 100644
index 0000000000..6888b2f2a0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RemoveUnreferencedVariables.h:
+// Drop variables that are declared but never referenced in the AST. This avoids adding unnecessary
+// initialization code for them. Also removes unreferenced struct types.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEUNREFERENCEDVARIABLES_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REMOVEUNREFERENCEDVARIABLES_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void RemoveUnreferencedVariables(TIntermBlock *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEUNREFERENCEDVARIABLES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp
new file mode 100644
index 0000000000..8e76c4862c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp
@@ -0,0 +1,462 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteAtomicCounters: Emulate atomic counter buffers with storage buffers.
+//
+
+#include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
+
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+namespace
+{
+// DeclareAtomicCountersBuffer adds a storage buffer that's used with atomic counters.
+const TVariable *DeclareAtomicCountersBuffer(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ // Define `uint counters[];` as the only field in the interface block.
+ TFieldList *fieldList = new TFieldList;
+ TType *counterType = new TType(EbtUInt);
+ counterType->makeArray(0);
+
+ TField *countersField = new TField(counterType, ImmutableString("counters"), TSourceLoc(),
+ SymbolType::AngleInternal);
+
+ fieldList->push_back(countersField);
+
+ TMemoryQualifier coherentMemory = TMemoryQualifier::Create();
+ coherentMemory.coherent = true;
+
+ // Define a storage block "ANGLEAtomicCounters" with instance name "atomicCounters".
+ return DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, coherentMemory,
+ "ANGLEAtomicCounters", "atomicCounters");
+}
+
+TIntermBinary *CreateAtomicCounterRef(const TVariable *atomicCounters, TIntermTyped *offset)
+{
+ TIntermSymbol *atomicCountersRef = new TIntermSymbol(atomicCounters);
+ TConstantUnion *firstFieldIndex = new TConstantUnion;
+ firstFieldIndex->setIConst(0);
+ TIntermConstantUnion *firstFieldRef =
+ new TIntermConstantUnion(firstFieldIndex, *StaticType::GetBasic<EbtUInt>());
+ TIntermBinary *firstField =
+ new TIntermBinary(EOpIndexDirectInterfaceBlock, atomicCountersRef, firstFieldRef);
+ return new TIntermBinary(EOpIndexDirect, firstField, offset);
+}
+
+TIntermConstantUnion *CreateUIntConstant(uint32_t value)
+{
+ const TType *constantType = StaticType::GetBasic<EbtUInt, 1>();
+ TConstantUnion *constantValue = new TConstantUnion;
+ constantValue->setUConst(value);
+ return new TIntermConstantUnion(constantValue, *constantType);
+}
+
+// Traverser that:
+//
+// 1. Converts the |atomic_uint| types to |uint|.
+// 2. Substitutes the |uniform atomic_uint| declarations with a global declaration that holds the
+// offset.
+// 3. Substitutes |atomicVar[n]| with |offset + n|.
+class RewriteAtomicCountersTraverser : public TIntermTraverser
+{
+ public:
+ RewriteAtomicCountersTraverser(TSymbolTable *symbolTable, const TVariable *atomicCounters)
+ : TIntermTraverser(true, true, true, symbolTable),
+ mAtomicCounters(atomicCounters),
+ mCurrentAtomicCounterOffset(0),
+ mCurrentAtomicCounterDecl(nullptr),
+ mCurrentAtomicCounterDeclParent(nullptr)
+ {}
+
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+
+ TIntermTyped *variable = sequence.front()->getAsTyped();
+ const TType &type = variable->getType();
+ bool isAtomicCounter = type.getQualifier() == EvqUniform && type.isAtomicCounter();
+
+ if (visit == PreVisit || visit == InVisit)
+ {
+ if (isAtomicCounter)
+ {
+ // We only support one atomic counter buffer, so the binding should necessarily be
+ // 0.
+ ASSERT(type.getLayoutQualifier().binding == 0);
+
+ mCurrentAtomicCounterDecl = node;
+ mCurrentAtomicCounterDeclParent = getParentNode()->getAsBlock();
+ mCurrentAtomicCounterOffset = type.getLayoutQualifier().offset;
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ mCurrentAtomicCounterDecl = nullptr;
+ mCurrentAtomicCounterDeclParent = nullptr;
+ mCurrentAtomicCounterOffset = 0;
+ }
+ return true;
+ }
+
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override
+ {
+ const TFunction *function = node->getFunction();
+ // Go over the parameters and replace the atomic arguments with a uint type. If this is
+ // the function definition, keep the replaced variable for future encounters.
+ mAtomicCounterFunctionParams.clear();
+ for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
+ {
+ const TVariable *param = function->getParam(paramIndex);
+ TVariable *replacement = convertFunctionParameter(node, param);
+ if (replacement)
+ {
+ mAtomicCounterFunctionParams[param] = replacement;
+ }
+ }
+
+ if (mAtomicCounterFunctionParams.empty())
+ {
+ return;
+ }
+
+ // Create a new function prototype and replace this with it.
+ TFunction *replacementFunction = new TFunction(
+ mSymbolTable, function->name(), SymbolType::UserDefined,
+ new TType(function->getReturnType()), function->isKnownToNotHaveSideEffects());
+ for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
+ {
+ const TVariable *param = function->getParam(paramIndex);
+ TVariable *replacement = nullptr;
+ if (param->getType().isAtomicCounter())
+ {
+ ASSERT(mAtomicCounterFunctionParams.count(param) != 0);
+ replacement = mAtomicCounterFunctionParams[param];
+ }
+ else
+ {
+ replacement = new TVariable(mSymbolTable, param->name(),
+ new TType(param->getType()), SymbolType::UserDefined);
+ }
+ replacementFunction->addParameter(replacement);
+ }
+
+ TIntermFunctionPrototype *replacementPrototype =
+ new TIntermFunctionPrototype(replacementFunction);
+ queueReplacement(replacementPrototype, OriginalNode::IS_DROPPED);
+
+ mReplacedFunctions[function] = replacementFunction;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit)
+ {
+ mAtomicCounterFunctionCallArgs.clear();
+ }
+
+ if (visit != PostVisit)
+ {
+ return true;
+ }
+
+ if (node->getOp() == EOpCallBuiltInFunction)
+ {
+ convertBuiltinFunction(node);
+ }
+ else if (node->getOp() == EOpCallFunctionInAST)
+ {
+ convertASTFunction(node);
+ }
+
+ return true;
+ }
+
+ void visitSymbol(TIntermSymbol *symbol) override
+ {
+ const TVariable *symbolVariable = &symbol->variable();
+
+ if (mCurrentAtomicCounterDecl)
+ {
+ declareAtomicCounter(symbolVariable);
+ return;
+ }
+
+ if (!symbol->getType().isAtomicCounter())
+ {
+ return;
+ }
+
+ // The symbol is either referencing a global atomic counter, or is a function parameter. In
+ // either case, it could be an array. The are the following possibilities:
+ //
+ // layout(..) uniform atomic_uint ac;
+ // layout(..) uniform atomic_uint acArray[N];
+ //
+ // void func(inout atomic_uint c)
+ // {
+ // otherFunc(c);
+ // }
+ //
+ // void funcArray(inout atomic_uint cArray[N])
+ // {
+ // otherFuncArray(cArray);
+ // otherFunc(cArray[n]);
+ // }
+ //
+ // void funcGlobal()
+ // {
+ // func(ac);
+ // func(acArray[n]);
+ // funcArray(acArray);
+ // atomicIncrement(ac);
+ // atomicIncrement(acArray[n]);
+ // }
+ //
+ // This should translate to:
+ //
+ // buffer ANGLEAtomicCounters
+ // {
+ // uint counters[];
+ // } atomicCounters;
+ //
+ // const uint ac = <offset>;
+ // const uint acArray = <offset>;
+ //
+ // void func(inout uint c)
+ // {
+ // otherFunc(c);
+ // }
+ //
+ // void funcArray(inout uint cArray)
+ // {
+ // otherFuncArray(cArray);
+ // otherFunc(cArray + n);
+ // }
+ //
+ // void funcGlobal()
+ // {
+ // func(ac);
+ // func(acArray+n);
+ // funcArray(acArray);
+ // atomicAdd(atomicCounters.counters[ac]);
+ // atomicAdd(atomicCounters.counters[ac+n]);
+ // }
+ //
+ // In all cases, the argument transformation is stored in |mAtomicCounterFunctionCallArgs|.
+ // In the function call's PostVisit, if it's a builtin, the look up in
+ // |atomicCounters.counters| is done as well as the builtin function change. Otherwise,
+ // the transformed argument is passed on as is.
+ //
+
+ TIntermTyped *offset = nullptr;
+ if (mAtomicCounterOffsets.count(symbolVariable) != 0)
+ {
+ offset = new TIntermSymbol(mAtomicCounterOffsets[symbolVariable]);
+ }
+ else
+ {
+ ASSERT(mAtomicCounterFunctionParams.count(symbolVariable) != 0);
+ offset = new TIntermSymbol(mAtomicCounterFunctionParams[symbolVariable]);
+ }
+
+ TIntermNode *argument = symbol;
+
+ TIntermNode *parent = getParentNode();
+ ASSERT(parent);
+
+ TIntermBinary *arrayExpression = parent->getAsBinaryNode();
+ if (arrayExpression)
+ {
+ ASSERT(arrayExpression->getOp() == EOpIndexDirect ||
+ arrayExpression->getOp() == EOpIndexIndirect);
+
+ offset = new TIntermBinary(EOpAdd, offset, arrayExpression->getRight()->deepCopy());
+ argument = arrayExpression;
+ }
+
+ mAtomicCounterFunctionCallArgs[argument] = offset;
+ }
+
+ private:
+ void declareAtomicCounter(const TVariable *symbolVariable)
+ {
+ // Create a global variable that contains the offset of this atomic counter declaration.
+ TType *uintType = new TType(*StaticType::GetBasic<EbtUInt, 1>());
+ uintType->setQualifier(EvqConst);
+ TVariable *offset =
+ new TVariable(mSymbolTable, symbolVariable->name(), uintType, SymbolType::UserDefined);
+
+ ASSERT(mCurrentAtomicCounterOffset % 4 == 0);
+ TIntermConstantUnion *offsetInitValue = CreateIndexNode(mCurrentAtomicCounterOffset / 4);
+
+ TIntermSymbol *offsetSymbol = new TIntermSymbol(offset);
+ TIntermBinary *offsetInit = new TIntermBinary(EOpInitialize, offsetSymbol, offsetInitValue);
+
+ TIntermDeclaration *offsetDeclaration = new TIntermDeclaration();
+ offsetDeclaration->appendDeclarator(offsetInit);
+
+ // Replace the atomic_uint declaration with the offset declaration.
+ TIntermSequence replacement;
+ replacement.push_back(offsetDeclaration);
+ mMultiReplacements.emplace_back(mCurrentAtomicCounterDeclParent, mCurrentAtomicCounterDecl,
+ replacement);
+
+ // Remember the offset variable.
+ mAtomicCounterOffsets[symbolVariable] = offset;
+ }
+
+ TVariable *convertFunctionParameter(TIntermNode *parent, const TVariable *param)
+ {
+ if (!param->getType().isAtomicCounter())
+ {
+ return nullptr;
+ }
+
+ const TType *newType = StaticType::GetBasic<EbtUInt>();
+
+ TVariable *replacementVar =
+ new TVariable(mSymbolTable, param->name(), newType, SymbolType::UserDefined);
+
+ return replacementVar;
+ }
+
+ void convertBuiltinFunction(TIntermAggregate *node)
+ {
+ // If the function is |memoryBarrierAtomicCounter|, simply replace it with
+ // |memoryBarrierBuffer|.
+ if (node->getFunction()->name() == "memoryBarrierAtomicCounter")
+ {
+ TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode(
+ "memoryBarrierBuffer", new TIntermSequence, *mSymbolTable, 310);
+ queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
+ return;
+ }
+
+ // If it's an |atomicCounter*| function, replace the function with an |atomic*| equivalent.
+ if (!node->getFunction()->isAtomicCounterFunction())
+ {
+ return;
+ }
+
+ const ImmutableString &functionName = node->getFunction()->name();
+ TIntermSequence *arguments = node->getSequence();
+
+ // Note: atomicAdd(0) is used for atomic reads.
+ uint32_t valueChange = 0;
+ constexpr char kAtomicAddFunction[] = "atomicAdd";
+ bool isDecrement = false;
+
+ if (functionName == "atomicCounterIncrement")
+ {
+ valueChange = 1;
+ }
+ else if (functionName == "atomicCounterDecrement")
+ {
+ // uint values are required to wrap around, so 0xFFFFFFFFu is used as -1.
+ valueChange = std::numeric_limits<uint32_t>::max();
+ static_assert(static_cast<uint32_t>(-1) == std::numeric_limits<uint32_t>::max(),
+ "uint32_t max is not -1");
+
+ isDecrement = true;
+ }
+ else
+ {
+ ASSERT(functionName == "atomicCounter");
+ }
+
+ const TIntermNode *param = (*arguments)[0];
+ ASSERT(mAtomicCounterFunctionCallArgs.count(param) != 0);
+
+ TIntermTyped *offset = mAtomicCounterFunctionCallArgs[param];
+
+ TIntermSequence *substituteArguments = new TIntermSequence;
+ substituteArguments->push_back(CreateAtomicCounterRef(mAtomicCounters, offset));
+ substituteArguments->push_back(CreateUIntConstant(valueChange));
+
+ TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode(
+ kAtomicAddFunction, substituteArguments, *mSymbolTable, 310);
+
+ // Note that atomicCounterDecrement returns the *new* value instead of the prior value,
+ // unlike atomicAdd. So we need to do a -1 on the result as well.
+ if (isDecrement)
+ {
+ substituteCall = new TIntermBinary(EOpSub, substituteCall, CreateUIntConstant(1));
+ }
+
+ queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
+ }
+
+ void convertASTFunction(TIntermAggregate *node)
+ {
+ // See if the function needs replacement at all.
+ const TFunction *function = node->getFunction();
+ if (mReplacedFunctions.count(function) == 0)
+ {
+ return;
+ }
+
+ // atomic_uint arguments to this call are staged to be replaced at the same time.
+ TFunction *substituteFunction = mReplacedFunctions[function];
+ TIntermSequence *substituteArguments = new TIntermSequence;
+
+ for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
+ {
+ TIntermNode *param = node->getChildNode(paramIndex);
+
+ TIntermNode *replacement = nullptr;
+ if (param->getAsTyped()->getType().isAtomicCounter())
+ {
+ ASSERT(mAtomicCounterFunctionCallArgs.count(param) != 0);
+ replacement = mAtomicCounterFunctionCallArgs[param];
+ }
+ else
+ {
+ replacement = param->getAsTyped()->deepCopy();
+ }
+ substituteArguments->push_back(replacement);
+ }
+
+ TIntermTyped *substituteCall =
+ TIntermAggregate::CreateFunctionCall(*substituteFunction, substituteArguments);
+
+ queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
+ }
+
+ private:
+ const TVariable *mAtomicCounters;
+
+ // A map from the atomic_uint variable to the offset declaration.
+ std::unordered_map<const TVariable *, TVariable *> mAtomicCounterOffsets;
+ // A map from functions with atomic_uint parameters to one where that's replaced with uint.
+ std::unordered_map<const TFunction *, TFunction *> mReplacedFunctions;
+ // A map from atomic_uint function parameters to their replacement uint parameter for the
+ // current function definition.
+ std::unordered_map<const TVariable *, TVariable *> mAtomicCounterFunctionParams;
+ // A map from atomic_uint function call arguments to their replacement for the current
+ // non-builtin function call.
+ std::unordered_map<const TIntermNode *, TIntermTyped *> mAtomicCounterFunctionCallArgs;
+
+ uint32_t mCurrentAtomicCounterOffset;
+ TIntermDeclaration *mCurrentAtomicCounterDecl;
+ TIntermAggregateBase *mCurrentAtomicCounterDeclParent;
+};
+
+} // anonymous namespace
+
+void RewriteAtomicCounters(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ const TVariable *atomicCounters = DeclareAtomicCountersBuffer(root, symbolTable);
+
+ RewriteAtomicCountersTraverser traverser(symbolTable, atomicCounters);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h
new file mode 100644
index 0000000000..905b258bd7
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h
@@ -0,0 +1,21 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteAtomicCounters: Change atomic counter buffers to storage buffers, with atomic counter
+// variables being offsets into the uint array of that storage buffer.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEATOMICCOUNTERS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITEATOMICCOUNTERS_H_
+
+namespace sh
+{
+class TIntermBlock;
+class TSymbolTable;
+class TVariable;
+
+void RewriteAtomicCounters(TIntermBlock *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEATOMICCOUNTERS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp
new file mode 100644
index 0000000000..f47e790b0a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp
@@ -0,0 +1,182 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of the function RewriteAtomicFunctionExpressions.
+// See the header for more details.
+
+#include "RewriteAtomicFunctionExpressions.h"
+
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+namespace
+{
+// Traverser that simplifies all the atomic function expressions into the ones that can be directly
+// translated into HLSL.
+//
+// case 1 (only for atomicExchange and atomicCompSwap):
+// original:
+// atomicExchange(counter, newValue);
+// new:
+// tempValue = atomicExchange(counter, newValue);
+//
+// case 2 (atomic function, temporary variable required):
+// original:
+// value = atomicAdd(counter, 1) * otherValue;
+// someArray[atomicAdd(counter, 1)] = someOtherValue;
+// new:
+// value = ((tempValue = atomicAdd(counter, 1)), tempValue) * otherValue;
+// someArray[((tempValue = atomicAdd(counter, 1)), tempValue)] = someOtherValue;
+//
+// case 3 (atomic function used directly initialize a variable):
+// original:
+// int value = atomicAdd(counter, 1);
+// new:
+// tempValue = atomicAdd(counter, 1);
+// int value = tempValue;
+//
+class RewriteAtomicFunctionExpressionsTraverser : public TIntermTraverser
+{
+ public:
+ RewriteAtomicFunctionExpressionsTraverser(TSymbolTable *symbolTable, int shaderVersion);
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+
+ private:
+ static bool IsAtomicExchangeOrCompSwapNoReturnValue(TIntermAggregate *node,
+ TIntermNode *parentNode);
+ static bool IsAtomicFunctionInsideExpression(TIntermAggregate *node, TIntermNode *parentNode);
+
+ void rewriteAtomicFunctionCallNode(TIntermAggregate *oldAtomicFunctionNode);
+
+ const TVariable *getTempVariable(const TType *type);
+
+ int mShaderVersion;
+ TIntermSequence mTempVariables;
+};
+
+RewriteAtomicFunctionExpressionsTraverser::RewriteAtomicFunctionExpressionsTraverser(
+ TSymbolTable *symbolTable,
+ int shaderVersion)
+ : TIntermTraverser(false, false, true, symbolTable), mShaderVersion(shaderVersion)
+{}
+
+void RewriteAtomicFunctionExpressionsTraverser::rewriteAtomicFunctionCallNode(
+ TIntermAggregate *oldAtomicFunctionNode)
+{
+ ASSERT(oldAtomicFunctionNode);
+
+ const TVariable *returnVariable = getTempVariable(&oldAtomicFunctionNode->getType());
+
+ TIntermBinary *rewrittenNode = new TIntermBinary(
+ TOperator::EOpAssign, CreateTempSymbolNode(returnVariable), oldAtomicFunctionNode);
+
+ auto *parentNode = getParentNode();
+
+ auto *parentBinary = parentNode->getAsBinaryNode();
+ if (parentBinary && parentBinary->getOp() == EOpInitialize)
+ {
+ insertStatementInParentBlock(rewrittenNode);
+ queueReplacement(CreateTempSymbolNode(returnVariable), OriginalNode::IS_DROPPED);
+ }
+ else
+ {
+ // As all atomic function assignment will be converted to the last argument of an
+ // interlocked function, if we need the return value, assignment needs to be wrapped with
+ // the comma operator and the temporary variables.
+ if (!parentNode->getAsBlock())
+ {
+ rewrittenNode = TIntermBinary::CreateComma(
+ rewrittenNode, new TIntermSymbol(returnVariable), mShaderVersion);
+ }
+
+ queueReplacement(rewrittenNode, OriginalNode::IS_DROPPED);
+ }
+}
+
+const TVariable *RewriteAtomicFunctionExpressionsTraverser::getTempVariable(const TType *type)
+{
+ TIntermDeclaration *variableDeclaration;
+ TVariable *returnVariable =
+ DeclareTempVariable(mSymbolTable, type, EvqTemporary, &variableDeclaration);
+ mTempVariables.push_back(variableDeclaration);
+ return returnVariable;
+}
+
+bool RewriteAtomicFunctionExpressionsTraverser::IsAtomicExchangeOrCompSwapNoReturnValue(
+ TIntermAggregate *node,
+ TIntermNode *parentNode)
+{
+ ASSERT(node);
+ return (node->getOp() == EOpAtomicExchange || node->getOp() == EOpAtomicCompSwap) &&
+ parentNode && parentNode->getAsBlock();
+}
+
+bool RewriteAtomicFunctionExpressionsTraverser::IsAtomicFunctionInsideExpression(
+ TIntermAggregate *node,
+ TIntermNode *parentNode)
+{
+ ASSERT(node);
+ // We only need to handle atomic functions with a parent that it is not block nodes. If the
+ // parent node is block, it means that the atomic function is not inside an expression.
+ if (!IsAtomicFunction(node->getOp()) || parentNode->getAsBlock())
+ {
+ return false;
+ }
+
+ auto *parentAsBinary = parentNode->getAsBinaryNode();
+ // Assignments are handled in OutputHLSL
+ return !parentAsBinary || parentAsBinary->getOp() != EOpAssign;
+}
+
+bool RewriteAtomicFunctionExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ ASSERT(visit == PostVisit);
+ // Skip atomic memory functions for SSBO. They will be processed in the OutputHLSL traverser.
+ if (IsAtomicFunction(node->getOp()) &&
+ IsInShaderStorageBlock((*node->getSequence())[0]->getAsTyped()))
+ {
+ return false;
+ }
+
+ TIntermNode *parentNode = getParentNode();
+ if (IsAtomicExchangeOrCompSwapNoReturnValue(node, parentNode) ||
+ IsAtomicFunctionInsideExpression(node, parentNode))
+ {
+ rewriteAtomicFunctionCallNode(node);
+ }
+
+ return true;
+}
+
+bool RewriteAtomicFunctionExpressionsTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+ ASSERT(visit == PostVisit);
+
+ if (!mTempVariables.empty() && getParentNode()->getAsFunctionDefinition())
+ {
+ insertStatementsInBlockAtPosition(node, 0, mTempVariables, TIntermSequence());
+ mTempVariables.clear();
+ }
+
+ return true;
+}
+
+} // anonymous namespace
+
+void RewriteAtomicFunctionExpressions(TIntermNode *root,
+ TSymbolTable *symbolTable,
+ int shaderVersion)
+{
+ RewriteAtomicFunctionExpressionsTraverser traverser(symbolTable, shaderVersion);
+ traverser.traverse(root);
+ traverser.updateTree();
+}
+} // namespace sh \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h
new file mode 100644
index 0000000000..a54440536e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteAtomicFunctionExpressions rewrites the expressions that contain
+// atomic function calls and cannot be directly translated into HLSL into
+// several simple ones that can be easily handled in the HLSL translator.
+//
+// We need to rewite these expressions because:
+// 1. All GLSL atomic functions have return values, which all represent the
+// original value of the shared or ssbo variable; while all HLSL atomic
+// functions don't, and the original value can be stored in the last
+// parameter of the function call.
+// 2. For HLSL atomic functions, the last parameter that stores the original
+// value is optional except for InterlockedExchange and
+// InterlockedCompareExchange. Missing original_value in the call of
+// InterlockedExchange or InterlockedCompareExchange results in a compile
+// error from HLSL compiler.
+//
+// RewriteAtomicFunctionExpressions is a function that can modify the AST
+// to ensure all the expressions that contain atomic function calls can be
+// directly translated into HLSL expressions.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_ATOMIC_FUNCTION_EXPRESSIONS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_ATOMIC_FUNCTION_EXPRESSIONS_H_
+
+namespace sh
+{
+class TIntermNode;
+class TSymbolTable;
+
+void RewriteAtomicFunctionExpressions(TIntermNode *root,
+ TSymbolTable *symbolTable,
+ int shaderVersion);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_ATOMIC_FUNCTION_EXPRESSIONS_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp
new file mode 100644
index 0000000000..80606e7844
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp
@@ -0,0 +1,89 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of dFdy viewport transformation.
+// See header for more info.
+
+#include "compiler/translator/tree_ops/RewriteDfdy.h"
+
+#include "common/angleutils.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root,
+ const TSymbolTable &symbolTable,
+ TIntermBinary *viewportYScale);
+
+ private:
+ Traverser(TIntermBinary *viewportYScale, TSymbolTable *symbolTable);
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+
+ TIntermBinary *mViewportYScale = nullptr;
+};
+
+Traverser::Traverser(TIntermBinary *viewportYScale, TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable), mViewportYScale(viewportYScale)
+{}
+
+// static
+void Traverser::Apply(TIntermNode *root,
+ const TSymbolTable &symbolTable,
+ TIntermBinary *viewportYScale)
+{
+ TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable);
+ Traverser traverser(viewportYScale, pSymbolTable);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ // Decide if the node represents a call to dFdy()
+ if (node->getOp() != EOpDFdy)
+ {
+ return true;
+ }
+
+ // Copy the dFdy node so we can replace it with the corrected value
+ TIntermUnary *newDfdy = node->deepCopy()->getAsUnaryNode();
+
+ size_t objectSize = node->getType().getObjectSize();
+ TOperator multiplyOp = (objectSize == 1) ? EOpMul : EOpVectorTimesScalar;
+
+ // Correct dFdy()'s value:
+ // (dFdy() * ANGLEUniforms.viewportYScale)
+ TIntermBinary *correctedDfdy = new TIntermBinary(multiplyOp, newDfdy, mViewportYScale);
+
+ // Replace the old dFdy node with the new node that contains the corrected value
+ queueReplacement(correctedDfdy, OriginalNode::IS_DROPPED);
+
+ return true;
+}
+
+} // anonymous namespace
+
+void RewriteDfdy(TIntermNode *root,
+ const TSymbolTable &symbolTable,
+ int shaderVersion,
+ TIntermBinary *viewportYScale)
+{
+ // dFdy is only valid in GLSL 3.0 and later.
+ if (shaderVersion < 300)
+ return;
+
+ Traverser::Apply(root, symbolTable, viewportYScale);
+}
+
+} // namespace sh \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h
new file mode 100644
index 0000000000..299d3652f9
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h
@@ -0,0 +1,30 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This mutating tree traversal flips the output of dFdy() to account for framebuffer flipping.
+//
+// From: dFdy(p)
+// To: (dFdy(p) * viewportYScale)
+//
+// See http://anglebug.com/3487
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_FLIP_DFDY_H_
+#define COMPILER_TRANSLATOR_TREEOPS_FLIP_DFDY_H_
+
+class TIntermNode;
+class TIntermBinary;
+class TSymbolTable;
+
+namespace sh
+{
+
+void RewriteDfdy(TIntermNode *root,
+ const TSymbolTable &symbolTable,
+ int shaderVersion,
+ TIntermBinary *viewportYScale);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_FLIP_DFDY_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp
new file mode 100644
index 0000000000..7956322a5a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp
@@ -0,0 +1,144 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RewriteDoWhile.cpp: rewrites do-while loops using another equivalent
+// construct.
+
+#include "compiler/translator/tree_ops/RewriteDoWhile.h"
+
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// An AST traverser that rewrites loops of the form
+// do {
+// CODE;
+// } while (CONDITION)
+//
+// to loops of the form
+// bool temp = false;
+// while (true) {
+// if (temp) {
+// if (!CONDITION) {
+// break;
+// }
+// }
+// temp = true;
+// CODE;
+// }
+//
+// The reason we don't use a simpler form, with for example just (temp && !CONDITION) in the
+// while condition, is that short-circuit is often badly supported by driver shader compiler.
+// The double if has the same effect, but forces shader compilers to behave.
+//
+// TODO(cwallez) when UnfoldShortCircuitIntoIf handles loops correctly, revisit this as we might
+// be able to use while (temp || CONDITION) with temp initially set to true then run
+// UnfoldShortCircuitIntoIf
+class DoWhileRewriter : public TIntermTraverser
+{
+ public:
+ DoWhileRewriter(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable)
+ {}
+
+ bool visitBlock(Visit, TIntermBlock *node) override
+ {
+ // A well-formed AST can only have do-while inside TIntermBlock. By doing a prefix traversal
+ // we are able to replace the do-while in the sequence directly as the content of the
+ // do-while will be traversed later.
+
+ TIntermSequence *statements = node->getSequence();
+
+ // The statements vector will have new statements inserted when we encounter a do-while,
+ // which prevents us from using a range-based for loop. Using the usual i++ works, as
+ // the (two) new statements inserted replace the statement at the current position.
+ for (size_t i = 0; i < statements->size(); i++)
+ {
+ TIntermNode *statement = (*statements)[i];
+ TIntermLoop *loop = statement->getAsLoopNode();
+
+ if (loop == nullptr || loop->getType() != ELoopDoWhile)
+ {
+ continue;
+ }
+
+ // Found a loop to change.
+ const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
+ TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType);
+
+ // bool temp = false;
+ TIntermDeclaration *tempDeclaration =
+ CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(false));
+
+ // temp = true;
+ TIntermBinary *assignTrue =
+ CreateTempAssignmentNode(conditionVariable, CreateBoolNode(true));
+
+ // if (temp) {
+ // if (!CONDITION) {
+ // break;
+ // }
+ // }
+ TIntermIfElse *breakIf = nullptr;
+ {
+ TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr);
+
+ TIntermBlock *breakBlock = new TIntermBlock();
+ breakBlock->getSequence()->push_back(breakStatement);
+
+ TIntermUnary *negatedCondition =
+ new TIntermUnary(EOpLogicalNot, loop->getCondition(), nullptr);
+
+ TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr);
+
+ TIntermBlock *innerIfBlock = new TIntermBlock();
+ innerIfBlock->getSequence()->push_back(innerIf);
+
+ breakIf = new TIntermIfElse(CreateTempSymbolNode(conditionVariable), innerIfBlock,
+ nullptr);
+ }
+
+ // Assemble the replacement loops, reusing the do-while loop's body and inserting our
+ // statements at the front.
+ TIntermLoop *newLoop = nullptr;
+ {
+ TIntermBlock *body = loop->getBody();
+ if (body == nullptr)
+ {
+ body = new TIntermBlock();
+ }
+ auto sequence = body->getSequence();
+ sequence->insert(sequence->begin(), assignTrue);
+ sequence->insert(sequence->begin(), breakIf);
+
+ newLoop = new TIntermLoop(ELoopWhile, nullptr, CreateBoolNode(true), nullptr, body);
+ }
+
+ TIntermSequence replacement;
+ replacement.push_back(tempDeclaration);
+ replacement.push_back(newLoop);
+
+ node->replaceChildNodeWithMultiple(loop, replacement);
+ }
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void RewriteDoWhile(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ DoWhileRewriter rewriter(symbolTable);
+
+ root->traverse(&rewriter);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h
new file mode 100644
index 0000000000..c91d7deb06
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RewriteDoWhile.h: rewrite do-while loops as while loops to work around
+// driver bugs
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEDOWHILE_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITEDOWHILE_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void RewriteDoWhile(TIntermNode *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEDOWHILE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp
new file mode 100644
index 0000000000..701e29aa9d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp
@@ -0,0 +1,120 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteElseBlocks.cpp: Implementation for tree transform to change
+// all if-else blocks to if-if blocks.
+//
+
+#include "compiler/translator/tree_ops/RewriteElseBlocks.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/NodeSearch.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class ElseBlockRewriter : public TIntermTraverser
+{
+ public:
+ ElseBlockRewriter(TSymbolTable *symbolTable);
+
+ protected:
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override;
+ bool visitBlock(Visit visit, TIntermBlock *block) override;
+
+ private:
+ TIntermNode *rewriteIfElse(TIntermIfElse *ifElse);
+
+ const TType *mFunctionType;
+};
+
+ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr)
+{}
+
+bool ElseBlockRewriter::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ // Store the current function context (see comment below)
+ mFunctionType = ((visit == PreVisit) ? &node->getFunctionPrototype()->getType() : nullptr);
+ return true;
+}
+
+bool ElseBlockRewriter::visitBlock(Visit visit, TIntermBlock *node)
+{
+ if (visit == PostVisit)
+ {
+ for (size_t statementIndex = 0; statementIndex != node->getSequence()->size();
+ statementIndex++)
+ {
+ TIntermNode *statement = (*node->getSequence())[statementIndex];
+ TIntermIfElse *ifElse = statement->getAsIfElseNode();
+ if (ifElse && ifElse->getFalseBlock() != nullptr)
+ {
+ (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse);
+ }
+ }
+ }
+ return true;
+}
+
+TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse)
+{
+ ASSERT(ifElse != nullptr);
+
+ TIntermDeclaration *storeCondition = nullptr;
+ TVariable *conditionVariable =
+ DeclareTempVariable(mSymbolTable, ifElse->getCondition(), EvqTemporary, &storeCondition);
+
+ TIntermBlock *falseBlock = nullptr;
+
+ TType boolType(EbtBool, EbpUndefined, EvqTemporary);
+
+ if (ifElse->getFalseBlock())
+ {
+ TIntermBlock *negatedElse = nullptr;
+ // crbug.com/346463
+ // D3D generates error messages claiming a function has no return value, when rewriting
+ // an if-else clause that returns something non-void in a function. By appending dummy
+ // returns (that are unreachable) we can silence this compile error.
+ if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
+ {
+ TIntermNode *returnNode = new TIntermBranch(EOpReturn, CreateZeroNode(*mFunctionType));
+ negatedElse = new TIntermBlock();
+ negatedElse->appendStatement(returnNode);
+ }
+
+ TIntermSymbol *conditionSymbolElse = CreateTempSymbolNode(conditionVariable);
+ TIntermUnary *negatedCondition =
+ new TIntermUnary(EOpLogicalNot, conditionSymbolElse, nullptr);
+ TIntermIfElse *falseIfElse =
+ new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse);
+ falseBlock = EnsureBlock(falseIfElse);
+ }
+
+ TIntermSymbol *conditionSymbolSel = CreateTempSymbolNode(conditionVariable);
+ TIntermIfElse *newIfElse =
+ new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock);
+
+ TIntermBlock *block = new TIntermBlock();
+ block->getSequence()->push_back(storeCondition);
+ block->getSequence()->push_back(newIfElse);
+
+ return block;
+}
+
+} // anonymous namespace
+
+void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable)
+{
+ ElseBlockRewriter rewriter(symbolTable);
+ node->traverse(&rewriter);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h
new file mode 100644
index 0000000000..3ae3b4a710
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteElseBlocks.h: Prototype for tree transform to change
+// all if-else blocks to if-if blocks.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEELSEBLOCKS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITEELSEBLOCKS_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEELSEBLOCKS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp
new file mode 100644
index 0000000000..9228f5b4ec
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp
@@ -0,0 +1,411 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteExpressionsWithShaderStorageBlock rewrites the expressions that contain shader storage
+// block calls into several simple ones that can be easily handled in the HLSL translator. After the
+// AST pass, all ssbo related blocks will be like below:
+// ssbo_access_chain = ssbo_access_chain;
+// ssbo_access_chain = expr_no_ssbo;
+// lvalue_no_ssbo = ssbo_access_chain;
+//
+
+#include "compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h"
+
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+namespace
+{
+
+bool IsIncrementOrDecrementOperator(TOperator op)
+{
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IsCompoundAssignment(TOperator op)
+{
+ switch (op)
+ {
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// EOpIndexDirect, EOpIndexIndirect, EOpIndexDirectStruct, EOpIndexDirectInterfaceBlock belong to
+// operators in SSBO access chain.
+bool IsReadonlyBinaryOperatorNotInSSBOAccessChain(TOperator op)
+{
+ switch (op)
+ {
+ case EOpComma:
+ case EOpAdd:
+ case EOpSub:
+ case EOpMul:
+ case EOpDiv:
+ case EOpIMod:
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesMatrix:
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool HasSSBOAsFunctionArgument(TIntermSequence *arguments)
+{
+ for (TIntermNode *arg : *arguments)
+ {
+ TIntermTyped *typedArg = arg->getAsTyped();
+ if (IsInShaderStorageBlock(typedArg))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+class RewriteExpressionsWithShaderStorageBlockTraverser : public TIntermTraverser
+{
+ public:
+ RewriteExpressionsWithShaderStorageBlockTraverser(TSymbolTable *symbolTable);
+ void nextIteration();
+ bool foundSSBO() const { return mFoundSSBO; }
+
+ private:
+ bool visitBinary(Visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+
+ TIntermSymbol *insertInitStatementAndReturnTempSymbol(TIntermTyped *node,
+ TIntermSequence *insertions);
+
+ bool mFoundSSBO;
+};
+
+RewriteExpressionsWithShaderStorageBlockTraverser::
+ RewriteExpressionsWithShaderStorageBlockTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, true, false, symbolTable), mFoundSSBO(false)
+{}
+
+TIntermSymbol *
+RewriteExpressionsWithShaderStorageBlockTraverser::insertInitStatementAndReturnTempSymbol(
+ TIntermTyped *node,
+ TIntermSequence *insertions)
+{
+ TIntermDeclaration *variableDeclaration;
+ TVariable *tempVariable =
+ DeclareTempVariable(mSymbolTable, node, EvqTemporary, &variableDeclaration);
+
+ insertions->push_back(variableDeclaration);
+ return CreateTempSymbolNode(tempVariable);
+}
+
+bool RewriteExpressionsWithShaderStorageBlockTraverser::visitBinary(Visit visit,
+ TIntermBinary *node)
+{
+ // Make sure that the expression is caculated from left to right.
+ if (visit != InVisit)
+ {
+ return true;
+ }
+
+ if (mFoundSSBO)
+ {
+ return false;
+ }
+
+ bool rightSSBO = IsInShaderStorageBlock(node->getRight());
+ bool leftSSBO = IsInShaderStorageBlock(node->getLeft());
+ if (!leftSSBO && !rightSSBO)
+ {
+ return true;
+ }
+
+ // case 1: Compound assigment operator
+ // original:
+ // lssbo += expr;
+ // new:
+ // var rvalue = expr;
+ // var temp = lssbo;
+ // temp += rvalue;
+ // lssbo = temp;
+ //
+ // original:
+ // lvalue_no_ssbo += rssbo;
+ // new:
+ // var rvalue = rssbo;
+ // lvalue_no_ssbo += rvalue;
+ if (IsCompoundAssignment(node->getOp()))
+ {
+ mFoundSSBO = true;
+ TIntermSequence insertions;
+ TIntermTyped *rightNode =
+ insertInitStatementAndReturnTempSymbol(node->getRight(), &insertions);
+ if (leftSSBO)
+ {
+ TIntermSymbol *tempSymbol =
+ insertInitStatementAndReturnTempSymbol(node->getLeft()->deepCopy(), &insertions);
+ TIntermBinary *tempCompoundOperate =
+ new TIntermBinary(node->getOp(), tempSymbol->deepCopy(), rightNode->deepCopy());
+ insertions.push_back(tempCompoundOperate);
+ insertStatementsInParentBlock(insertions);
+
+ TIntermBinary *assignTempValueToSSBO =
+ new TIntermBinary(EOpAssign, node->getLeft(), tempSymbol->deepCopy());
+ queueReplacement(assignTempValueToSSBO, OriginalNode::IS_DROPPED);
+ }
+ else
+ {
+ insertStatementsInParentBlock(insertions);
+ TIntermBinary *compoundAssignRValueToLValue =
+ new TIntermBinary(node->getOp(), node->getLeft(), rightNode->deepCopy());
+ queueReplacement(compoundAssignRValueToLValue, OriginalNode::IS_DROPPED);
+ }
+ }
+ // case 2: Readonly binary operator
+ // original:
+ // ssbo0 + ssbo1 + ssbo2;
+ // new:
+ // var temp0 = ssbo0;
+ // var temp1 = ssbo1;
+ // var temp2 = ssbo2;
+ // temp0 + temp1 + temp2;
+ else if (IsReadonlyBinaryOperatorNotInSSBOAccessChain(node->getOp()) && (leftSSBO || rightSSBO))
+ {
+ mFoundSSBO = true;
+ TIntermTyped *rightNode = node->getRight();
+ TIntermTyped *leftNode = node->getLeft();
+ TIntermSequence insertions;
+ if (rightSSBO)
+ {
+ rightNode = insertInitStatementAndReturnTempSymbol(node->getRight(), &insertions);
+ }
+ if (leftSSBO)
+ {
+ leftNode = insertInitStatementAndReturnTempSymbol(node->getLeft(), &insertions);
+ }
+
+ insertStatementsInParentBlock(insertions);
+ TIntermBinary *newExpr =
+ new TIntermBinary(node->getOp(), leftNode->deepCopy(), rightNode->deepCopy());
+ queueReplacement(newExpr, OriginalNode::IS_DROPPED);
+ }
+ return !mFoundSSBO;
+}
+
+// case 3: ssbo as the argument of aggregate type
+// original:
+// foo(ssbo);
+// new:
+// var tempArg = ssbo;
+// foo(tempArg);
+// ssbo = tempArg; (Optional based on whether ssbo is an out|input argument)
+//
+// original:
+// foo(ssbo) * expr;
+// new:
+// var tempArg = ssbo;
+// var tempReturn = foo(tempArg);
+// ssbo = tempArg; (Optional based on whether ssbo is an out|input argument)
+// tempReturn * expr;
+bool RewriteExpressionsWithShaderStorageBlockTraverser::visitAggregate(Visit visit,
+ TIntermAggregate *node)
+{
+ // Make sure that visitAggregate is only executed once for same node.
+ if (visit != PreVisit)
+ {
+ return true;
+ }
+
+ if (mFoundSSBO)
+ {
+ return false;
+ }
+
+ // We still need to process the ssbo as the non-first argument of atomic memory functions.
+ if (IsAtomicFunction(node->getOp()) &&
+ IsInShaderStorageBlock((*node->getSequence())[0]->getAsTyped()))
+ {
+ return true;
+ }
+
+ if (!HasSSBOAsFunctionArgument(node->getSequence()))
+ {
+ return true;
+ }
+
+ mFoundSSBO = true;
+ TIntermSequence insertions;
+ TIntermSequence readBackToSSBOs;
+ TIntermSequence *originalArguments = node->getSequence();
+ for (size_t i = 0; i < node->getChildCount(); ++i)
+ {
+ TIntermTyped *ssboArgument = (*originalArguments)[i]->getAsTyped();
+ if (IsInShaderStorageBlock(ssboArgument))
+ {
+ TIntermSymbol *argumentCopy =
+ insertInitStatementAndReturnTempSymbol(ssboArgument, &insertions);
+ if (node->getFunction() != nullptr)
+ {
+ TQualifier qual = node->getFunction()->getParam(i)->getType().getQualifier();
+ if (qual == EvqInOut || qual == EvqOut)
+ {
+ TIntermBinary *readBackToSSBO = new TIntermBinary(
+ EOpAssign, ssboArgument->deepCopy(), argumentCopy->deepCopy());
+ readBackToSSBOs.push_back(readBackToSSBO);
+ }
+ }
+ node->replaceChildNode(ssboArgument, argumentCopy);
+ }
+ }
+
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ if (parentBlock)
+ {
+ // Aggregate node is as a single sentence.
+ insertions.push_back(node);
+ if (!readBackToSSBOs.empty())
+ {
+ insertions.insert(insertions.end(), readBackToSSBOs.begin(), readBackToSSBOs.end());
+ }
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentBlock, node, insertions));
+ }
+ else
+ {
+ // Aggregate node is inside an expression.
+ TIntermSymbol *tempSymbol = insertInitStatementAndReturnTempSymbol(node, &insertions);
+ if (!readBackToSSBOs.empty())
+ {
+ insertions.insert(insertions.end(), readBackToSSBOs.begin(), readBackToSSBOs.end());
+ }
+ insertStatementsInParentBlock(insertions);
+ queueReplacement(tempSymbol->deepCopy(), OriginalNode::IS_DROPPED);
+ }
+
+ return false;
+}
+
+bool RewriteExpressionsWithShaderStorageBlockTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mFoundSSBO)
+ {
+ return false;
+ }
+
+ if (!IsInShaderStorageBlock(node->getOperand()))
+ {
+ return true;
+ }
+
+ // .length() is processed in OutputHLSL.
+ if (node->getOp() == EOpArrayLength)
+ {
+ return true;
+ }
+
+ mFoundSSBO = true;
+
+ // case 4: ssbo as the operand of ++/--
+ // original:
+ // ++ssbo * expr;
+ // new:
+ // var temp1 = ssbo;
+ // var temp2 = ++temp1;
+ // ssbo = temp1;
+ // temp2 * expr;
+ if (IsIncrementOrDecrementOperator(node->getOp()))
+ {
+ TIntermSequence insertions;
+ TIntermSymbol *temp1 =
+ insertInitStatementAndReturnTempSymbol(node->getOperand(), &insertions);
+ TIntermUnary *newUnary = new TIntermUnary(node->getOp(), temp1->deepCopy(), nullptr);
+ TIntermSymbol *temp2 = insertInitStatementAndReturnTempSymbol(newUnary, &insertions);
+ TIntermBinary *readBackToSSBO =
+ new TIntermBinary(EOpAssign, node->getOperand()->deepCopy(), temp1->deepCopy());
+ insertions.push_back(readBackToSSBO);
+ insertStatementsInParentBlock(insertions);
+ queueReplacement(temp2->deepCopy(), OriginalNode::IS_DROPPED);
+ }
+ // case 5: ssbo as the operand of readonly unary operator
+ // original:
+ // ~ssbo * expr;
+ // new:
+ // var temp = ssbo;
+ // ~temp * expr;
+ else
+ {
+ TIntermSequence insertions;
+ TIntermSymbol *temp =
+ insertInitStatementAndReturnTempSymbol(node->getOperand(), &insertions);
+ insertStatementsInParentBlock(insertions);
+ node->replaceChildNode(node->getOperand(), temp->deepCopy());
+ }
+ return false;
+}
+
+void RewriteExpressionsWithShaderStorageBlockTraverser::nextIteration()
+{
+ mFoundSSBO = false;
+}
+
+} // anonymous namespace
+
+void RewriteExpressionsWithShaderStorageBlock(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ RewriteExpressionsWithShaderStorageBlockTraverser traverser(symbolTable);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundSSBO())
+ traverser.updateTree();
+ } while (traverser.foundSSBO());
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h
new file mode 100644
index 0000000000..957552e6fd
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h
@@ -0,0 +1,32 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteExpressionsWithShaderStorageBlock rewrites the expressions that contain shader storage
+// block calls into several simple ones that can be easily handled in the HLSL translator. After the
+// AST pass, all ssbo related blocks will be like below:
+// ssbo_access_chain = ssbo_access_chain;
+// ssbo_access_chain = expr_no_ssbo;
+// lvalue_no_ssbo = ssbo_access_chain;
+//
+// Below situations are needed to be rewritten (Details can be found in .cpp file).
+// SSBO as the operand of compound assignment operators.
+// SSBO as the operand of ++/--.
+// SSBO as the operand of repeated assignment.
+// SSBO as the operand of readonly unary/binary/ternary operators.
+// SSBO as the argument of aggregate type.
+// SSBO as the condition of if/switch/while/do-while/for
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_
+
+namespace sh
+{
+class TIntermNode;
+class TSymbolTable;
+
+void RewriteExpressionsWithShaderStorageBlock(TIntermNode *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp
new file mode 100644
index 0000000000..3cc670e688
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteRepeatedAssignToSwizzled.cpp: Rewrite expressions that assign an assignment to a swizzled
+// vector, like:
+// v.x = z = expression;
+// to:
+// z = expression;
+// v.x = z;
+//
+// Note that this doesn't handle some corner cases: expressions nested inside other expressions,
+// inside loop headers, or inside if conditions.
+
+#include "compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h"
+
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class RewriteAssignToSwizzledTraverser : public TIntermTraverser
+{
+ public:
+ static void rewrite(TIntermBlock *root);
+
+ private:
+ RewriteAssignToSwizzledTraverser();
+
+ bool visitBinary(Visit, TIntermBinary *node) override;
+
+ void nextIteration();
+
+ bool didRewrite() { return mDidRewrite; }
+
+ bool mDidRewrite;
+};
+
+// static
+void RewriteAssignToSwizzledTraverser::rewrite(TIntermBlock *root)
+{
+ RewriteAssignToSwizzledTraverser rewrite;
+ do
+ {
+ rewrite.nextIteration();
+ root->traverse(&rewrite);
+ rewrite.updateTree();
+ } while (rewrite.didRewrite());
+}
+
+RewriteAssignToSwizzledTraverser::RewriteAssignToSwizzledTraverser()
+ : TIntermTraverser(true, false, false), mDidRewrite(false)
+{}
+
+void RewriteAssignToSwizzledTraverser::nextIteration()
+{
+ mDidRewrite = false;
+}
+
+bool RewriteAssignToSwizzledTraverser::visitBinary(Visit, TIntermBinary *node)
+{
+ TIntermBinary *rightBinary = node->getRight()->getAsBinaryNode();
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ if (parentBlock && node->isAssignment() && node->getLeft()->getAsSwizzleNode() && rightBinary &&
+ rightBinary->isAssignment())
+ {
+ TIntermSequence replacements;
+ replacements.push_back(rightBinary);
+ TIntermTyped *rightAssignmentTargetCopy = rightBinary->getLeft()->deepCopy();
+ TIntermBinary *lastAssign =
+ new TIntermBinary(EOpAssign, node->getLeft(), rightAssignmentTargetCopy);
+ replacements.push_back(lastAssign);
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
+ mDidRewrite = true;
+ return false;
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+void RewriteRepeatedAssignToSwizzled(TIntermBlock *root)
+{
+ RewriteAssignToSwizzledTraverser::rewrite(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h
new file mode 100644
index 0000000000..2f2d3b9f80
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteRepeatedAssignToSwizzled.h: Rewrite expressions that assign an assignment to a swizzled
+// vector, like:
+// v.x = z = expression;
+// to:
+// z = expression;
+// v.x = z;
+//
+// Note that this doesn't handle some corner cases: expressions nested inside other expressions,
+// inside loop headers, or inside if conditions.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEREPEATEDASSIGNTOSWIZZLED_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITEREPEATEDASSIGNTOSWIZZLED_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+
+void RewriteRepeatedAssignToSwizzled(TIntermBlock *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEREPEATEDASSIGNTOSWIZZLED_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp
new file mode 100644
index 0000000000..8d5bdd0bae
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp
@@ -0,0 +1,699 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteStructSamplers: Extract structs from samplers.
+//
+
+#include "compiler/translator/tree_ops/RewriteStructSamplers.h"
+
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+namespace
+{
+// Helper method to get the sampler extracted struct type of a parameter.
+TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable &param)
+{
+ const TStructure *structure = param.getType().getStruct();
+ const TSymbol *structSymbol = symbolTable->findUserDefined(structure->name());
+ ASSERT(structSymbol && structSymbol->isStruct());
+ const TStructure *structVar = static_cast<const TStructure *>(structSymbol);
+ TType *structType = new TType(structVar, false);
+
+ if (param.getType().isArray())
+ {
+ structType->makeArrays(*param.getType().getArraySizes());
+ }
+
+ ASSERT(!structType->isStructureContainingSamplers());
+
+ return structType;
+}
+
+TIntermSymbol *ReplaceTypeOfSymbolNode(TIntermSymbol *symbolNode, TSymbolTable *symbolTable)
+{
+ const TVariable &oldVariable = symbolNode->variable();
+
+ TType *newType = GetStructSamplerParameterType(symbolTable, oldVariable);
+
+ TVariable *newVariable =
+ new TVariable(oldVariable.uniqueId(), oldVariable.name(), oldVariable.symbolType(),
+ oldVariable.extension(), newType);
+ return new TIntermSymbol(newVariable);
+}
+
+TIntermTyped *ReplaceTypeOfTypedStructNode(TIntermTyped *argument, TSymbolTable *symbolTable)
+{
+ TIntermSymbol *asSymbol = argument->getAsSymbolNode();
+ if (asSymbol)
+ {
+ ASSERT(asSymbol->getType().getStruct());
+ return ReplaceTypeOfSymbolNode(asSymbol, symbolTable);
+ }
+
+ TIntermTyped *replacement = argument->deepCopy();
+ TIntermBinary *binary = replacement->getAsBinaryNode();
+ ASSERT(binary);
+
+ while (binary)
+ {
+ ASSERT(binary->getOp() == EOpIndexDirectStruct || binary->getOp() == EOpIndexDirect);
+
+ asSymbol = binary->getLeft()->getAsSymbolNode();
+
+ if (asSymbol)
+ {
+ ASSERT(asSymbol->getType().getStruct());
+ TIntermSymbol *newSymbol = ReplaceTypeOfSymbolNode(asSymbol, symbolTable);
+ binary->replaceChildNode(binary->getLeft(), newSymbol);
+ return replacement;
+ }
+
+ binary = binary->getLeft()->getAsBinaryNode();
+ }
+
+ UNREACHABLE();
+ return nullptr;
+}
+
+// Maximum string size of a hex unsigned int.
+constexpr size_t kHexSize = ImmutableStringBuilder::GetHexCharCount<unsigned int>();
+
+class Traverser final : public TIntermTraverser
+{
+ public:
+ explicit Traverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable), mRemovedUniformsCount(0)
+ {
+ mSymbolTable->push();
+ }
+
+ ~Traverser() override { mSymbolTable->pop(); }
+
+ int removedUniformsCount() const { return mRemovedUniformsCount; }
+
+ // Each struct sampler declaration is stripped of its samplers. New uniforms are added for each
+ // stripped struct sampler.
+ bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
+ {
+ if (visit != PreVisit)
+ return true;
+
+ if (!mInGlobalScope)
+ {
+ return true;
+ }
+
+ const TIntermSequence &sequence = *(decl->getSequence());
+ TIntermTyped *declarator = sequence.front()->getAsTyped();
+ const TType &type = declarator->getType();
+
+ if (type.isStructureContainingSamplers())
+ {
+ TIntermSequence *newSequence = new TIntermSequence;
+
+ if (type.isStructSpecifier())
+ {
+ stripStructSpecifierSamplers(type.getStruct(), newSequence);
+ }
+ else
+ {
+ TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
+ ASSERT(asSymbol);
+ const TVariable &variable = asSymbol->variable();
+ ASSERT(variable.symbolType() != SymbolType::Empty);
+ extractStructSamplerUniforms(decl, variable, type.getStruct(), newSequence);
+ }
+
+ mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence);
+ }
+
+ return true;
+ }
+
+ // Each struct sampler reference is replaced with a reference to the new extracted sampler.
+ bool visitBinary(Visit visit, TIntermBinary *node) override
+ {
+ if (visit != PreVisit)
+ return true;
+
+ if (node->getOp() == EOpIndexDirectStruct && node->getType().isSampler())
+ {
+ ImmutableString newName = GetStructSamplerNameFromTypedNode(node);
+ const TVariable *samplerReplacement =
+ static_cast<const TVariable *>(mSymbolTable->findUserDefined(newName));
+ ASSERT(samplerReplacement);
+
+ TIntermSymbol *replacement = new TIntermSymbol(samplerReplacement);
+
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ return true;
+ }
+
+ return true;
+ }
+
+ // In we are passing references to structs containing samplers we must new additional
+ // arguments. For each extracted struct sampler a new argument is added. This chains to nested
+ // structs.
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override
+ {
+ const TFunction *function = node->getFunction();
+
+ if (!function->hasSamplerInStructParams())
+ {
+ return;
+ }
+
+ const TSymbol *foundFunction = mSymbolTable->findUserDefined(function->name());
+ if (foundFunction)
+ {
+ ASSERT(foundFunction->isFunction());
+ function = static_cast<const TFunction *>(foundFunction);
+ }
+ else
+ {
+ TFunction *newFunction = createStructSamplerFunction(function);
+ mSymbolTable->declareUserDefinedFunction(newFunction, true);
+ function = newFunction;
+ }
+
+ ASSERT(!function->hasSamplerInStructParams());
+ TIntermFunctionPrototype *newProto = new TIntermFunctionPrototype(function);
+ queueReplacement(newProto, OriginalNode::IS_DROPPED);
+ }
+
+ // We insert a new scope for each function definition so we can track the new parameters.
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
+ {
+ if (visit == PreVisit)
+ {
+ mSymbolTable->push();
+ }
+ else
+ {
+ ASSERT(visit == PostVisit);
+ mSymbolTable->pop();
+ }
+ return true;
+ }
+
+ // For function call nodes we pass references to the extracted struct samplers in that scope.
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit != PreVisit)
+ return true;
+
+ if (!node->isFunctionCall())
+ return true;
+
+ const TFunction *function = node->getFunction();
+ if (!function->hasSamplerInStructParams())
+ return true;
+
+ ASSERT(node->getOp() == EOpCallFunctionInAST);
+ TFunction *newFunction = mSymbolTable->findUserDefinedFunction(function->name());
+ TIntermSequence *newArguments = getStructSamplerArguments(function, node->getSequence());
+
+ TIntermAggregate *newCall =
+ TIntermAggregate::CreateFunctionCall(*newFunction, newArguments);
+ queueReplacement(newCall, OriginalNode::IS_DROPPED);
+ return true;
+ }
+
+ private:
+ // This returns the name of a struct sampler reference. References are always TIntermBinary.
+ static ImmutableString GetStructSamplerNameFromTypedNode(TIntermTyped *node)
+ {
+ std::string stringBuilder;
+
+ TIntermTyped *currentNode = node;
+ while (currentNode->getAsBinaryNode())
+ {
+ TIntermBinary *asBinary = currentNode->getAsBinaryNode();
+
+ switch (asBinary->getOp())
+ {
+ case EOpIndexDirect:
+ {
+ const int index = asBinary->getRight()->getAsConstantUnion()->getIConst(0);
+ const std::string strInt = Str(index);
+ stringBuilder.insert(0, strInt);
+ stringBuilder.insert(0, "_");
+ break;
+ }
+ case EOpIndexDirectStruct:
+ {
+ stringBuilder.insert(0, asBinary->getIndexStructFieldName().data());
+ stringBuilder.insert(0, "_");
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ currentNode = asBinary->getLeft();
+ }
+
+ const ImmutableString &variableName = currentNode->getAsSymbolNode()->variable().name();
+ stringBuilder.insert(0, variableName.data());
+
+ return stringBuilder;
+ }
+
+ // Removes all the struct samplers from a struct specifier.
+ void stripStructSpecifierSamplers(const TStructure *structure, TIntermSequence *newSequence)
+ {
+ TFieldList *newFieldList = new TFieldList;
+ ASSERT(structure->containsSamplers());
+
+ for (const TField *field : structure->fields())
+ {
+ const TType &fieldType = *field->type();
+ if (!fieldType.isSampler() && !isRemovedStructType(fieldType))
+ {
+ TType *newType = nullptr;
+
+ if (fieldType.isStructureContainingSamplers())
+ {
+ const TSymbol *structSymbol =
+ mSymbolTable->findUserDefined(fieldType.getStruct()->name());
+ ASSERT(structSymbol && structSymbol->isStruct());
+ const TStructure *fieldStruct = static_cast<const TStructure *>(structSymbol);
+ newType = new TType(fieldStruct, true);
+ if (fieldType.isArray())
+ {
+ newType->makeArrays(*fieldType.getArraySizes());
+ }
+ }
+ else
+ {
+ newType = new TType(fieldType);
+ }
+
+ TField *newField =
+ new TField(newType, field->name(), field->line(), field->symbolType());
+ newFieldList->push_back(newField);
+ }
+ }
+
+ // Prune empty structs.
+ if (newFieldList->empty())
+ {
+ mRemovedStructs.insert(structure->name());
+ return;
+ }
+
+ TStructure *newStruct =
+ new TStructure(mSymbolTable, structure->name(), newFieldList, structure->symbolType());
+ TType *newStructType = new TType(newStruct, true);
+ TVariable *newStructVar =
+ new TVariable(mSymbolTable, kEmptyImmutableString, newStructType, SymbolType::Empty);
+ TIntermSymbol *newStructRef = new TIntermSymbol(newStructVar);
+
+ TIntermDeclaration *structDecl = new TIntermDeclaration;
+ structDecl->appendDeclarator(newStructRef);
+
+ newSequence->push_back(structDecl);
+
+ mSymbolTable->declare(newStruct);
+ }
+
+ // Returns true if the type is a struct that was removed because we extracted all the members.
+ bool isRemovedStructType(const TType &type) const
+ {
+ const TStructure *structure = type.getStruct();
+ return (structure && (mRemovedStructs.count(structure->name()) > 0));
+ }
+
+ // Removes samplers from struct uniforms. For each sampler removed also adds a new globally
+ // defined sampler uniform.
+ void extractStructSamplerUniforms(TIntermDeclaration *oldDeclaration,
+ const TVariable &variable,
+ const TStructure *structure,
+ TIntermSequence *newSequence)
+ {
+ ASSERT(structure->containsSamplers());
+
+ size_t nonSamplerCount = 0;
+
+ for (const TField *field : structure->fields())
+ {
+ nonSamplerCount +=
+ extractFieldSamplers(variable.name(), field, variable.getType(), newSequence);
+ }
+
+ if (nonSamplerCount > 0)
+ {
+ // Keep the old declaration around if it has other members.
+ newSequence->push_back(oldDeclaration);
+ }
+ else
+ {
+ mRemovedUniformsCount++;
+ }
+ }
+
+ // Extracts samplers from a field of a struct. Works with nested structs and arrays.
+ size_t extractFieldSamplers(const ImmutableString &prefix,
+ const TField *field,
+ const TType &containingType,
+ TIntermSequence *newSequence)
+ {
+ if (containingType.isArray())
+ {
+ size_t nonSamplerCount = 0;
+
+ // Name the samplers internally as varName_<index>_fieldName
+ const TVector<unsigned int> &arraySizes = *containingType.getArraySizes();
+ for (unsigned int arrayElement = 0; arrayElement < arraySizes[0]; ++arrayElement)
+ {
+ ImmutableStringBuilder stringBuilder(prefix.length() + kHexSize + 1);
+ stringBuilder << prefix << "_";
+ stringBuilder.appendHex(arrayElement);
+ nonSamplerCount = extractFieldSamplersImpl(stringBuilder, field, newSequence);
+ }
+
+ return nonSamplerCount;
+ }
+
+ return extractFieldSamplersImpl(prefix, field, newSequence);
+ }
+
+ // Extracts samplers from a field of a struct. Works with nested structs and arrays.
+ size_t extractFieldSamplersImpl(const ImmutableString &prefix,
+ const TField *field,
+ TIntermSequence *newSequence)
+ {
+ size_t nonSamplerCount = 0;
+
+ const TType &fieldType = *field->type();
+ if (fieldType.isSampler() || fieldType.isStructureContainingSamplers())
+ {
+ ImmutableStringBuilder stringBuilder(prefix.length() + field->name().length() + 1);
+ stringBuilder << prefix << "_" << field->name();
+ ImmutableString newPrefix(stringBuilder);
+
+ if (fieldType.isSampler())
+ {
+ extractSampler(newPrefix, fieldType, newSequence);
+ }
+ else
+ {
+ const TStructure *structure = fieldType.getStruct();
+ for (const TField *nestedField : structure->fields())
+ {
+ nonSamplerCount +=
+ extractFieldSamplers(newPrefix, nestedField, fieldType, newSequence);
+ }
+ }
+ }
+ else
+ {
+ nonSamplerCount++;
+ }
+
+ return nonSamplerCount;
+ }
+
+ // Extracts a sampler from a struct. Declares the new extracted sampler.
+ void extractSampler(const ImmutableString &newName,
+ const TType &fieldType,
+ TIntermSequence *newSequence) const
+ {
+ TType *newType = new TType(fieldType);
+ newType->setQualifier(EvqUniform);
+ TVariable *newVariable =
+ new TVariable(mSymbolTable, newName, newType, SymbolType::AngleInternal);
+ TIntermSymbol *newRef = new TIntermSymbol(newVariable);
+
+ TIntermDeclaration *samplerDecl = new TIntermDeclaration;
+ samplerDecl->appendDeclarator(newRef);
+
+ newSequence->push_back(samplerDecl);
+
+ mSymbolTable->declareInternal(newVariable);
+ }
+
+ // Returns the chained name of a sampler uniform field.
+ static ImmutableString GetFieldName(const ImmutableString &paramName,
+ const TField *field,
+ unsigned arrayIndex)
+ {
+ ImmutableStringBuilder nameBuilder(paramName.length() + kHexSize + 2 +
+ field->name().length());
+ nameBuilder << paramName << "_";
+
+ if (arrayIndex < std::numeric_limits<unsigned>::max())
+ {
+ nameBuilder.appendHex(arrayIndex);
+ nameBuilder << "_";
+ }
+ nameBuilder << field->name();
+
+ return nameBuilder;
+ }
+
+ // A pattern that visits every parameter of a function call. Uses different handlers for struct
+ // parameters, struct sampler parameters, and non-struct parameters.
+ class StructSamplerFunctionVisitor : angle::NonCopyable
+ {
+ public:
+ StructSamplerFunctionVisitor() = default;
+ virtual ~StructSamplerFunctionVisitor() = default;
+
+ virtual void traverse(const TFunction *function)
+ {
+ size_t paramCount = function->getParamCount();
+
+ for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex)
+ {
+ const TVariable *param = function->getParam(paramIndex);
+ const TType &paramType = param->getType();
+
+ if (paramType.isStructureContainingSamplers())
+ {
+ const ImmutableString &baseName = getNameFromIndex(function, paramIndex);
+ if (traverseStructContainingSamplers(baseName, paramType))
+ {
+ visitStructParam(function, paramIndex);
+ }
+ }
+ else
+ {
+ visitNonStructParam(function, paramIndex);
+ }
+ }
+ }
+
+ virtual ImmutableString getNameFromIndex(const TFunction *function, size_t paramIndex) = 0;
+ virtual void visitSamplerInStructParam(const ImmutableString &name,
+ const TField *field) = 0;
+ virtual void visitStructParam(const TFunction *function, size_t paramIndex) = 0;
+ virtual void visitNonStructParam(const TFunction *function, size_t paramIndex) = 0;
+
+ private:
+ bool traverseStructContainingSamplers(const ImmutableString &baseName,
+ const TType &structType)
+ {
+ bool hasNonSamplerFields = false;
+ const TStructure *structure = structType.getStruct();
+ for (const TField *field : structure->fields())
+ {
+ if (field->type()->isStructureContainingSamplers() || field->type()->isSampler())
+ {
+ if (traverseSamplerInStruct(baseName, structType, field))
+ {
+ hasNonSamplerFields = true;
+ }
+ }
+ else
+ {
+ hasNonSamplerFields = true;
+ }
+ }
+ return hasNonSamplerFields;
+ }
+
+ bool traverseSamplerInStruct(const ImmutableString &baseName,
+ const TType &baseType,
+ const TField *field)
+ {
+ bool hasNonSamplerParams = false;
+
+ if (baseType.isArray())
+ {
+ const TVector<unsigned int> &arraySizes = *baseType.getArraySizes();
+ ASSERT(arraySizes.size() == 1);
+
+ for (unsigned int arrayIndex = 0; arrayIndex < arraySizes[0]; ++arrayIndex)
+ {
+ ImmutableString name = GetFieldName(baseName, field, arrayIndex);
+
+ if (field->type()->isStructureContainingSamplers())
+ {
+ if (traverseStructContainingSamplers(name, *field->type()))
+ {
+ hasNonSamplerParams = true;
+ }
+ }
+ else
+ {
+ ASSERT(field->type()->isSampler());
+ visitSamplerInStructParam(name, field);
+ }
+ }
+ }
+ else if (field->type()->isStructureContainingSamplers())
+ {
+ ImmutableString name =
+ GetFieldName(baseName, field, std::numeric_limits<unsigned>::max());
+ hasNonSamplerParams = traverseStructContainingSamplers(name, *field->type());
+ }
+ else
+ {
+ ASSERT(field->type()->isSampler());
+ ImmutableString name =
+ GetFieldName(baseName, field, std::numeric_limits<unsigned>::max());
+ visitSamplerInStructParam(name, field);
+ }
+
+ return hasNonSamplerParams;
+ }
+ };
+
+ // A visitor that replaces functions with struct sampler references. The struct sampler
+ // references are expanded to include new fields for the structs.
+ class CreateStructSamplerFunctionVisitor final : public StructSamplerFunctionVisitor
+ {
+ public:
+ CreateStructSamplerFunctionVisitor(TSymbolTable *symbolTable)
+ : mSymbolTable(symbolTable), mNewFunction(nullptr)
+ {}
+
+ ImmutableString getNameFromIndex(const TFunction *function, size_t paramIndex) override
+ {
+ const TVariable *param = function->getParam(paramIndex);
+ return param->name();
+ }
+
+ void traverse(const TFunction *function) override
+ {
+ mNewFunction =
+ new TFunction(mSymbolTable, function->name(), function->symbolType(),
+ &function->getReturnType(), function->isKnownToNotHaveSideEffects());
+
+ StructSamplerFunctionVisitor::traverse(function);
+ }
+
+ void visitSamplerInStructParam(const ImmutableString &name, const TField *field) override
+ {
+ TVariable *fieldSampler =
+ new TVariable(mSymbolTable, name, field->type(), SymbolType::AngleInternal);
+ mNewFunction->addParameter(fieldSampler);
+ mSymbolTable->declareInternal(fieldSampler);
+ }
+
+ void visitStructParam(const TFunction *function, size_t paramIndex) override
+ {
+ const TVariable *param = function->getParam(paramIndex);
+ TType *structType = GetStructSamplerParameterType(mSymbolTable, *param);
+ TVariable *newParam =
+ new TVariable(mSymbolTable, param->name(), structType, param->symbolType());
+ mNewFunction->addParameter(newParam);
+ }
+
+ void visitNonStructParam(const TFunction *function, size_t paramIndex) override
+ {
+ const TVariable *param = function->getParam(paramIndex);
+ mNewFunction->addParameter(param);
+ }
+
+ TFunction *getNewFunction() const { return mNewFunction; }
+
+ private:
+ TSymbolTable *mSymbolTable;
+ TFunction *mNewFunction;
+ };
+
+ TFunction *createStructSamplerFunction(const TFunction *function) const
+ {
+ CreateStructSamplerFunctionVisitor visitor(mSymbolTable);
+ visitor.traverse(function);
+ return visitor.getNewFunction();
+ }
+
+ // A visitor that replaces function calls with expanded struct sampler parameters.
+ class GetSamplerArgumentsVisitor final : public StructSamplerFunctionVisitor
+ {
+ public:
+ GetSamplerArgumentsVisitor(TSymbolTable *symbolTable, const TIntermSequence *arguments)
+ : mSymbolTable(symbolTable), mArguments(arguments), mNewArguments(new TIntermSequence)
+ {}
+
+ ImmutableString getNameFromIndex(const TFunction *function, size_t paramIndex) override
+ {
+ TIntermTyped *argument = (*mArguments)[paramIndex]->getAsTyped();
+ return GetStructSamplerNameFromTypedNode(argument);
+ }
+
+ void visitSamplerInStructParam(const ImmutableString &name, const TField *field) override
+ {
+ TVariable *argSampler =
+ new TVariable(mSymbolTable, name, field->type(), SymbolType::AngleInternal);
+ TIntermSymbol *argSymbol = new TIntermSymbol(argSampler);
+ mNewArguments->push_back(argSymbol);
+ }
+
+ void visitStructParam(const TFunction *function, size_t paramIndex) override
+ {
+ // The tree structure of the parameter is modified to point to the new type. This leaves
+ // the tree in a consistent state.
+ TIntermTyped *argument = (*mArguments)[paramIndex]->getAsTyped();
+ TIntermTyped *replacement = ReplaceTypeOfTypedStructNode(argument, mSymbolTable);
+ mNewArguments->push_back(replacement);
+ }
+
+ void visitNonStructParam(const TFunction *function, size_t paramIndex) override
+ {
+ TIntermTyped *argument = (*mArguments)[paramIndex]->getAsTyped();
+ mNewArguments->push_back(argument);
+ }
+
+ TIntermSequence *getNewArguments() const { return mNewArguments; }
+
+ private:
+ TSymbolTable *mSymbolTable;
+ const TIntermSequence *mArguments;
+ TIntermSequence *mNewArguments;
+ };
+
+ TIntermSequence *getStructSamplerArguments(const TFunction *function,
+ const TIntermSequence *arguments) const
+ {
+ GetSamplerArgumentsVisitor visitor(mSymbolTable, arguments);
+ visitor.traverse(function);
+ return visitor.getNewArguments();
+ }
+
+ int mRemovedUniformsCount;
+ std::set<ImmutableString> mRemovedStructs;
+};
+} // anonymous namespace
+
+int RewriteStructSamplers(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ Traverser rewriteStructSamplers(symbolTable);
+ root->traverse(&rewriteStructSamplers);
+ rewriteStructSamplers.updateTree();
+
+ return rewriteStructSamplers.removedUniformsCount();
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h
new file mode 100644
index 0000000000..2b7aa6e1c4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h
@@ -0,0 +1,31 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteStructSamplers: Extract structs from samplers.
+//
+// This traverser is designed to strip out samplers from structs. It moves them into
+// separate uniform sampler declarations. This allows the struct to be stored in the
+// default uniform block. It also requires that we rewrite any functions that take the
+// struct as an argument. The struct is split into two arguments.
+//
+// For example:
+// struct S { sampler2D samp; int i; };
+// uniform S uni;
+// Is rewritten as:
+// struct S { int i; };
+// uniform S uni;
+// uniform sampler2D uni_i;
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITESTRUCTSAMPLERS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITESTRUCTSAMPLERS_H_
+
+namespace sh
+{
+class TIntermBlock;
+class TSymbolTable;
+int RewriteStructSamplers(TIntermBlock *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITESTRUCTSAMPLERS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp
new file mode 100644
index 0000000000..3587fd6538
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp
@@ -0,0 +1,154 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of texelFetchOffset translation issue workaround.
+// See header for more info.
+
+#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
+
+#include "common/angleutils.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion);
+
+ private:
+ Traverser(const TSymbolTable &symbolTable, int shaderVersion);
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ void nextIteration();
+
+ const TSymbolTable *symbolTable;
+ const int shaderVersion;
+ bool mFound = false;
+};
+
+Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion)
+ : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion)
+{}
+
+// static
+void Traverser::Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion)
+{
+ Traverser traverser(symbolTable, shaderVersion);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.mFound)
+ {
+ traverser.updateTree();
+ }
+ } while (traverser.mFound);
+}
+
+void Traverser::nextIteration()
+{
+ mFound = false;
+}
+
+bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mFound)
+ {
+ return false;
+ }
+
+ // Decide if the node represents the call of texelFetchOffset.
+ if (node->getOp() != EOpCallBuiltInFunction)
+ {
+ return true;
+ }
+
+ ASSERT(node->getFunction()->symbolType() == SymbolType::BuiltIn);
+ if (node->getFunction()->name() != "texelFetchOffset")
+ {
+ return true;
+ }
+
+ // Potential problem case detected, apply workaround.
+ const TIntermSequence *sequence = node->getSequence();
+ ASSERT(sequence->size() == 4u);
+
+ // Decide if the sampler is a 2DArray sampler. In that case position is ivec3 and offset is
+ // ivec2.
+ bool is2DArray = sequence->at(1)->getAsTyped()->getNominalSize() == 3 &&
+ sequence->at(3)->getAsTyped()->getNominalSize() == 2;
+
+ // Create new node that represents the call of function texelFetch.
+ // Its argument list will be: texelFetch(sampler, Position+offset, lod).
+
+ TIntermSequence *texelFetchArguments = new TIntermSequence();
+
+ // sampler
+ texelFetchArguments->push_back(sequence->at(0));
+
+ // Position
+ TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
+ ASSERT(texCoordNode);
+
+ // offset
+ TIntermTyped *offsetNode = nullptr;
+ ASSERT(sequence->at(3)->getAsTyped());
+ if (is2DArray)
+ {
+ // For 2DArray samplers, Position is ivec3 and offset is ivec2;
+ // So offset must be converted into an ivec3 before being added to Position.
+ TIntermSequence *constructOffsetIvecArguments = new TIntermSequence();
+ constructOffsetIvecArguments->push_back(sequence->at(3)->getAsTyped());
+
+ TIntermTyped *zeroNode = CreateZeroNode(TType(EbtInt));
+ constructOffsetIvecArguments->push_back(zeroNode);
+
+ offsetNode = TIntermAggregate::CreateConstructor(texCoordNode->getType(),
+ constructOffsetIvecArguments);
+ offsetNode->setLine(texCoordNode->getLine());
+ }
+ else
+ {
+ offsetNode = sequence->at(3)->getAsTyped();
+ }
+
+ // Position+offset
+ TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
+ add->setLine(texCoordNode->getLine());
+ texelFetchArguments->push_back(add);
+
+ // lod
+ texelFetchArguments->push_back(sequence->at(2));
+
+ ASSERT(texelFetchArguments->size() == 3u);
+
+ TIntermTyped *texelFetchNode = CreateBuiltInFunctionCallNode("texelFetch", texelFetchArguments,
+ *symbolTable, shaderVersion);
+ texelFetchNode->setLine(node->getLine());
+
+ // Replace the old node by this new node.
+ queueReplacement(texelFetchNode, OriginalNode::IS_DROPPED);
+ mFound = true;
+ return false;
+}
+
+} // anonymous namespace
+
+void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion)
+{
+ // texelFetchOffset is only valid in GLSL 3.0 and later.
+ if (shaderVersion < 300)
+ return;
+
+ Traverser::Apply(root, symbolTable, shaderVersion);
+}
+
+} // namespace sh \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h
new file mode 100644
index 0000000000..45e224dd62
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This mutating tree traversal works around an issue on the translation
+// from texelFetchOffset into HLSL function Load on INTEL drivers. It
+// works by translating texelFetchOffset into texelFetch:
+//
+// - From: texelFetchOffset(sampler, Position, lod, offset)
+// - To: texelFetch(sampler, Position+offset, lod)
+//
+// See http://anglebug.com/1469
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_TEXELFETCHOFFSET_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_TEXELFETCHOFFSET_H_
+
+class TIntermNode;
+class TSymbolTable;
+
+namespace sh
+{
+
+void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_TEXELFETCHOFFSET_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp
new file mode 100644
index 0000000000..e95dde2a76
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h"
+
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root);
+
+ private:
+ Traverser();
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ void nextIteration();
+
+ bool mFound = false;
+};
+
+// static
+void Traverser::Apply(TIntermNode *root)
+{
+ Traverser traverser;
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.mFound)
+ {
+ traverser.updateTree();
+ }
+ } while (traverser.mFound);
+}
+
+Traverser::Traverser() : TIntermTraverser(true, false, false) {}
+
+void Traverser::nextIteration()
+{
+ mFound = false;
+}
+
+bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mFound)
+ {
+ return false;
+ }
+
+ // Detect if the current operator is unary minus operator.
+ if (node->getOp() != EOpNegative)
+ {
+ return true;
+ }
+
+ // Detect if the current operand is a float variable.
+ TIntermTyped *fValue = node->getOperand();
+ if (!fValue->getType().isScalarFloat())
+ {
+ return true;
+ }
+
+ // 0.0 - float
+ TIntermTyped *zero = CreateZeroNode(fValue->getType());
+ zero->setLine(fValue->getLine());
+ TIntermBinary *sub = new TIntermBinary(EOpSub, zero, fValue);
+ sub->setLine(fValue->getLine());
+
+ queueReplacement(sub, OriginalNode::IS_DROPPED);
+
+ mFound = true;
+ return false;
+}
+
+} // anonymous namespace
+
+void RewriteUnaryMinusOperatorFloat(TIntermNode *root)
+{
+ Traverser::Apply(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h
new file mode 100644
index 0000000000..2df592a775
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Rewrite "-float" to "0.0 - float" to work around unary minus operator on float issue on Intel Mac
+// OSX 10.11.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORFLOAT_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORFLOAT_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void RewriteUnaryMinusOperatorFloat(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORFLOAT_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp
new file mode 100644
index 0000000000..5bfdb76e03
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp
@@ -0,0 +1,110 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of evaluating unary integer variable bug workaround.
+// See header for more info.
+
+#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h"
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ static void Apply(TIntermNode *root);
+
+ private:
+ Traverser();
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ void nextIteration();
+
+ bool mFound = false;
+};
+
+// static
+void Traverser::Apply(TIntermNode *root)
+{
+ Traverser traverser;
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.mFound)
+ {
+ traverser.updateTree();
+ }
+ } while (traverser.mFound);
+}
+
+Traverser::Traverser() : TIntermTraverser(true, false, false) {}
+
+void Traverser::nextIteration()
+{
+ mFound = false;
+}
+
+bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mFound)
+ {
+ return false;
+ }
+
+ // Decide if the current unary operator is unary minus.
+ if (node->getOp() != EOpNegative)
+ {
+ return true;
+ }
+
+ // Decide if the current operand is an integer variable.
+ TIntermTyped *opr = node->getOperand();
+ if (!opr->getType().isScalarInt())
+ {
+ return true;
+ }
+
+ // Potential problem case detected, apply workaround: -(int) -> ~(int) + 1.
+ // ~(int)
+ TIntermUnary *bitwiseNot = new TIntermUnary(EOpBitwiseNot, opr, nullptr);
+ bitwiseNot->setLine(opr->getLine());
+
+ // Constant 1 (or 1u)
+ TConstantUnion *one = new TConstantUnion();
+ if (opr->getType().getBasicType() == EbtInt)
+ {
+ one->setIConst(1);
+ }
+ else
+ {
+ one->setUConst(1u);
+ }
+ TIntermConstantUnion *oneNode =
+ new TIntermConstantUnion(one, TType(opr->getBasicType(), opr->getPrecision(), EvqConst));
+ oneNode->setLine(opr->getLine());
+
+ // ~(int) + 1
+ TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode);
+ add->setLine(opr->getLine());
+
+ queueReplacement(add, OriginalNode::IS_DROPPED);
+
+ mFound = true;
+ return false;
+}
+
+} // anonymous namespace
+
+void RewriteUnaryMinusOperatorInt(TIntermNode *root)
+{
+ Traverser::Apply(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h
new file mode 100644
index 0000000000..66192179c4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This mutating tree traversal works around a bug on evaluating unary
+// integer variable on Intel D3D driver. It works by rewriting -(int) to
+// ~(int) + 1 when evaluating unary integer variables.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORINT_H_
+#define COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORINT_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void RewriteUnaryMinusOperatorInt(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORINT_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp
new file mode 100644
index 0000000000..53d34ec5c1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp
@@ -0,0 +1,226 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Scalarize vector and matrix constructor args, so that vectors built from components don't have
+// matrix arguments, and matrices built from components don't have vector arguments. This avoids
+// driver bugs around vector and matrix constructors.
+//
+
+#include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h"
+#include "common/debug.h"
+
+#include <algorithm>
+
+#include "angle_gl.h"
+#include "common/angleutils.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
+{
+ return new TIntermBinary(EOpIndexDirect, symbolNode, CreateIndexNode(index));
+}
+
+TIntermBinary *ConstructMatrixIndexBinaryNode(TIntermSymbol *symbolNode, int colIndex, int rowIndex)
+{
+ TIntermBinary *colVectorNode = ConstructVectorIndexBinaryNode(symbolNode, colIndex);
+
+ return new TIntermBinary(EOpIndexDirect, colVectorNode, CreateIndexNode(rowIndex));
+}
+
+class ScalarizeArgsTraverser : public TIntermTraverser
+{
+ public:
+ ScalarizeArgsTraverser(sh::GLenum shaderType,
+ bool fragmentPrecisionHigh,
+ TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mShaderType(shaderType),
+ mFragmentPrecisionHigh(fragmentPrecisionHigh),
+ mNodesToScalarize(IntermNodePatternMatcher::kScalarizedVecOrMatConstructor)
+ {}
+
+ protected:
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBlock(Visit visit, TIntermBlock *node) override;
+
+ private:
+ void scalarizeArgs(TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix);
+
+ // If we have the following code:
+ // mat4 m(0);
+ // vec4 v(1, m);
+ // We will rewrite to:
+ // mat4 m(0);
+ // mat4 s0 = m;
+ // vec4 v(1, s0[0][0], s0[0][1], s0[0][2]);
+ // This function is to create nodes for "mat4 s0 = m;" and insert it to the code sequence. This
+ // way the possible side effects of the constructor argument will only be evaluated once.
+ TVariable *createTempVariable(TIntermTyped *original);
+
+ std::vector<TIntermSequence> mBlockStack;
+
+ sh::GLenum mShaderType;
+ bool mFragmentPrecisionHigh;
+
+ IntermNodePatternMatcher mNodesToScalarize;
+};
+
+bool ScalarizeArgsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ ASSERT(visit == PreVisit);
+ if (mNodesToScalarize.match(node, getParentNode()))
+ {
+ if (node->getType().isVector())
+ {
+ scalarizeArgs(node, false, true);
+ }
+ else
+ {
+ ASSERT(node->getType().isMatrix());
+ scalarizeArgs(node, true, false);
+ }
+ }
+ return true;
+}
+
+bool ScalarizeArgsTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+ mBlockStack.push_back(TIntermSequence());
+ {
+ for (TIntermNode *child : *node->getSequence())
+ {
+ ASSERT(child != nullptr);
+ child->traverse(this);
+ mBlockStack.back().push_back(child);
+ }
+ }
+ if (mBlockStack.back().size() > node->getSequence()->size())
+ {
+ node->getSequence()->clear();
+ *(node->getSequence()) = mBlockStack.back();
+ }
+ mBlockStack.pop_back();
+ return false;
+}
+
+void ScalarizeArgsTraverser::scalarizeArgs(TIntermAggregate *aggregate,
+ bool scalarizeVector,
+ bool scalarizeMatrix)
+{
+ ASSERT(aggregate);
+ ASSERT(!aggregate->isArray());
+ int size = static_cast<int>(aggregate->getType().getObjectSize());
+ TIntermSequence *sequence = aggregate->getSequence();
+ TIntermSequence originalArgs(*sequence);
+ sequence->clear();
+ for (TIntermNode *originalArgNode : originalArgs)
+ {
+ ASSERT(size > 0);
+ TIntermTyped *originalArg = originalArgNode->getAsTyped();
+ ASSERT(originalArg);
+ TVariable *argVariable = createTempVariable(originalArg);
+ if (originalArg->isScalar())
+ {
+ sequence->push_back(CreateTempSymbolNode(argVariable));
+ size--;
+ }
+ else if (originalArg->isVector())
+ {
+ if (scalarizeVector)
+ {
+ int repeat = std::min(size, originalArg->getNominalSize());
+ size -= repeat;
+ for (int index = 0; index < repeat; ++index)
+ {
+ TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
+ TIntermBinary *newNode = ConstructVectorIndexBinaryNode(symbolNode, index);
+ sequence->push_back(newNode);
+ }
+ }
+ else
+ {
+ TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
+ sequence->push_back(symbolNode);
+ size -= originalArg->getNominalSize();
+ }
+ }
+ else
+ {
+ ASSERT(originalArg->isMatrix());
+ if (scalarizeMatrix)
+ {
+ int colIndex = 0, rowIndex = 0;
+ int repeat = std::min(size, originalArg->getCols() * originalArg->getRows());
+ size -= repeat;
+ while (repeat > 0)
+ {
+ TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
+ TIntermBinary *newNode =
+ ConstructMatrixIndexBinaryNode(symbolNode, colIndex, rowIndex);
+ sequence->push_back(newNode);
+ rowIndex++;
+ if (rowIndex >= originalArg->getRows())
+ {
+ rowIndex = 0;
+ colIndex++;
+ }
+ repeat--;
+ }
+ }
+ else
+ {
+ TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
+ sequence->push_back(symbolNode);
+ size -= originalArg->getCols() * originalArg->getRows();
+ }
+ }
+ }
+}
+
+TVariable *ScalarizeArgsTraverser::createTempVariable(TIntermTyped *original)
+{
+ ASSERT(original);
+
+ TType *type = new TType(original->getType());
+ type->setQualifier(EvqTemporary);
+ if (mShaderType == GL_FRAGMENT_SHADER && type->getBasicType() == EbtFloat &&
+ type->getPrecision() == EbpUndefined)
+ {
+ // We use the highest available precision for the temporary variable
+ // to avoid computing the actual precision using the rules defined
+ // in GLSL ES 1.0 Section 4.5.2.
+ type->setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium);
+ }
+
+ TVariable *variable = CreateTempVariable(mSymbolTable, type);
+
+ ASSERT(mBlockStack.size() > 0);
+ TIntermSequence &sequence = mBlockStack.back();
+ TIntermDeclaration *declaration = CreateTempInitDeclarationNode(variable, original);
+ sequence.push_back(declaration);
+
+ return variable;
+}
+
+} // namespace
+
+void ScalarizeVecAndMatConstructorArgs(TIntermBlock *root,
+ sh::GLenum shaderType,
+ bool fragmentPrecisionHigh,
+ TSymbolTable *symbolTable)
+{
+ ScalarizeArgsTraverser scalarizer(shaderType, fragmentPrecisionHigh, symbolTable);
+ root->traverse(&scalarizer);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h
new file mode 100644
index 0000000000..e66908de1d
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Scalarize vector and matrix constructor args, so that vectors built from components don't have
+// matrix arguments, and matrices built from components don't have vector arguments. This avoids
+// driver bugs around vector and matrix constructors.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+namespace sh
+{
+class TIntermBlock;
+class TSymbolTable;
+
+void ScalarizeVecAndMatConstructorArgs(TIntermBlock *root,
+ sh::GLenum shaderType,
+ bool fragmentPrecisionHigh,
+ TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp
new file mode 100644
index 0000000000..5b4672bf24
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp
@@ -0,0 +1,84 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SeparateArrayConstructorStatements splits statements that are array constructors and drops all of
+// their constant arguments. For example, a statement like:
+// int[2](0, i++);
+// Will be changed to:
+// i++;
+
+#include "compiler/translator/tree_ops/SeparateArrayConstructorStatements.h"
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void SplitConstructorArgs(const TIntermSequence &originalArgs, TIntermSequence *argsOut)
+{
+ for (TIntermNode *arg : originalArgs)
+ {
+ TIntermTyped *argTyped = arg->getAsTyped();
+ if (argTyped->hasSideEffects())
+ {
+ TIntermAggregate *argAggregate = argTyped->getAsAggregate();
+ if (argTyped->isArray() && argAggregate && argAggregate->isConstructor())
+ {
+ SplitConstructorArgs(*argAggregate->getSequence(), argsOut);
+ }
+ else
+ {
+ argsOut->push_back(argTyped);
+ }
+ }
+ }
+}
+
+class SeparateArrayConstructorStatementsTraverser : public TIntermTraverser
+{
+ public:
+ SeparateArrayConstructorStatementsTraverser();
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+};
+
+SeparateArrayConstructorStatementsTraverser::SeparateArrayConstructorStatementsTraverser()
+ : TIntermTraverser(true, false, false)
+{}
+
+bool SeparateArrayConstructorStatementsTraverser::visitAggregate(Visit visit,
+ TIntermAggregate *node)
+{
+ TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
+ if (!parentAsBlock)
+ {
+ return false;
+ }
+ if (!node->isArray() || !node->isConstructor())
+ {
+ return false;
+ }
+
+ TIntermSequence constructorArgs;
+ SplitConstructorArgs(*node->getSequence(), &constructorArgs);
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentAsBlock, node, constructorArgs));
+
+ return false;
+}
+
+} // namespace
+
+void SeparateArrayConstructorStatements(TIntermBlock *root)
+{
+ SeparateArrayConstructorStatementsTraverser traverser;
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h
new file mode 100644
index 0000000000..740ba95aca
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SeparateArrayConstructorStatements splits statements that are array constructors and drops all of
+// their constant arguments. For example, a statement like:
+// int[2](0, i++);
+// Will be changed to:
+// i++;
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYCONSTRUCTORSTATEMENTS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYCONSTRUCTORSTATEMENTS_H_
+
+namespace sh
+{
+class TIntermBlock;
+
+void SeparateArrayConstructorStatements(TIntermBlock *root);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYCONSTRUCTORSTATEMENTS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp
new file mode 100644
index 0000000000..435ba9d6c4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp
@@ -0,0 +1,90 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The SeparateArrayInitialization function splits each array initialization into a declaration and
+// an assignment.
+// Example:
+// type[n] a = initializer;
+// will effectively become
+// type[n] a;
+// a = initializer;
+//
+// Note that if the array is declared as const, the initialization may still be split, making the
+// AST technically invalid. Because of that this transformation should only be used when subsequent
+// stages don't care about const qualifiers. However, the initialization will not be split if the
+// initializer can be written as a HLSL literal.
+
+#include "compiler/translator/tree_ops/SeparateArrayInitialization.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/OutputHLSL.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SeparateArrayInitTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+
+ private:
+ SeparateArrayInitTraverser();
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+};
+
+void SeparateArrayInitTraverser::apply(TIntermNode *root)
+{
+ SeparateArrayInitTraverser separateInit;
+ root->traverse(&separateInit);
+ separateInit.updateTree();
+}
+
+SeparateArrayInitTraverser::SeparateArrayInitTraverser() : TIntermTraverser(true, false, false) {}
+
+bool SeparateArrayInitTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ TIntermSequence *sequence = node->getSequence();
+ TIntermBinary *initNode = sequence->back()->getAsBinaryNode();
+ if (initNode != nullptr && initNode->getOp() == EOpInitialize)
+ {
+ TIntermTyped *initializer = initNode->getRight();
+ if (initializer->isArray() && !initializer->hasConstantValue())
+ {
+ // We rely on that array declarations have been isolated to single declarations.
+ ASSERT(sequence->size() == 1);
+ TIntermTyped *symbol = initNode->getLeft();
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ ASSERT(parentBlock != nullptr);
+
+ TIntermSequence replacements;
+
+ TIntermDeclaration *replacementDeclaration = new TIntermDeclaration();
+ replacementDeclaration->appendDeclarator(symbol);
+ replacementDeclaration->setLine(symbol->getLine());
+ replacements.push_back(replacementDeclaration);
+
+ TIntermBinary *replacementAssignment =
+ new TIntermBinary(EOpAssign, symbol, initializer);
+ replacementAssignment->setLine(symbol->getLine());
+ replacements.push_back(replacementAssignment);
+
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+void SeparateArrayInitialization(TIntermNode *root)
+{
+ SeparateArrayInitTraverser::apply(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h
new file mode 100644
index 0000000000..a197ff5a86
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The SeparateArrayInitialization function splits each array initialization into a declaration and
+// an assignment.
+// Example:
+// type[n] a = initializer;
+// will effectively become
+// type[n] a;
+// a = initializer;
+//
+// Note that if the array is declared as const, the initialization may still be split, making the
+// AST technically invalid. Because of that this transformation should only be used when subsequent
+// stages don't care about const qualifiers. However, the initialization will not be split if the
+// initializer can be written as a HLSL literal.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYINITIALIZATION_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYINITIALIZATION_H_
+
+namespace sh
+{
+class TIntermNode;
+
+void SeparateArrayInitialization(TIntermNode *root);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYINITIALIZATION_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp
new file mode 100644
index 0000000000..82011acd8a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The SeparateDeclarations function processes declarations, so that in the end each declaration
+// contains only one declarator.
+// This is useful as an intermediate step when initialization needs to be separated from
+// declaration, or when things need to be unfolded out of the initializer.
+// Example:
+// int a[1] = int[1](1), b[1] = int[1](2);
+// gets transformed when run through this class into the AST equivalent of:
+// int a[1] = int[1](1);
+// int b[1] = int[1](2);
+
+#include "compiler/translator/tree_ops/SeparateDeclarations.h"
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SeparateDeclarationsTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+
+ private:
+ SeparateDeclarationsTraverser();
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+};
+
+void SeparateDeclarationsTraverser::apply(TIntermNode *root)
+{
+ SeparateDeclarationsTraverser separateDecl;
+ root->traverse(&separateDecl);
+ separateDecl.updateTree();
+}
+
+SeparateDeclarationsTraverser::SeparateDeclarationsTraverser()
+ : TIntermTraverser(true, false, false)
+{}
+
+bool SeparateDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ TIntermSequence *sequence = node->getSequence();
+ if (sequence->size() > 1)
+ {
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ ASSERT(parentBlock != nullptr);
+
+ TIntermSequence replacementDeclarations;
+ for (size_t ii = 0; ii < sequence->size(); ++ii)
+ {
+ TIntermDeclaration *replacementDeclaration = new TIntermDeclaration();
+
+ replacementDeclaration->appendDeclarator(sequence->at(ii)->getAsTyped());
+ replacementDeclaration->setLine(sequence->at(ii)->getLine());
+ replacementDeclarations.push_back(replacementDeclaration);
+ }
+
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(parentBlock, node, replacementDeclarations));
+ }
+ return false;
+}
+
+} // namespace
+
+void SeparateDeclarations(TIntermNode *root)
+{
+ SeparateDeclarationsTraverser::apply(root);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h
new file mode 100644
index 0000000000..1e7f967be9
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The SeparateDeclarations function processes declarations, so that in the end each declaration
+// contains only one declarator.
+// This is useful as an intermediate step when initialization needs to be separated from
+// declaration, or when things need to be unfolded out of the initializer.
+// Example:
+// int a[1] = int[1](1), b[1] = int[1](2);
+// gets transformed when run through this class into the AST equivalent of:
+// int a[1] = int[1](1);
+// int b[1] = int[1](2);
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEDECLARATIONS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEDECLARATIONS_H_
+
+namespace sh
+{
+class TIntermNode;
+
+void SeparateDeclarations(TIntermNode *root);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEDECLARATIONS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp
new file mode 100644
index 0000000000..127e97ebcf
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp
@@ -0,0 +1,129 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names
+// from more complex expressions, assigning them to a temporary variable a#.
+// Examples where a, b and c are all arrays:
+// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2;
+// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i];
+
+#include "compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h"
+
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// Traverser that separates one array expression into a statement at a time.
+class SeparateExpressionsTraverser : public TIntermTraverser
+{
+ public:
+ SeparateExpressionsTraverser(TSymbolTable *symbolTable);
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ void nextIteration();
+ bool foundArrayExpression() const { return mFoundArrayExpression; }
+
+ protected:
+ // Marked to true once an operation that needs to be hoisted out of the expression has been
+ // found. After that, no more AST updates are performed on that traversal.
+ bool mFoundArrayExpression;
+
+ IntermNodePatternMatcher mPatternToSeparateMatcher;
+};
+
+SeparateExpressionsTraverser::SeparateExpressionsTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mFoundArrayExpression(false),
+ mPatternToSeparateMatcher(IntermNodePatternMatcher::kExpressionReturningArray)
+{}
+
+// Performs a shallow copy of an assignment node.
+// These shallow copies are useful when a node gets inserted into an aggregate node
+// and also needs to be replaced in its original location by a different node.
+TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
+{
+ return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight());
+}
+
+bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (mFoundArrayExpression)
+ return false;
+
+ // Return if the expression is not an array or if we're not inside a complex expression.
+ if (!mPatternToSeparateMatcher.match(node, getParentNode()))
+ return true;
+
+ ASSERT(node->getOp() == EOpAssign);
+
+ mFoundArrayExpression = true;
+
+ TIntermSequence insertions;
+ insertions.push_back(CopyAssignmentNode(node));
+ // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just
+ // use the original target of the assignment. Care must be taken so that this doesn't happen
+ // when the same array symbol is a target of assignment more than once in one expression.
+ TIntermDeclaration *arrayVariableDeclaration;
+ TVariable *arrayVariable =
+ DeclareTempVariable(mSymbolTable, node->getLeft(), EvqTemporary, &arrayVariableDeclaration);
+ insertions.push_back(arrayVariableDeclaration);
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(CreateTempSymbolNode(arrayVariable), OriginalNode::IS_DROPPED);
+
+ return false;
+}
+
+bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mFoundArrayExpression)
+ return false; // No need to traverse further
+
+ if (!mPatternToSeparateMatcher.match(node, getParentNode()))
+ return true;
+
+ ASSERT(node->isConstructor() || node->getOp() == EOpCallFunctionInAST);
+
+ mFoundArrayExpression = true;
+
+ TIntermDeclaration *arrayVariableDeclaration;
+ TVariable *arrayVariable = DeclareTempVariable(mSymbolTable, node->shallowCopy(), EvqTemporary,
+ &arrayVariableDeclaration);
+ insertStatementInParentBlock(arrayVariableDeclaration);
+
+ queueReplacement(CreateTempSymbolNode(arrayVariable), OriginalNode::IS_DROPPED);
+
+ return false;
+}
+
+void SeparateExpressionsTraverser::nextIteration()
+{
+ mFoundArrayExpression = false;
+}
+
+} // namespace
+
+void SeparateExpressionsReturningArrays(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ SeparateExpressionsTraverser traverser(symbolTable);
+ // Separate one expression at a time, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundArrayExpression())
+ traverser.updateTree();
+ } while (traverser.foundArrayExpression());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h
new file mode 100644
index 0000000000..9b09f7c61e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names
+// from more complex expressions, assigning them to a temporary variable a#.
+// Examples where a, b and c are all arrays:
+// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2;
+// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i];
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
+
+namespace sh
+{
+class TIntermNode;
+class TSymbolTable;
+
+void SeparateExpressionsReturningArrays(TIntermNode *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp
new file mode 100644
index 0000000000..35d3c33f34
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp
@@ -0,0 +1,299 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions
+// to regular statements inside the loop. This way further transformations that generate statements
+// from loop conditions and loop expressions work correctly.
+//
+
+#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
+
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
+{
+ public:
+ SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask,
+ TSymbolTable *symbolTable);
+
+ void traverseLoop(TIntermLoop *node) override;
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+
+ bool foundLoopToChange() const { return mFoundLoopToChange; }
+
+ protected:
+ // Marked to true once an operation that needs to be hoisted out of a loop expression has been
+ // found.
+ bool mFoundLoopToChange;
+ bool mInsideLoopInitConditionOrExpression;
+ IntermNodePatternMatcher mConditionsToSimplify;
+};
+
+SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
+ unsigned int conditionsToSimplifyMask,
+ TSymbolTable *symbolTable)
+ : TLValueTrackingTraverser(true, false, false, symbolTable),
+ mFoundLoopToChange(false),
+ mInsideLoopInitConditionOrExpression(false),
+ mConditionsToSimplify(conditionsToSimplifyMask)
+{}
+
+// If we're inside a loop initialization, condition, or expression, we check for expressions that
+// should be moved out of the loop condition or expression. If one is found, the loop is
+// transformed.
+// If we're not inside loop initialization, condition, or expression, we only need to traverse nodes
+// that may contain loops.
+
+bool SimplifyLoopConditionsTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (!mInsideLoopInitConditionOrExpression)
+ return false;
+
+ if (mFoundLoopToChange)
+ return false; // Already decided to change this loop.
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node);
+ return !mFoundLoopToChange;
+}
+
+bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (!mInsideLoopInitConditionOrExpression)
+ return false;
+
+ if (mFoundLoopToChange)
+ return false; // Already decided to change this loop.
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
+ return !mFoundLoopToChange;
+}
+
+bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (!mInsideLoopInitConditionOrExpression)
+ return false;
+
+ if (mFoundLoopToChange)
+ return false; // Already decided to change this loop.
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
+ return !mFoundLoopToChange;
+}
+
+bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+ if (!mInsideLoopInitConditionOrExpression)
+ return false;
+
+ if (mFoundLoopToChange)
+ return false; // Already decided to change this loop.
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node);
+ return !mFoundLoopToChange;
+}
+
+bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ if (!mInsideLoopInitConditionOrExpression)
+ return false;
+
+ if (mFoundLoopToChange)
+ return false; // Already decided to change this loop.
+
+ mFoundLoopToChange = mConditionsToSimplify.match(node);
+ return !mFoundLoopToChange;
+}
+
+void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
+{
+ // Mark that we're inside a loop condition or expression, and determine if the loop needs to be
+ // transformed.
+
+ ScopedNodeInTraversalPath addToPath(this, node);
+
+ mInsideLoopInitConditionOrExpression = true;
+ mFoundLoopToChange = false;
+
+ if (!mFoundLoopToChange && node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ if (!mFoundLoopToChange && node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ if (!mFoundLoopToChange && node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ mInsideLoopInitConditionOrExpression = false;
+
+ if (mFoundLoopToChange)
+ {
+ const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
+ TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType);
+
+ // Replace the loop condition with a boolean variable that's updated on each iteration.
+ TLoopType loopType = node->getType();
+ if (loopType == ELoopWhile)
+ {
+ // Transform:
+ // while (expr) { body; }
+ // into
+ // bool s0 = expr;
+ // while (s0) { { body; } s0 = expr; }
+ TIntermDeclaration *tempInitDeclaration =
+ CreateTempInitDeclarationNode(conditionVariable, node->getCondition()->deepCopy());
+ insertStatementInParentBlock(tempInitDeclaration);
+
+ TIntermBlock *newBody = new TIntermBlock();
+ if (node->getBody())
+ {
+ newBody->getSequence()->push_back(node->getBody());
+ }
+ newBody->getSequence()->push_back(
+ CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
+
+ // Can't use queueReplacement to replace old body, since it may have been nullptr.
+ // It's safe to do the replacements in place here - the new body will still be
+ // traversed, but that won't create any problems.
+ node->setBody(newBody);
+ node->setCondition(CreateTempSymbolNode(conditionVariable));
+ }
+ else if (loopType == ELoopDoWhile)
+ {
+ // Transform:
+ // do {
+ // body;
+ // } while (expr);
+ // into
+ // bool s0 = true;
+ // do {
+ // { body; }
+ // s0 = expr;
+ // } while (s0);
+ TIntermDeclaration *tempInitDeclaration =
+ CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(true));
+ insertStatementInParentBlock(tempInitDeclaration);
+
+ TIntermBlock *newBody = new TIntermBlock();
+ if (node->getBody())
+ {
+ newBody->getSequence()->push_back(node->getBody());
+ }
+ newBody->getSequence()->push_back(
+ CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
+
+ // Can't use queueReplacement to replace old body, since it may have been nullptr.
+ // It's safe to do the replacements in place here - the new body will still be
+ // traversed, but that won't create any problems.
+ node->setBody(newBody);
+ node->setCondition(CreateTempSymbolNode(conditionVariable));
+ }
+ else if (loopType == ELoopFor)
+ {
+ // Move the loop condition inside the loop.
+ // Transform:
+ // for (init; expr; exprB) { body; }
+ // into
+ // {
+ // init;
+ // bool s0 = expr;
+ // while (s0) {
+ // { body; }
+ // exprB;
+ // s0 = expr;
+ // }
+ // }
+ TIntermBlock *loopScope = new TIntermBlock();
+ TIntermSequence *loopScopeSequence = loopScope->getSequence();
+
+ // Insert "init;"
+ if (node->getInit())
+ {
+ loopScopeSequence->push_back(node->getInit());
+ }
+
+ // Insert "bool s0 = expr;" if applicable, "bool s0 = true;" otherwise
+ TIntermTyped *conditionInitializer = nullptr;
+ if (node->getCondition())
+ {
+ conditionInitializer = node->getCondition()->deepCopy();
+ }
+ else
+ {
+ conditionInitializer = CreateBoolNode(true);
+ }
+ loopScopeSequence->push_back(
+ CreateTempInitDeclarationNode(conditionVariable, conditionInitializer));
+
+ // Insert "{ body; }" in the while loop
+ TIntermBlock *whileLoopBody = new TIntermBlock();
+ if (node->getBody())
+ {
+ whileLoopBody->getSequence()->push_back(node->getBody());
+ }
+ // Insert "exprB;" in the while loop
+ if (node->getExpression())
+ {
+ whileLoopBody->getSequence()->push_back(node->getExpression());
+ }
+ // Insert "s0 = expr;" in the while loop
+ if (node->getCondition())
+ {
+ whileLoopBody->getSequence()->push_back(
+ CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
+ }
+
+ // Create "while(s0) { whileLoopBody }"
+ TIntermLoop *whileLoop =
+ new TIntermLoop(ELoopWhile, nullptr, CreateTempSymbolNode(conditionVariable),
+ nullptr, whileLoopBody);
+ loopScope->getSequence()->push_back(whileLoop);
+ queueReplacement(loopScope, OriginalNode::IS_DROPPED);
+
+ // After this the old body node will be traversed and loops inside it may be
+ // transformed. This is fine, since the old body node will still be in the AST after the
+ // transformation that's queued here, and transforming loops inside it doesn't need to
+ // know the exact post-transform path to it.
+ }
+ }
+
+ mFoundLoopToChange = false;
+
+ // We traverse the body of the loop even if the loop is transformed.
+ if (node->getBody())
+ node->getBody()->traverse(this);
+}
+
+} // namespace
+
+void SimplifyLoopConditions(TIntermNode *root,
+ unsigned int conditionsToSimplifyMask,
+ TSymbolTable *symbolTable)
+{
+ SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h
new file mode 100644
index 0000000000..15265bb577
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions
+// to regular statements inside the loop. This way further transformations that generate statements
+// from loop conditions and loop expressions work correctly.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SIMPLIFYLOOPCONDITIONS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SIMPLIFYLOOPCONDITIONS_H_
+
+namespace sh
+{
+class TIntermNode;
+class TSymbolTable;
+
+void SimplifyLoopConditions(TIntermNode *root,
+ unsigned int conditionsToSimplify,
+ TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SIMPLIFYLOOPCONDITIONS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp
new file mode 100644
index 0000000000..72804946fa
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp
@@ -0,0 +1,163 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that
+// go through further AST transformations that generate statements, and splits them so that
+// possible side effects of earlier parts of the sequence operator expression are guaranteed to be
+// evaluated before the latter parts of the sequence operator expression are evaluated.
+//
+
+#include "compiler/translator/tree_ops/SplitSequenceOperator.h"
+
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser
+{
+ public:
+ SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, TSymbolTable *symbolTable);
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+
+ void nextIteration();
+ bool foundExpressionToSplit() const { return mFoundExpressionToSplit; }
+
+ protected:
+ // Marked to true once an operation that needs to be hoisted out of the expression has been
+ // found. After that, no more AST updates are performed on that traversal.
+ bool mFoundExpressionToSplit;
+ int mInsideSequenceOperator;
+
+ IntermNodePatternMatcher mPatternToSplitMatcher;
+};
+
+SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask,
+ TSymbolTable *symbolTable)
+ : TLValueTrackingTraverser(true, false, true, symbolTable),
+ mFoundExpressionToSplit(false),
+ mInsideSequenceOperator(0),
+ mPatternToSplitMatcher(patternsToSplitMask)
+{}
+
+void SplitSequenceOperatorTraverser::nextIteration()
+{
+ mFoundExpressionToSplit = false;
+ mInsideSequenceOperator = 0;
+}
+
+bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mFoundExpressionToSplit)
+ return false;
+
+ if (mInsideSequenceOperator > 0 && visit == PreVisit)
+ {
+ // Detect expressions that need to be simplified
+ mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode());
+ return !mFoundExpressionToSplit;
+ }
+
+ return true;
+}
+
+bool SplitSequenceOperatorTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mFoundExpressionToSplit)
+ return false;
+
+ if (mInsideSequenceOperator > 0 && visit == PreVisit)
+ {
+ // Detect expressions that need to be simplified
+ mFoundExpressionToSplit = mPatternToSplitMatcher.match(node);
+ return !mFoundExpressionToSplit;
+ }
+
+ return true;
+}
+
+bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (node->getOp() == EOpComma)
+ {
+ if (visit == PreVisit)
+ {
+ if (mFoundExpressionToSplit)
+ {
+ return false;
+ }
+ mInsideSequenceOperator++;
+ }
+ else if (visit == PostVisit)
+ {
+ // Split sequence operators starting from the outermost one to preserve correct
+ // execution order.
+ if (mFoundExpressionToSplit && mInsideSequenceOperator == 1)
+ {
+ // Move the left side operand into a separate statement in the parent block.
+ TIntermSequence insertions;
+ insertions.push_back(node->getLeft());
+ insertStatementsInParentBlock(insertions);
+ // Replace the comma node with its right side operand.
+ queueReplacement(node->getRight(), OriginalNode::IS_DROPPED);
+ }
+ mInsideSequenceOperator--;
+ }
+ return true;
+ }
+
+ if (mFoundExpressionToSplit)
+ return false;
+
+ if (mInsideSequenceOperator > 0 && visit == PreVisit)
+ {
+ // Detect expressions that need to be simplified
+ mFoundExpressionToSplit =
+ mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere());
+ return !mFoundExpressionToSplit;
+ }
+
+ return true;
+}
+
+bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+ if (mFoundExpressionToSplit)
+ return false;
+
+ if (mInsideSequenceOperator > 0 && visit == PreVisit)
+ {
+ // Detect expressions that need to be simplified
+ mFoundExpressionToSplit = mPatternToSplitMatcher.match(node);
+ return !mFoundExpressionToSplit;
+ }
+
+ return true;
+}
+
+} // namespace
+
+void SplitSequenceOperator(TIntermNode *root, int patternsToSplitMask, TSymbolTable *symbolTable)
+{
+ SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable);
+ // Separate one expression at a time, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundExpressionToSplit())
+ traverser.updateTree();
+ } while (traverser.foundExpressionToSplit());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h
new file mode 100644
index 0000000000..fc341c968e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that
+// go through further AST transformations that generate statements, and splits them so that
+// possible side effects of earlier parts of the sequence operator expression are guaranteed to be
+// evaluated before the latter parts of the sequence operator expression are evaluated.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_SPLITSEQUENCEOPERATOR_H_
+#define COMPILER_TRANSLATOR_TREEOPS_SPLITSEQUENCEOPERATOR_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void SplitSequenceOperator(TIntermNode *root, int patternsToSplitMask, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_SPLITSEQUENCEOPERATOR_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp
new file mode 100644
index 0000000000..e408714fde
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_ops/UnfoldShortCircuitAST.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// "x || y" is equivalent to "x ? true : y".
+TIntermTernary *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
+{
+ return new TIntermTernary(x, CreateBoolNode(true), y);
+}
+
+// "x && y" is equivalent to "x ? y : false".
+TIntermTernary *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
+{
+ return new TIntermTernary(x, y, CreateBoolNode(false));
+}
+
+// This traverser identifies all the short circuit binary nodes that need to
+// be replaced, and creates the corresponding replacement nodes. However,
+// the actual replacements happen after the traverse through updateTree().
+
+class UnfoldShortCircuitASTTraverser : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuitASTTraverser() : TIntermTraverser(true, false, false) {}
+
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+};
+
+bool UnfoldShortCircuitASTTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TIntermTernary *replacement = nullptr;
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ replacement = UnfoldOR(node->getLeft(), node->getRight());
+ break;
+ case EOpLogicalAnd:
+ replacement = UnfoldAND(node->getLeft(), node->getRight());
+ break;
+ default:
+ break;
+ }
+ if (replacement)
+ {
+ queueReplacement(replacement, OriginalNode::IS_DROPPED);
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+void UnfoldShortCircuitAST(TIntermBlock *root)
+{
+ UnfoldShortCircuitASTTraverser traverser;
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h
new file mode 100644
index 0000000000..7f492a9ca0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuitAST is an AST traverser to replace short-circuiting
+// operations with ternary operations.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUITAST_H_
+#define COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUITAST_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+
+void UnfoldShortCircuitAST(TIntermBlock *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUITAST_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp
new file mode 100644
index 0000000000..4a86c04766
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp
@@ -0,0 +1,193 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else
+// statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#include "compiler/translator/tree_ops/UnfoldShortCircuitToIf.h"
+
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// Traverser that unfolds one short-circuiting operation at a time.
+class UnfoldShortCircuitTraverser : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuitTraverser(TSymbolTable *symbolTable);
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
+
+ void nextIteration();
+ bool foundShortCircuit() const { return mFoundShortCircuit; }
+
+ protected:
+ // Marked to true once an operation that needs to be unfolded has been found.
+ // After that, no more unfolding is performed on that traversal.
+ bool mFoundShortCircuit;
+
+ IntermNodePatternMatcher mPatternToUnfoldMatcher;
+};
+
+UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable),
+ mFoundShortCircuit(false),
+ mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression)
+{}
+
+bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (mFoundShortCircuit)
+ return false;
+
+ if (visit != PreVisit)
+ return true;
+
+ if (!mPatternToUnfoldMatcher.match(node, getParentNode()))
+ return true;
+
+ // If our right node doesn't have side effects, we know we don't need to unfold this
+ // expression: there will be no short-circuiting side effects to avoid
+ // (note: unfolding doesn't depend on the left node -- it will always be evaluated)
+ ASSERT(node->getRight()->hasSideEffects());
+
+ mFoundShortCircuit = true;
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ {
+ // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true;
+ // else s = y;",
+ // and then further simplifies down to "bool s = x; if(!s) s = y;".
+
+ TIntermSequence insertions;
+ const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
+ TVariable *resultVariable = CreateTempVariable(mSymbolTable, boolType);
+
+ ASSERT(node->getLeft()->getType() == *boolType);
+ insertions.push_back(CreateTempInitDeclarationNode(resultVariable, node->getLeft()));
+
+ TIntermBlock *assignRightBlock = new TIntermBlock();
+ ASSERT(node->getRight()->getType() == *boolType);
+ assignRightBlock->getSequence()->push_back(
+ CreateTempAssignmentNode(resultVariable, node->getRight()));
+
+ TIntermUnary *notTempSymbol =
+ new TIntermUnary(EOpLogicalNot, CreateTempSymbolNode(resultVariable), nullptr);
+ TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(CreateTempSymbolNode(resultVariable), OriginalNode::IS_DROPPED);
+ return false;
+ }
+ case EOpLogicalAnd:
+ {
+ // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y;
+ // else s = false;",
+ // and then further simplifies down to "bool s = x; if(s) s = y;".
+ TIntermSequence insertions;
+ const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
+ TVariable *resultVariable = CreateTempVariable(mSymbolTable, boolType);
+
+ ASSERT(node->getLeft()->getType() == *boolType);
+ insertions.push_back(CreateTempInitDeclarationNode(resultVariable, node->getLeft()));
+
+ TIntermBlock *assignRightBlock = new TIntermBlock();
+ ASSERT(node->getRight()->getType() == *boolType);
+ assignRightBlock->getSequence()->push_back(
+ CreateTempAssignmentNode(resultVariable, node->getRight()));
+
+ TIntermIfElse *ifNode =
+ new TIntermIfElse(CreateTempSymbolNode(resultVariable), assignRightBlock, nullptr);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ queueReplacement(CreateTempSymbolNode(resultVariable), OriginalNode::IS_DROPPED);
+ return false;
+ }
+ default:
+ UNREACHABLE();
+ return true;
+ }
+}
+
+bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+ if (mFoundShortCircuit)
+ return false;
+
+ if (visit != PreVisit)
+ return true;
+
+ if (!mPatternToUnfoldMatcher.match(node))
+ return true;
+
+ mFoundShortCircuit = true;
+
+ // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
+ TIntermSequence insertions;
+ TIntermDeclaration *tempDeclaration = nullptr;
+ TVariable *resultVariable = DeclareTempVariable(mSymbolTable, new TType(node->getType()),
+ EvqTemporary, &tempDeclaration);
+ insertions.push_back(tempDeclaration);
+
+ TIntermBlock *trueBlock = new TIntermBlock();
+ TIntermBinary *trueAssignment =
+ CreateTempAssignmentNode(resultVariable, node->getTrueExpression());
+ trueBlock->getSequence()->push_back(trueAssignment);
+
+ TIntermBlock *falseBlock = new TIntermBlock();
+ TIntermBinary *falseAssignment =
+ CreateTempAssignmentNode(resultVariable, node->getFalseExpression());
+ falseBlock->getSequence()->push_back(falseAssignment);
+
+ TIntermIfElse *ifNode =
+ new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ TIntermSymbol *ternaryResult = CreateTempSymbolNode(resultVariable);
+ queueReplacement(ternaryResult, OriginalNode::IS_DROPPED);
+
+ return false;
+}
+
+void UnfoldShortCircuitTraverser::nextIteration()
+{
+ mFoundShortCircuit = false;
+}
+
+} // namespace
+
+void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable)
+{
+ UnfoldShortCircuitTraverser traverser(symbolTable);
+ // Unfold one operator at a time, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundShortCircuit())
+ traverser.updateTree();
+ } while (traverser.foundShortCircuit());
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h
new file mode 100644
index 0000000000..3458cd27f0
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else
+// statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUIT_H_
+#define COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUIT_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUIT_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp
new file mode 100644
index 0000000000..83a133ca1f
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp
@@ -0,0 +1,104 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// UseInterfaceBlockFields.cpp: insert statements to reference all members in InterfaceBlock list at
+// the beginning of main. This is to work around a Mac driver that treats unused standard/shared
+// uniform blocks as inactive.
+
+#include "compiler/translator/tree_ops/UseInterfaceBlockFields.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/FindMain.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void AddNodeUseStatements(TIntermTyped *node, TIntermSequence *sequence)
+{
+ if (node->isArray())
+ {
+ for (unsigned int i = 0u; i < node->getOutermostArraySize(); ++i)
+ {
+ TIntermBinary *element =
+ new TIntermBinary(EOpIndexDirect, node->deepCopy(), CreateIndexNode(i));
+ AddNodeUseStatements(element, sequence);
+ }
+ }
+ else
+ {
+ sequence->insert(sequence->begin(), node);
+ }
+}
+
+void AddFieldUseStatements(const ShaderVariable &var,
+ TIntermSequence *sequence,
+ const TSymbolTable &symbolTable)
+{
+ ASSERT(var.name.find_last_of('[') == std::string::npos);
+ TIntermSymbol *symbol = ReferenceGlobalVariable(ImmutableString(var.name), symbolTable);
+ AddNodeUseStatements(symbol, sequence);
+}
+
+void InsertUseCode(const InterfaceBlock &block, TIntermTyped *blockNode, TIntermSequence *sequence)
+{
+ for (unsigned int i = 0; i < block.fields.size(); ++i)
+ {
+ TIntermBinary *element = new TIntermBinary(EOpIndexDirectInterfaceBlock,
+ blockNode->deepCopy(), CreateIndexNode(i));
+ sequence->insert(sequence->begin(), element);
+ }
+}
+
+void InsertUseCode(TIntermSequence *sequence,
+ const InterfaceBlockList &blocks,
+ const TSymbolTable &symbolTable)
+{
+ for (const auto &block : blocks)
+ {
+ if (block.instanceName.empty())
+ {
+ for (const auto &var : block.fields)
+ {
+ AddFieldUseStatements(var, sequence, symbolTable);
+ }
+ }
+ else if (block.arraySize > 0u)
+ {
+ TIntermSymbol *arraySymbol =
+ ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable);
+ for (unsigned int i = 0u; i < block.arraySize; ++i)
+ {
+ TIntermBinary *elementSymbol =
+ new TIntermBinary(EOpIndexDirect, arraySymbol->deepCopy(), CreateIndexNode(i));
+ InsertUseCode(block, elementSymbol, sequence);
+ }
+ }
+ else
+ {
+ TIntermSymbol *blockSymbol =
+ ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable);
+ InsertUseCode(block, blockSymbol, sequence);
+ }
+ }
+}
+
+} // namespace
+
+void UseInterfaceBlockFields(TIntermBlock *root,
+ const InterfaceBlockList &blocks,
+ const TSymbolTable &symbolTable)
+{
+ TIntermBlock *mainBody = FindMainBody(root);
+ InsertUseCode(mainBody->getSequence(), blocks, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h
new file mode 100644
index 0000000000..37f0ba0220
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h
@@ -0,0 +1,30 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// UseInterfaceBlockFields.h: insert statements to reference all members in InterfaceBlock list at
+// the beginning of main. This is to work around a Mac driver that treats unused standard/shared
+// uniform blocks as inactive.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_USEINTERFACEBLOCKFIELDS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_USEINTERFACEBLOCKFIELDS_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+using InterfaceBlockList = std::vector<sh::InterfaceBlock>;
+
+void UseInterfaceBlockFields(TIntermBlock *root,
+ const InterfaceBlockList &blocks,
+ const TSymbolTable &symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_USEINTERFACEBLOCKFIELDS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp
new file mode 100644
index 0000000000..221a73592b
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp
@@ -0,0 +1,287 @@
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// VectorizeVectorScalarArithmetic.cpp: Turn some arithmetic operations that operate on a float
+// vector-scalar pair into vector-vector operations. This is done recursively. Some scalar binary
+// operations inside vector constructors are also turned into vector operations.
+//
+// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA
+// driver version 387.92. It works around the most common occurrences of the bug.
+
+#include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h"
+
+#include <set>
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class VectorizeVectorScalarArithmeticTraverser : public TIntermTraverser
+{
+ public:
+ VectorizeVectorScalarArithmeticTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable), mReplaced(false)
+ {}
+
+ bool didReplaceScalarsWithVectors() { return mReplaced; }
+ void nextIteration()
+ {
+ mReplaced = false;
+ mModifiedBlocks.clear();
+ }
+
+ protected:
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ private:
+ // These helpers should only be called from visitAggregate when visiting a constructor.
+ // argBinary is the only argument of the constructor.
+ void replaceMathInsideConstructor(TIntermAggregate *node, TIntermBinary *argBinary);
+ void replaceAssignInsideConstructor(const TIntermAggregate *node,
+ const TIntermBinary *argBinary);
+
+ static TIntermTyped *Vectorize(TIntermTyped *node,
+ TType vectorType,
+ TIntermTraverser::OriginalNode *originalNodeFate);
+
+ bool mReplaced;
+ std::set<const TIntermBlock *> mModifiedBlocks;
+};
+
+TIntermTyped *VectorizeVectorScalarArithmeticTraverser::Vectorize(
+ TIntermTyped *node,
+ TType vectorType,
+ TIntermTraverser::OriginalNode *originalNodeFate)
+{
+ ASSERT(node->isScalar());
+ vectorType.setQualifier(EvqTemporary);
+ TIntermSequence vectorConstructorArgs;
+ vectorConstructorArgs.push_back(node);
+ TIntermAggregate *vectorized =
+ TIntermAggregate::CreateConstructor(vectorType, &vectorConstructorArgs);
+ TIntermTyped *vectorizedFolded = vectorized->fold(nullptr);
+ if (originalNodeFate != nullptr)
+ {
+ if (vectorizedFolded != vectorized)
+ {
+ *originalNodeFate = OriginalNode::IS_DROPPED;
+ }
+ else
+ {
+ *originalNodeFate = OriginalNode::BECOMES_CHILD;
+ }
+ }
+ return vectorizedFolded;
+}
+
+bool VectorizeVectorScalarArithmeticTraverser::visitBinary(Visit /*visit*/, TIntermBinary *node)
+{
+ TIntermTyped *left = node->getLeft();
+ TIntermTyped *right = node->getRight();
+ ASSERT(left);
+ ASSERT(right);
+ switch (node->getOp())
+ {
+ case EOpAdd:
+ case EOpAddAssign:
+ // Only these specific ops are necessary to turn into vector ops.
+ break;
+ default:
+ return true;
+ }
+ if (node->getBasicType() != EbtFloat)
+ {
+ // Only float ops have reproduced the bug.
+ return true;
+ }
+ if (left->isScalar() && right->isVector())
+ {
+ ASSERT(!node->isAssignment());
+ ASSERT(!right->isArray());
+ OriginalNode originalNodeFate;
+ TIntermTyped *leftVectorized = Vectorize(left, right->getType(), &originalNodeFate);
+ queueReplacementWithParent(node, left, leftVectorized, originalNodeFate);
+ mReplaced = true;
+ // Don't replace more nodes in the same subtree on this traversal. However, nodes elsewhere
+ // in the tree may still be replaced.
+ return false;
+ }
+ else if (left->isVector() && right->isScalar())
+ {
+ OriginalNode originalNodeFate;
+ TIntermTyped *rightVectorized = Vectorize(right, left->getType(), &originalNodeFate);
+ queueReplacementWithParent(node, right, rightVectorized, originalNodeFate);
+ mReplaced = true;
+ // Don't replace more nodes in the same subtree on this traversal. However, nodes elsewhere
+ // in the tree may still be replaced.
+ return false;
+ }
+ return true;
+}
+
+void VectorizeVectorScalarArithmeticTraverser::replaceMathInsideConstructor(
+ TIntermAggregate *node,
+ TIntermBinary *argBinary)
+{
+ // Turn:
+ // a * b
+ // into:
+ // gvec(a) * gvec(b)
+
+ TIntermTyped *left = argBinary->getLeft();
+ TIntermTyped *right = argBinary->getRight();
+ ASSERT(left->isScalar() && right->isScalar());
+
+ TType leftVectorizedType = left->getType();
+ leftVectorizedType.setPrimarySize(static_cast<unsigned char>(node->getType().getNominalSize()));
+ TIntermTyped *leftVectorized = Vectorize(left, leftVectorizedType, nullptr);
+ TType rightVectorizedType = right->getType();
+ rightVectorizedType.setPrimarySize(
+ static_cast<unsigned char>(node->getType().getNominalSize()));
+ TIntermTyped *rightVectorized = Vectorize(right, rightVectorizedType, nullptr);
+
+ TIntermBinary *newArg = new TIntermBinary(argBinary->getOp(), leftVectorized, rightVectorized);
+ queueReplacementWithParent(node, argBinary, newArg, OriginalNode::IS_DROPPED);
+}
+
+void VectorizeVectorScalarArithmeticTraverser::replaceAssignInsideConstructor(
+ const TIntermAggregate *node,
+ const TIntermBinary *argBinary)
+{
+ // Turn:
+ // gvec(a *= b);
+ // into:
+ // // This is inserted into the parent block:
+ // gvec s0 = gvec(a);
+ //
+ // // This goes where the gvec constructor used to be:
+ // ((s0 *= b, a = s0.x), s0);
+
+ TIntermTyped *left = argBinary->getLeft();
+ TIntermTyped *right = argBinary->getRight();
+ ASSERT(left->isScalar() && right->isScalar());
+ ASSERT(!left->hasSideEffects());
+
+ TType vecType = node->getType();
+ vecType.setQualifier(EvqTemporary);
+
+ // gvec s0 = gvec(a);
+ // s0 is called "tempAssignmentTarget" below.
+ TIntermTyped *tempAssignmentTargetInitializer = Vectorize(left->deepCopy(), vecType, nullptr);
+ TIntermDeclaration *tempAssignmentTargetDeclaration = nullptr;
+ TVariable *tempAssignmentTarget =
+ DeclareTempVariable(mSymbolTable, tempAssignmentTargetInitializer, EvqTemporary,
+ &tempAssignmentTargetDeclaration);
+
+ // s0 *= b
+ TOperator compoundAssignmentOp = argBinary->getOp();
+ if (compoundAssignmentOp == EOpMulAssign)
+ {
+ compoundAssignmentOp = EOpVectorTimesScalarAssign;
+ }
+ TIntermBinary *replacementCompoundAssignment = new TIntermBinary(
+ compoundAssignmentOp, CreateTempSymbolNode(tempAssignmentTarget), right->deepCopy());
+
+ // s0.x
+ TVector<int> swizzleXOffset;
+ swizzleXOffset.push_back(0);
+ TIntermSwizzle *tempAssignmentTargetX =
+ new TIntermSwizzle(CreateTempSymbolNode(tempAssignmentTarget), swizzleXOffset);
+ // a = s0.x
+ TIntermBinary *replacementAssignBackToTarget =
+ new TIntermBinary(EOpAssign, left->deepCopy(), tempAssignmentTargetX);
+
+ // s0 *= b, a = s0.x
+ TIntermBinary *replacementSequenceLeft =
+ new TIntermBinary(EOpComma, replacementCompoundAssignment, replacementAssignBackToTarget);
+ // (s0 *= b, a = s0.x), s0
+ // Note that the created comma node is not const qualified in any case, so we can always pass
+ // shader version 300 here.
+ TIntermBinary *replacementSequence = TIntermBinary::CreateComma(
+ replacementSequenceLeft, CreateTempSymbolNode(tempAssignmentTarget), 300);
+
+ insertStatementInParentBlock(tempAssignmentTargetDeclaration);
+ queueReplacement(replacementSequence, OriginalNode::IS_DROPPED);
+}
+
+bool VectorizeVectorScalarArithmeticTraverser::visitAggregate(Visit /*visit*/,
+ TIntermAggregate *node)
+{
+ // Transform scalar binary expressions inside vector constructors.
+ if (!node->isConstructor() || !node->isVector() || node->getSequence()->size() != 1)
+ {
+ return true;
+ }
+ TIntermTyped *argument = node->getSequence()->back()->getAsTyped();
+ ASSERT(argument);
+ if (!argument->isScalar() || argument->getBasicType() != EbtFloat)
+ {
+ return true;
+ }
+ TIntermBinary *argBinary = argument->getAsBinaryNode();
+ if (!argBinary)
+ {
+ return true;
+ }
+
+ // Only specific ops are necessary to change.
+ switch (argBinary->getOp())
+ {
+ case EOpMul:
+ case EOpDiv:
+ {
+ replaceMathInsideConstructor(node, argBinary);
+ mReplaced = true;
+ // Don't replace more nodes in the same subtree on this traversal. However, nodes
+ // elsewhere in the tree may still be replaced.
+ return false;
+ }
+ case EOpMulAssign:
+ case EOpDivAssign:
+ {
+ // The case where the left side has side effects is too complicated to deal with, so we
+ // leave that be.
+ if (!argBinary->getLeft()->hasSideEffects())
+ {
+ const TIntermBlock *parentBlock = getParentBlock();
+ // We can't do more than one insertion to the same block on the same traversal.
+ if (mModifiedBlocks.find(parentBlock) == mModifiedBlocks.end())
+ {
+ replaceAssignInsideConstructor(node, argBinary);
+ mModifiedBlocks.insert(parentBlock);
+ mReplaced = true;
+ // Don't replace more nodes in the same subtree on this traversal.
+ // However, nodes elsewhere in the tree may still be replaced.
+ return false;
+ }
+ }
+ break;
+ }
+ default:
+ return true;
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+void VectorizeVectorScalarArithmetic(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ VectorizeVectorScalarArithmeticTraverser traverser(symbolTable);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ } while (traverser.didReplaceScalarsWithVectors());
+}
+
+} // namespace sh \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h
new file mode 100644
index 0000000000..e6480646f8
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// VectorizeVectorScalarArithmetic.h: Turn some arithmetic operations that operate on a float
+// vector-scalar pair into vector-vector operations. This is done recursively. Some scalar binary
+// operations inside vector constructors are also turned into vector operations.
+//
+// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA
+// driver version 387.92. It works around the most common occurrences of the bug.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_VECTORIZEVECTORSCALARARITHMETIC_H_
+#define COMPILER_TRANSLATOR_TREEOPS_VECTORIZEVECTORSCALARARITHMETIC_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void VectorizeVectorScalarArithmetic(TIntermBlock *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_VECTORIZEVECTORSCALARARITHMETIC_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp
new file mode 100644
index 0000000000..5a4dd30853
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp
@@ -0,0 +1,126 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WrapSwitchStatementsInBlocks.cpp: Wrap switch statements in blocks and declare all switch-scoped
+// variables there to make the AST compatible with HLSL output.
+//
+// switch (init)
+// {
+// case 0:
+// float f;
+// default:
+// f = 1.0;
+// }
+//
+// becomes
+//
+// {
+// float f;
+// switch (init)
+// {
+// case 0:
+// default:
+// f = 1.0;
+// }
+// }
+
+#include "compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class WrapSwitchStatementsInBlocksTraverser : public TIntermTraverser
+{
+ public:
+ WrapSwitchStatementsInBlocksTraverser() : TIntermTraverser(true, false, false) {}
+
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+};
+
+bool WrapSwitchStatementsInBlocksTraverser::visitSwitch(Visit, TIntermSwitch *node)
+{
+ std::vector<TIntermDeclaration *> declarations;
+ TIntermSequence *statementList = node->getStatementList()->getSequence();
+ for (TIntermNode *statement : *statementList)
+ {
+ TIntermDeclaration *asDeclaration = statement->getAsDeclarationNode();
+ if (asDeclaration)
+ {
+ declarations.push_back(asDeclaration);
+ }
+ }
+ if (declarations.empty())
+ {
+ // We don't need to wrap the switch if it doesn't contain declarations as its direct
+ // descendants.
+ return true;
+ }
+
+ TIntermBlock *wrapperBlock = new TIntermBlock();
+ for (TIntermDeclaration *declaration : declarations)
+ {
+ // SeparateDeclarations should have already been run.
+ ASSERT(declaration->getSequence()->size() == 1);
+
+ TIntermDeclaration *declarationInBlock = new TIntermDeclaration();
+ TIntermSymbol *declaratorAsSymbol = declaration->getSequence()->at(0)->getAsSymbolNode();
+ if (declaratorAsSymbol)
+ {
+ // This is a simple declaration like: "float f;"
+ // Remove the declaration from inside the switch and put it in the wrapping block.
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
+ node->getStatementList(), declaration, emptyReplacement));
+
+ declarationInBlock->appendDeclarator(declaratorAsSymbol->deepCopy());
+ // The declaration can't be the last statement inside the switch since unused variables
+ // should already have been pruned.
+ ASSERT(declaration != statementList->back());
+ }
+ else
+ {
+ // This is an init declaration like: "float f = 0.0;"
+ // Change the init declaration inside the switch into an assignment and put a plain
+ // declaration in the wrapping block.
+ TIntermBinary *declaratorAsBinary =
+ declaration->getSequence()->at(0)->getAsBinaryNode();
+ ASSERT(declaratorAsBinary);
+
+ TIntermBinary *initAssignment = new TIntermBinary(
+ EOpAssign, declaratorAsBinary->getLeft(), declaratorAsBinary->getRight());
+
+ queueReplacementWithParent(node->getStatementList(), declaration, initAssignment,
+ OriginalNode::IS_DROPPED);
+
+ declarationInBlock->appendDeclarator(declaratorAsBinary->getLeft()->deepCopy());
+ }
+ wrapperBlock->appendStatement(declarationInBlock);
+ }
+
+ wrapperBlock->appendStatement(node);
+ queueReplacement(wrapperBlock, OriginalNode::BECOMES_CHILD);
+
+ // Should be fine to process multiple switch statements, even nesting ones in the same
+ // traversal.
+ return true;
+}
+
+} // anonymous namespace
+
+// Wrap switch statements in the AST into blocks when needed.
+void WrapSwitchStatementsInBlocks(TIntermBlock *root)
+{
+ WrapSwitchStatementsInBlocksTraverser traverser;
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h
new file mode 100644
index 0000000000..d04893cb52
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WrapSwitchStatementsInBlocks.h: Wrap switch statements in blocks and declare all switch-scoped
+// variables there to make the AST compatible with HLSL output.
+
+#ifndef COMPILER_TRANSLATOR_TREEOPS_WRAPSWITCHSTATEMENTSINBLOCKS_H_
+#define COMPILER_TRANSLATOR_TREEOPS_WRAPSWITCHSTATEMENTSINBLOCKS_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+
+// Wrap switch statements in the AST into blocks when needed. Returns true if the AST was changed.
+void WrapSwitchStatementsInBlocks(TIntermBlock *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEOPS_WRAPSWITCHSTATEMENTSINBLOCKS_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h b/gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h
new file mode 100644
index 0000000000..6c84834550
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h
@@ -0,0 +1,1373 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_builtin_symbols.py using data from builtin_variables.json and
+// builtin_function_declarations.txt.
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// BuiltIn_autogen.h:
+// Compile-time initialized built-ins.
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_
+
+#include "compiler/translator/SymbolUniqueId.h"
+
+namespace sh
+{
+
+class TVariable;
+
+class BuiltInId
+{
+ public:
+ static constexpr const TSymbolUniqueId radians_Float1 = TSymbolUniqueId(0);
+ static constexpr const TSymbolUniqueId pt0B = TSymbolUniqueId(1);
+ static constexpr const TSymbolUniqueId radians_Float2 = TSymbolUniqueId(2);
+ static constexpr const TSymbolUniqueId pt1B = TSymbolUniqueId(3);
+ static constexpr const TSymbolUniqueId radians_Float3 = TSymbolUniqueId(4);
+ static constexpr const TSymbolUniqueId pt2B = TSymbolUniqueId(5);
+ static constexpr const TSymbolUniqueId radians_Float4 = TSymbolUniqueId(6);
+ static constexpr const TSymbolUniqueId pt3B = TSymbolUniqueId(7);
+ static constexpr const TSymbolUniqueId degrees_Float1 = TSymbolUniqueId(8);
+ static constexpr const TSymbolUniqueId degrees_Float2 = TSymbolUniqueId(9);
+ static constexpr const TSymbolUniqueId degrees_Float3 = TSymbolUniqueId(10);
+ static constexpr const TSymbolUniqueId degrees_Float4 = TSymbolUniqueId(11);
+ static constexpr const TSymbolUniqueId sin_Float1 = TSymbolUniqueId(12);
+ static constexpr const TSymbolUniqueId sin_Float2 = TSymbolUniqueId(13);
+ static constexpr const TSymbolUniqueId sin_Float3 = TSymbolUniqueId(14);
+ static constexpr const TSymbolUniqueId sin_Float4 = TSymbolUniqueId(15);
+ static constexpr const TSymbolUniqueId cos_Float1 = TSymbolUniqueId(16);
+ static constexpr const TSymbolUniqueId cos_Float2 = TSymbolUniqueId(17);
+ static constexpr const TSymbolUniqueId cos_Float3 = TSymbolUniqueId(18);
+ static constexpr const TSymbolUniqueId cos_Float4 = TSymbolUniqueId(19);
+ static constexpr const TSymbolUniqueId tan_Float1 = TSymbolUniqueId(20);
+ static constexpr const TSymbolUniqueId tan_Float2 = TSymbolUniqueId(21);
+ static constexpr const TSymbolUniqueId tan_Float3 = TSymbolUniqueId(22);
+ static constexpr const TSymbolUniqueId tan_Float4 = TSymbolUniqueId(23);
+ static constexpr const TSymbolUniqueId asin_Float1 = TSymbolUniqueId(24);
+ static constexpr const TSymbolUniqueId asin_Float2 = TSymbolUniqueId(25);
+ static constexpr const TSymbolUniqueId asin_Float3 = TSymbolUniqueId(26);
+ static constexpr const TSymbolUniqueId asin_Float4 = TSymbolUniqueId(27);
+ static constexpr const TSymbolUniqueId acos_Float1 = TSymbolUniqueId(28);
+ static constexpr const TSymbolUniqueId acos_Float2 = TSymbolUniqueId(29);
+ static constexpr const TSymbolUniqueId acos_Float3 = TSymbolUniqueId(30);
+ static constexpr const TSymbolUniqueId acos_Float4 = TSymbolUniqueId(31);
+ static constexpr const TSymbolUniqueId atan_Float1_Float1 = TSymbolUniqueId(32);
+ static constexpr const TSymbolUniqueId atan_Float2_Float2 = TSymbolUniqueId(33);
+ static constexpr const TSymbolUniqueId atan_Float3_Float3 = TSymbolUniqueId(34);
+ static constexpr const TSymbolUniqueId atan_Float4_Float4 = TSymbolUniqueId(35);
+ static constexpr const TSymbolUniqueId atan_Float1 = TSymbolUniqueId(36);
+ static constexpr const TSymbolUniqueId atan_Float2 = TSymbolUniqueId(37);
+ static constexpr const TSymbolUniqueId atan_Float3 = TSymbolUniqueId(38);
+ static constexpr const TSymbolUniqueId atan_Float4 = TSymbolUniqueId(39);
+ static constexpr const TSymbolUniqueId sinh_Float1 = TSymbolUniqueId(40);
+ static constexpr const TSymbolUniqueId sinh_Float2 = TSymbolUniqueId(41);
+ static constexpr const TSymbolUniqueId sinh_Float3 = TSymbolUniqueId(42);
+ static constexpr const TSymbolUniqueId sinh_Float4 = TSymbolUniqueId(43);
+ static constexpr const TSymbolUniqueId cosh_Float1 = TSymbolUniqueId(44);
+ static constexpr const TSymbolUniqueId cosh_Float2 = TSymbolUniqueId(45);
+ static constexpr const TSymbolUniqueId cosh_Float3 = TSymbolUniqueId(46);
+ static constexpr const TSymbolUniqueId cosh_Float4 = TSymbolUniqueId(47);
+ static constexpr const TSymbolUniqueId tanh_Float1 = TSymbolUniqueId(48);
+ static constexpr const TSymbolUniqueId tanh_Float2 = TSymbolUniqueId(49);
+ static constexpr const TSymbolUniqueId tanh_Float3 = TSymbolUniqueId(50);
+ static constexpr const TSymbolUniqueId tanh_Float4 = TSymbolUniqueId(51);
+ static constexpr const TSymbolUniqueId asinh_Float1 = TSymbolUniqueId(52);
+ static constexpr const TSymbolUniqueId asinh_Float2 = TSymbolUniqueId(53);
+ static constexpr const TSymbolUniqueId asinh_Float3 = TSymbolUniqueId(54);
+ static constexpr const TSymbolUniqueId asinh_Float4 = TSymbolUniqueId(55);
+ static constexpr const TSymbolUniqueId acosh_Float1 = TSymbolUniqueId(56);
+ static constexpr const TSymbolUniqueId acosh_Float2 = TSymbolUniqueId(57);
+ static constexpr const TSymbolUniqueId acosh_Float3 = TSymbolUniqueId(58);
+ static constexpr const TSymbolUniqueId acosh_Float4 = TSymbolUniqueId(59);
+ static constexpr const TSymbolUniqueId atanh_Float1 = TSymbolUniqueId(60);
+ static constexpr const TSymbolUniqueId atanh_Float2 = TSymbolUniqueId(61);
+ static constexpr const TSymbolUniqueId atanh_Float3 = TSymbolUniqueId(62);
+ static constexpr const TSymbolUniqueId atanh_Float4 = TSymbolUniqueId(63);
+ static constexpr const TSymbolUniqueId pow_Float1_Float1 = TSymbolUniqueId(64);
+ static constexpr const TSymbolUniqueId pow_Float2_Float2 = TSymbolUniqueId(65);
+ static constexpr const TSymbolUniqueId pow_Float3_Float3 = TSymbolUniqueId(66);
+ static constexpr const TSymbolUniqueId pow_Float4_Float4 = TSymbolUniqueId(67);
+ static constexpr const TSymbolUniqueId exp_Float1 = TSymbolUniqueId(68);
+ static constexpr const TSymbolUniqueId exp_Float2 = TSymbolUniqueId(69);
+ static constexpr const TSymbolUniqueId exp_Float3 = TSymbolUniqueId(70);
+ static constexpr const TSymbolUniqueId exp_Float4 = TSymbolUniqueId(71);
+ static constexpr const TSymbolUniqueId log_Float1 = TSymbolUniqueId(72);
+ static constexpr const TSymbolUniqueId log_Float2 = TSymbolUniqueId(73);
+ static constexpr const TSymbolUniqueId log_Float3 = TSymbolUniqueId(74);
+ static constexpr const TSymbolUniqueId log_Float4 = TSymbolUniqueId(75);
+ static constexpr const TSymbolUniqueId exp2_Float1 = TSymbolUniqueId(76);
+ static constexpr const TSymbolUniqueId exp2_Float2 = TSymbolUniqueId(77);
+ static constexpr const TSymbolUniqueId exp2_Float3 = TSymbolUniqueId(78);
+ static constexpr const TSymbolUniqueId exp2_Float4 = TSymbolUniqueId(79);
+ static constexpr const TSymbolUniqueId log2_Float1 = TSymbolUniqueId(80);
+ static constexpr const TSymbolUniqueId log2_Float2 = TSymbolUniqueId(81);
+ static constexpr const TSymbolUniqueId log2_Float3 = TSymbolUniqueId(82);
+ static constexpr const TSymbolUniqueId log2_Float4 = TSymbolUniqueId(83);
+ static constexpr const TSymbolUniqueId sqrt_Float1 = TSymbolUniqueId(84);
+ static constexpr const TSymbolUniqueId sqrt_Float2 = TSymbolUniqueId(85);
+ static constexpr const TSymbolUniqueId sqrt_Float3 = TSymbolUniqueId(86);
+ static constexpr const TSymbolUniqueId sqrt_Float4 = TSymbolUniqueId(87);
+ static constexpr const TSymbolUniqueId inversesqrt_Float1 = TSymbolUniqueId(88);
+ static constexpr const TSymbolUniqueId inversesqrt_Float2 = TSymbolUniqueId(89);
+ static constexpr const TSymbolUniqueId inversesqrt_Float3 = TSymbolUniqueId(90);
+ static constexpr const TSymbolUniqueId inversesqrt_Float4 = TSymbolUniqueId(91);
+ static constexpr const TSymbolUniqueId abs_Float1 = TSymbolUniqueId(92);
+ static constexpr const TSymbolUniqueId abs_Float2 = TSymbolUniqueId(93);
+ static constexpr const TSymbolUniqueId abs_Float3 = TSymbolUniqueId(94);
+ static constexpr const TSymbolUniqueId abs_Float4 = TSymbolUniqueId(95);
+ static constexpr const TSymbolUniqueId abs_Int1 = TSymbolUniqueId(96);
+ static constexpr const TSymbolUniqueId pt0C = TSymbolUniqueId(97);
+ static constexpr const TSymbolUniqueId abs_Int2 = TSymbolUniqueId(98);
+ static constexpr const TSymbolUniqueId pt1C = TSymbolUniqueId(99);
+ static constexpr const TSymbolUniqueId abs_Int3 = TSymbolUniqueId(100);
+ static constexpr const TSymbolUniqueId pt2C = TSymbolUniqueId(101);
+ static constexpr const TSymbolUniqueId abs_Int4 = TSymbolUniqueId(102);
+ static constexpr const TSymbolUniqueId pt3C = TSymbolUniqueId(103);
+ static constexpr const TSymbolUniqueId sign_Float1 = TSymbolUniqueId(104);
+ static constexpr const TSymbolUniqueId sign_Float2 = TSymbolUniqueId(105);
+ static constexpr const TSymbolUniqueId sign_Float3 = TSymbolUniqueId(106);
+ static constexpr const TSymbolUniqueId sign_Float4 = TSymbolUniqueId(107);
+ static constexpr const TSymbolUniqueId sign_Int1 = TSymbolUniqueId(108);
+ static constexpr const TSymbolUniqueId sign_Int2 = TSymbolUniqueId(109);
+ static constexpr const TSymbolUniqueId sign_Int3 = TSymbolUniqueId(110);
+ static constexpr const TSymbolUniqueId sign_Int4 = TSymbolUniqueId(111);
+ static constexpr const TSymbolUniqueId floor_Float1 = TSymbolUniqueId(112);
+ static constexpr const TSymbolUniqueId floor_Float2 = TSymbolUniqueId(113);
+ static constexpr const TSymbolUniqueId floor_Float3 = TSymbolUniqueId(114);
+ static constexpr const TSymbolUniqueId floor_Float4 = TSymbolUniqueId(115);
+ static constexpr const TSymbolUniqueId trunc_Float1 = TSymbolUniqueId(116);
+ static constexpr const TSymbolUniqueId trunc_Float2 = TSymbolUniqueId(117);
+ static constexpr const TSymbolUniqueId trunc_Float3 = TSymbolUniqueId(118);
+ static constexpr const TSymbolUniqueId trunc_Float4 = TSymbolUniqueId(119);
+ static constexpr const TSymbolUniqueId round_Float1 = TSymbolUniqueId(120);
+ static constexpr const TSymbolUniqueId round_Float2 = TSymbolUniqueId(121);
+ static constexpr const TSymbolUniqueId round_Float3 = TSymbolUniqueId(122);
+ static constexpr const TSymbolUniqueId round_Float4 = TSymbolUniqueId(123);
+ static constexpr const TSymbolUniqueId roundEven_Float1 = TSymbolUniqueId(124);
+ static constexpr const TSymbolUniqueId roundEven_Float2 = TSymbolUniqueId(125);
+ static constexpr const TSymbolUniqueId roundEven_Float3 = TSymbolUniqueId(126);
+ static constexpr const TSymbolUniqueId roundEven_Float4 = TSymbolUniqueId(127);
+ static constexpr const TSymbolUniqueId ceil_Float1 = TSymbolUniqueId(128);
+ static constexpr const TSymbolUniqueId ceil_Float2 = TSymbolUniqueId(129);
+ static constexpr const TSymbolUniqueId ceil_Float3 = TSymbolUniqueId(130);
+ static constexpr const TSymbolUniqueId ceil_Float4 = TSymbolUniqueId(131);
+ static constexpr const TSymbolUniqueId fract_Float1 = TSymbolUniqueId(132);
+ static constexpr const TSymbolUniqueId fract_Float2 = TSymbolUniqueId(133);
+ static constexpr const TSymbolUniqueId fract_Float3 = TSymbolUniqueId(134);
+ static constexpr const TSymbolUniqueId fract_Float4 = TSymbolUniqueId(135);
+ static constexpr const TSymbolUniqueId mod_Float1_Float1 = TSymbolUniqueId(136);
+ static constexpr const TSymbolUniqueId mod_Float2_Float1 = TSymbolUniqueId(137);
+ static constexpr const TSymbolUniqueId mod_Float3_Float1 = TSymbolUniqueId(138);
+ static constexpr const TSymbolUniqueId mod_Float4_Float1 = TSymbolUniqueId(139);
+ static constexpr const TSymbolUniqueId mod_Float2_Float2 = TSymbolUniqueId(140);
+ static constexpr const TSymbolUniqueId mod_Float3_Float3 = TSymbolUniqueId(141);
+ static constexpr const TSymbolUniqueId mod_Float4_Float4 = TSymbolUniqueId(142);
+ static constexpr const TSymbolUniqueId min_Float1_Float1 = TSymbolUniqueId(143);
+ static constexpr const TSymbolUniqueId min_Float2_Float1 = TSymbolUniqueId(144);
+ static constexpr const TSymbolUniqueId min_Float3_Float1 = TSymbolUniqueId(145);
+ static constexpr const TSymbolUniqueId min_Float4_Float1 = TSymbolUniqueId(146);
+ static constexpr const TSymbolUniqueId min_Float2_Float2 = TSymbolUniqueId(147);
+ static constexpr const TSymbolUniqueId min_Float3_Float3 = TSymbolUniqueId(148);
+ static constexpr const TSymbolUniqueId min_Float4_Float4 = TSymbolUniqueId(149);
+ static constexpr const TSymbolUniqueId min_Int1_Int1 = TSymbolUniqueId(150);
+ static constexpr const TSymbolUniqueId min_Int2_Int2 = TSymbolUniqueId(151);
+ static constexpr const TSymbolUniqueId min_Int3_Int3 = TSymbolUniqueId(152);
+ static constexpr const TSymbolUniqueId min_Int4_Int4 = TSymbolUniqueId(153);
+ static constexpr const TSymbolUniqueId min_Int2_Int1 = TSymbolUniqueId(154);
+ static constexpr const TSymbolUniqueId min_Int3_Int1 = TSymbolUniqueId(155);
+ static constexpr const TSymbolUniqueId min_Int4_Int1 = TSymbolUniqueId(156);
+ static constexpr const TSymbolUniqueId min_UInt1_UInt1 = TSymbolUniqueId(157);
+ static constexpr const TSymbolUniqueId pt0D = TSymbolUniqueId(158);
+ static constexpr const TSymbolUniqueId min_UInt2_UInt2 = TSymbolUniqueId(159);
+ static constexpr const TSymbolUniqueId pt1D = TSymbolUniqueId(160);
+ static constexpr const TSymbolUniqueId min_UInt3_UInt3 = TSymbolUniqueId(161);
+ static constexpr const TSymbolUniqueId pt2D = TSymbolUniqueId(162);
+ static constexpr const TSymbolUniqueId min_UInt4_UInt4 = TSymbolUniqueId(163);
+ static constexpr const TSymbolUniqueId pt3D = TSymbolUniqueId(164);
+ static constexpr const TSymbolUniqueId min_UInt2_UInt1 = TSymbolUniqueId(165);
+ static constexpr const TSymbolUniqueId min_UInt3_UInt1 = TSymbolUniqueId(166);
+ static constexpr const TSymbolUniqueId min_UInt4_UInt1 = TSymbolUniqueId(167);
+ static constexpr const TSymbolUniqueId max_Float1_Float1 = TSymbolUniqueId(168);
+ static constexpr const TSymbolUniqueId max_Float2_Float1 = TSymbolUniqueId(169);
+ static constexpr const TSymbolUniqueId max_Float3_Float1 = TSymbolUniqueId(170);
+ static constexpr const TSymbolUniqueId max_Float4_Float1 = TSymbolUniqueId(171);
+ static constexpr const TSymbolUniqueId max_Float2_Float2 = TSymbolUniqueId(172);
+ static constexpr const TSymbolUniqueId max_Float3_Float3 = TSymbolUniqueId(173);
+ static constexpr const TSymbolUniqueId max_Float4_Float4 = TSymbolUniqueId(174);
+ static constexpr const TSymbolUniqueId max_Int1_Int1 = TSymbolUniqueId(175);
+ static constexpr const TSymbolUniqueId max_Int2_Int2 = TSymbolUniqueId(176);
+ static constexpr const TSymbolUniqueId max_Int3_Int3 = TSymbolUniqueId(177);
+ static constexpr const TSymbolUniqueId max_Int4_Int4 = TSymbolUniqueId(178);
+ static constexpr const TSymbolUniqueId max_Int2_Int1 = TSymbolUniqueId(179);
+ static constexpr const TSymbolUniqueId max_Int3_Int1 = TSymbolUniqueId(180);
+ static constexpr const TSymbolUniqueId max_Int4_Int1 = TSymbolUniqueId(181);
+ static constexpr const TSymbolUniqueId max_UInt1_UInt1 = TSymbolUniqueId(182);
+ static constexpr const TSymbolUniqueId max_UInt2_UInt2 = TSymbolUniqueId(183);
+ static constexpr const TSymbolUniqueId max_UInt3_UInt3 = TSymbolUniqueId(184);
+ static constexpr const TSymbolUniqueId max_UInt4_UInt4 = TSymbolUniqueId(185);
+ static constexpr const TSymbolUniqueId max_UInt2_UInt1 = TSymbolUniqueId(186);
+ static constexpr const TSymbolUniqueId max_UInt3_UInt1 = TSymbolUniqueId(187);
+ static constexpr const TSymbolUniqueId max_UInt4_UInt1 = TSymbolUniqueId(188);
+ static constexpr const TSymbolUniqueId clamp_Float1_Float1_Float1 = TSymbolUniqueId(189);
+ static constexpr const TSymbolUniqueId clamp_Float2_Float1_Float1 = TSymbolUniqueId(190);
+ static constexpr const TSymbolUniqueId clamp_Float3_Float1_Float1 = TSymbolUniqueId(191);
+ static constexpr const TSymbolUniqueId clamp_Float4_Float1_Float1 = TSymbolUniqueId(192);
+ static constexpr const TSymbolUniqueId clamp_Float2_Float2_Float2 = TSymbolUniqueId(193);
+ static constexpr const TSymbolUniqueId clamp_Float3_Float3_Float3 = TSymbolUniqueId(194);
+ static constexpr const TSymbolUniqueId clamp_Float4_Float4_Float4 = TSymbolUniqueId(195);
+ static constexpr const TSymbolUniqueId clamp_Int1_Int1_Int1 = TSymbolUniqueId(196);
+ static constexpr const TSymbolUniqueId clamp_Int2_Int1_Int1 = TSymbolUniqueId(197);
+ static constexpr const TSymbolUniqueId clamp_Int3_Int1_Int1 = TSymbolUniqueId(198);
+ static constexpr const TSymbolUniqueId clamp_Int4_Int1_Int1 = TSymbolUniqueId(199);
+ static constexpr const TSymbolUniqueId clamp_Int2_Int2_Int2 = TSymbolUniqueId(200);
+ static constexpr const TSymbolUniqueId clamp_Int3_Int3_Int3 = TSymbolUniqueId(201);
+ static constexpr const TSymbolUniqueId clamp_Int4_Int4_Int4 = TSymbolUniqueId(202);
+ static constexpr const TSymbolUniqueId clamp_UInt1_UInt1_UInt1 = TSymbolUniqueId(203);
+ static constexpr const TSymbolUniqueId clamp_UInt2_UInt1_UInt1 = TSymbolUniqueId(204);
+ static constexpr const TSymbolUniqueId clamp_UInt3_UInt1_UInt1 = TSymbolUniqueId(205);
+ static constexpr const TSymbolUniqueId clamp_UInt4_UInt1_UInt1 = TSymbolUniqueId(206);
+ static constexpr const TSymbolUniqueId clamp_UInt2_UInt2_UInt2 = TSymbolUniqueId(207);
+ static constexpr const TSymbolUniqueId clamp_UInt3_UInt3_UInt3 = TSymbolUniqueId(208);
+ static constexpr const TSymbolUniqueId clamp_UInt4_UInt4_UInt4 = TSymbolUniqueId(209);
+ static constexpr const TSymbolUniqueId mix_Float1_Float1_Float1 = TSymbolUniqueId(210);
+ static constexpr const TSymbolUniqueId mix_Float2_Float2_Float1 = TSymbolUniqueId(211);
+ static constexpr const TSymbolUniqueId mix_Float3_Float3_Float1 = TSymbolUniqueId(212);
+ static constexpr const TSymbolUniqueId mix_Float4_Float4_Float1 = TSymbolUniqueId(213);
+ static constexpr const TSymbolUniqueId mix_Float2_Float2_Float2 = TSymbolUniqueId(214);
+ static constexpr const TSymbolUniqueId mix_Float3_Float3_Float3 = TSymbolUniqueId(215);
+ static constexpr const TSymbolUniqueId mix_Float4_Float4_Float4 = TSymbolUniqueId(216);
+ static constexpr const TSymbolUniqueId mix_Float1_Float1_Bool1 = TSymbolUniqueId(217);
+ static constexpr const TSymbolUniqueId pt0E = TSymbolUniqueId(218);
+ static constexpr const TSymbolUniqueId mix_Float2_Float2_Bool2 = TSymbolUniqueId(219);
+ static constexpr const TSymbolUniqueId pt1E = TSymbolUniqueId(220);
+ static constexpr const TSymbolUniqueId mix_Float3_Float3_Bool3 = TSymbolUniqueId(221);
+ static constexpr const TSymbolUniqueId pt2E = TSymbolUniqueId(222);
+ static constexpr const TSymbolUniqueId mix_Float4_Float4_Bool4 = TSymbolUniqueId(223);
+ static constexpr const TSymbolUniqueId pt3E = TSymbolUniqueId(224);
+ static constexpr const TSymbolUniqueId step_Float1_Float1 = TSymbolUniqueId(225);
+ static constexpr const TSymbolUniqueId step_Float2_Float2 = TSymbolUniqueId(226);
+ static constexpr const TSymbolUniqueId step_Float3_Float3 = TSymbolUniqueId(227);
+ static constexpr const TSymbolUniqueId step_Float4_Float4 = TSymbolUniqueId(228);
+ static constexpr const TSymbolUniqueId step_Float1_Float2 = TSymbolUniqueId(229);
+ static constexpr const TSymbolUniqueId step_Float1_Float3 = TSymbolUniqueId(230);
+ static constexpr const TSymbolUniqueId step_Float1_Float4 = TSymbolUniqueId(231);
+ static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float1 = TSymbolUniqueId(232);
+ static constexpr const TSymbolUniqueId smoothstep_Float2_Float2_Float2 = TSymbolUniqueId(233);
+ static constexpr const TSymbolUniqueId smoothstep_Float3_Float3_Float3 = TSymbolUniqueId(234);
+ static constexpr const TSymbolUniqueId smoothstep_Float4_Float4_Float4 = TSymbolUniqueId(235);
+ static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float2 = TSymbolUniqueId(236);
+ static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float3 = TSymbolUniqueId(237);
+ static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float4 = TSymbolUniqueId(238);
+ static constexpr const TSymbolUniqueId modf_Float1_Float1 = TSymbolUniqueId(239);
+ static constexpr const TSymbolUniqueId pt_o_0B = TSymbolUniqueId(240);
+ static constexpr const TSymbolUniqueId modf_Float2_Float2 = TSymbolUniqueId(241);
+ static constexpr const TSymbolUniqueId pt_o_1B = TSymbolUniqueId(242);
+ static constexpr const TSymbolUniqueId modf_Float3_Float3 = TSymbolUniqueId(243);
+ static constexpr const TSymbolUniqueId pt_o_2B = TSymbolUniqueId(244);
+ static constexpr const TSymbolUniqueId modf_Float4_Float4 = TSymbolUniqueId(245);
+ static constexpr const TSymbolUniqueId pt_o_3B = TSymbolUniqueId(246);
+ static constexpr const TSymbolUniqueId isnan_Float1 = TSymbolUniqueId(247);
+ static constexpr const TSymbolUniqueId isnan_Float2 = TSymbolUniqueId(248);
+ static constexpr const TSymbolUniqueId isnan_Float3 = TSymbolUniqueId(249);
+ static constexpr const TSymbolUniqueId isnan_Float4 = TSymbolUniqueId(250);
+ static constexpr const TSymbolUniqueId isinf_Float1 = TSymbolUniqueId(251);
+ static constexpr const TSymbolUniqueId isinf_Float2 = TSymbolUniqueId(252);
+ static constexpr const TSymbolUniqueId isinf_Float3 = TSymbolUniqueId(253);
+ static constexpr const TSymbolUniqueId isinf_Float4 = TSymbolUniqueId(254);
+ static constexpr const TSymbolUniqueId floatBitsToInt_Float1 = TSymbolUniqueId(255);
+ static constexpr const TSymbolUniqueId floatBitsToInt_Float2 = TSymbolUniqueId(256);
+ static constexpr const TSymbolUniqueId floatBitsToInt_Float3 = TSymbolUniqueId(257);
+ static constexpr const TSymbolUniqueId floatBitsToInt_Float4 = TSymbolUniqueId(258);
+ static constexpr const TSymbolUniqueId floatBitsToUint_Float1 = TSymbolUniqueId(259);
+ static constexpr const TSymbolUniqueId floatBitsToUint_Float2 = TSymbolUniqueId(260);
+ static constexpr const TSymbolUniqueId floatBitsToUint_Float3 = TSymbolUniqueId(261);
+ static constexpr const TSymbolUniqueId floatBitsToUint_Float4 = TSymbolUniqueId(262);
+ static constexpr const TSymbolUniqueId intBitsToFloat_Int1 = TSymbolUniqueId(263);
+ static constexpr const TSymbolUniqueId intBitsToFloat_Int2 = TSymbolUniqueId(264);
+ static constexpr const TSymbolUniqueId intBitsToFloat_Int3 = TSymbolUniqueId(265);
+ static constexpr const TSymbolUniqueId intBitsToFloat_Int4 = TSymbolUniqueId(266);
+ static constexpr const TSymbolUniqueId uintBitsToFloat_UInt1 = TSymbolUniqueId(267);
+ static constexpr const TSymbolUniqueId uintBitsToFloat_UInt2 = TSymbolUniqueId(268);
+ static constexpr const TSymbolUniqueId uintBitsToFloat_UInt3 = TSymbolUniqueId(269);
+ static constexpr const TSymbolUniqueId uintBitsToFloat_UInt4 = TSymbolUniqueId(270);
+ static constexpr const TSymbolUniqueId frexp_Float1_Int1 = TSymbolUniqueId(271);
+ static constexpr const TSymbolUniqueId pt_o_0C = TSymbolUniqueId(272);
+ static constexpr const TSymbolUniqueId frexp_Float2_Int2 = TSymbolUniqueId(273);
+ static constexpr const TSymbolUniqueId pt_o_1C = TSymbolUniqueId(274);
+ static constexpr const TSymbolUniqueId frexp_Float3_Int3 = TSymbolUniqueId(275);
+ static constexpr const TSymbolUniqueId pt_o_2C = TSymbolUniqueId(276);
+ static constexpr const TSymbolUniqueId frexp_Float4_Int4 = TSymbolUniqueId(277);
+ static constexpr const TSymbolUniqueId pt_o_3C = TSymbolUniqueId(278);
+ static constexpr const TSymbolUniqueId ldexp_Float1_Int1 = TSymbolUniqueId(279);
+ static constexpr const TSymbolUniqueId ldexp_Float2_Int2 = TSymbolUniqueId(280);
+ static constexpr const TSymbolUniqueId ldexp_Float3_Int3 = TSymbolUniqueId(281);
+ static constexpr const TSymbolUniqueId ldexp_Float4_Int4 = TSymbolUniqueId(282);
+ static constexpr const TSymbolUniqueId packSnorm2x16_Float2 = TSymbolUniqueId(283);
+ static constexpr const TSymbolUniqueId packUnorm2x16_Float2 = TSymbolUniqueId(284);
+ static constexpr const TSymbolUniqueId packHalf2x16_Float2 = TSymbolUniqueId(285);
+ static constexpr const TSymbolUniqueId unpackSnorm2x16_UInt1 = TSymbolUniqueId(286);
+ static constexpr const TSymbolUniqueId unpackUnorm2x16_UInt1 = TSymbolUniqueId(287);
+ static constexpr const TSymbolUniqueId unpackHalf2x16_UInt1 = TSymbolUniqueId(288);
+ static constexpr const TSymbolUniqueId packUnorm4x8_Float4 = TSymbolUniqueId(289);
+ static constexpr const TSymbolUniqueId packSnorm4x8_Float4 = TSymbolUniqueId(290);
+ static constexpr const TSymbolUniqueId unpackUnorm4x8_UInt1 = TSymbolUniqueId(291);
+ static constexpr const TSymbolUniqueId unpackSnorm4x8_UInt1 = TSymbolUniqueId(292);
+ static constexpr const TSymbolUniqueId length_Float1 = TSymbolUniqueId(293);
+ static constexpr const TSymbolUniqueId length_Float2 = TSymbolUniqueId(294);
+ static constexpr const TSymbolUniqueId length_Float3 = TSymbolUniqueId(295);
+ static constexpr const TSymbolUniqueId length_Float4 = TSymbolUniqueId(296);
+ static constexpr const TSymbolUniqueId distance_Float1_Float1 = TSymbolUniqueId(297);
+ static constexpr const TSymbolUniqueId distance_Float2_Float2 = TSymbolUniqueId(298);
+ static constexpr const TSymbolUniqueId distance_Float3_Float3 = TSymbolUniqueId(299);
+ static constexpr const TSymbolUniqueId distance_Float4_Float4 = TSymbolUniqueId(300);
+ static constexpr const TSymbolUniqueId dot_Float1_Float1 = TSymbolUniqueId(301);
+ static constexpr const TSymbolUniqueId dot_Float2_Float2 = TSymbolUniqueId(302);
+ static constexpr const TSymbolUniqueId dot_Float3_Float3 = TSymbolUniqueId(303);
+ static constexpr const TSymbolUniqueId dot_Float4_Float4 = TSymbolUniqueId(304);
+ static constexpr const TSymbolUniqueId cross_Float3_Float3 = TSymbolUniqueId(305);
+ static constexpr const TSymbolUniqueId normalize_Float1 = TSymbolUniqueId(306);
+ static constexpr const TSymbolUniqueId normalize_Float2 = TSymbolUniqueId(307);
+ static constexpr const TSymbolUniqueId normalize_Float3 = TSymbolUniqueId(308);
+ static constexpr const TSymbolUniqueId normalize_Float4 = TSymbolUniqueId(309);
+ static constexpr const TSymbolUniqueId faceforward_Float1_Float1_Float1 = TSymbolUniqueId(310);
+ static constexpr const TSymbolUniqueId faceforward_Float2_Float2_Float2 = TSymbolUniqueId(311);
+ static constexpr const TSymbolUniqueId faceforward_Float3_Float3_Float3 = TSymbolUniqueId(312);
+ static constexpr const TSymbolUniqueId faceforward_Float4_Float4_Float4 = TSymbolUniqueId(313);
+ static constexpr const TSymbolUniqueId reflect_Float1_Float1 = TSymbolUniqueId(314);
+ static constexpr const TSymbolUniqueId reflect_Float2_Float2 = TSymbolUniqueId(315);
+ static constexpr const TSymbolUniqueId reflect_Float3_Float3 = TSymbolUniqueId(316);
+ static constexpr const TSymbolUniqueId reflect_Float4_Float4 = TSymbolUniqueId(317);
+ static constexpr const TSymbolUniqueId refract_Float1_Float1_Float1 = TSymbolUniqueId(318);
+ static constexpr const TSymbolUniqueId refract_Float2_Float2_Float1 = TSymbolUniqueId(319);
+ static constexpr const TSymbolUniqueId refract_Float3_Float3_Float1 = TSymbolUniqueId(320);
+ static constexpr const TSymbolUniqueId refract_Float4_Float4_Float1 = TSymbolUniqueId(321);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float2x2_Float2x2 = TSymbolUniqueId(322);
+ static constexpr const TSymbolUniqueId pt5B = TSymbolUniqueId(323);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float3x3_Float3x3 = TSymbolUniqueId(324);
+ static constexpr const TSymbolUniqueId ptAB = TSymbolUniqueId(325);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float4x4_Float4x4 = TSymbolUniqueId(326);
+ static constexpr const TSymbolUniqueId ptFB = TSymbolUniqueId(327);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float2x3_Float2x3 = TSymbolUniqueId(328);
+ static constexpr const TSymbolUniqueId pt9B = TSymbolUniqueId(329);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float3x2_Float3x2 = TSymbolUniqueId(330);
+ static constexpr const TSymbolUniqueId pt6B = TSymbolUniqueId(331);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float2x4_Float2x4 = TSymbolUniqueId(332);
+ static constexpr const TSymbolUniqueId ptDB = TSymbolUniqueId(333);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float4x2_Float4x2 = TSymbolUniqueId(334);
+ static constexpr const TSymbolUniqueId pt7B = TSymbolUniqueId(335);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float3x4_Float3x4 = TSymbolUniqueId(336);
+ static constexpr const TSymbolUniqueId ptEB = TSymbolUniqueId(337);
+ static constexpr const TSymbolUniqueId matrixCompMult_Float4x3_Float4x3 = TSymbolUniqueId(338);
+ static constexpr const TSymbolUniqueId ptBB = TSymbolUniqueId(339);
+ static constexpr const TSymbolUniqueId outerProduct_Float2_Float2 = TSymbolUniqueId(340);
+ static constexpr const TSymbolUniqueId outerProduct_Float3_Float3 = TSymbolUniqueId(341);
+ static constexpr const TSymbolUniqueId outerProduct_Float4_Float4 = TSymbolUniqueId(342);
+ static constexpr const TSymbolUniqueId outerProduct_Float3_Float2 = TSymbolUniqueId(343);
+ static constexpr const TSymbolUniqueId outerProduct_Float2_Float3 = TSymbolUniqueId(344);
+ static constexpr const TSymbolUniqueId outerProduct_Float4_Float2 = TSymbolUniqueId(345);
+ static constexpr const TSymbolUniqueId outerProduct_Float2_Float4 = TSymbolUniqueId(346);
+ static constexpr const TSymbolUniqueId outerProduct_Float4_Float3 = TSymbolUniqueId(347);
+ static constexpr const TSymbolUniqueId outerProduct_Float3_Float4 = TSymbolUniqueId(348);
+ static constexpr const TSymbolUniqueId transpose_Float2x2 = TSymbolUniqueId(349);
+ static constexpr const TSymbolUniqueId transpose_Float3x3 = TSymbolUniqueId(350);
+ static constexpr const TSymbolUniqueId transpose_Float4x4 = TSymbolUniqueId(351);
+ static constexpr const TSymbolUniqueId transpose_Float3x2 = TSymbolUniqueId(352);
+ static constexpr const TSymbolUniqueId transpose_Float2x3 = TSymbolUniqueId(353);
+ static constexpr const TSymbolUniqueId transpose_Float4x2 = TSymbolUniqueId(354);
+ static constexpr const TSymbolUniqueId transpose_Float2x4 = TSymbolUniqueId(355);
+ static constexpr const TSymbolUniqueId transpose_Float4x3 = TSymbolUniqueId(356);
+ static constexpr const TSymbolUniqueId transpose_Float3x4 = TSymbolUniqueId(357);
+ static constexpr const TSymbolUniqueId determinant_Float2x2 = TSymbolUniqueId(358);
+ static constexpr const TSymbolUniqueId determinant_Float3x3 = TSymbolUniqueId(359);
+ static constexpr const TSymbolUniqueId determinant_Float4x4 = TSymbolUniqueId(360);
+ static constexpr const TSymbolUniqueId inverse_Float2x2 = TSymbolUniqueId(361);
+ static constexpr const TSymbolUniqueId inverse_Float3x3 = TSymbolUniqueId(362);
+ static constexpr const TSymbolUniqueId inverse_Float4x4 = TSymbolUniqueId(363);
+ static constexpr const TSymbolUniqueId lessThan_Float2_Float2 = TSymbolUniqueId(364);
+ static constexpr const TSymbolUniqueId lessThan_Float3_Float3 = TSymbolUniqueId(365);
+ static constexpr const TSymbolUniqueId lessThan_Float4_Float4 = TSymbolUniqueId(366);
+ static constexpr const TSymbolUniqueId lessThan_Int2_Int2 = TSymbolUniqueId(367);
+ static constexpr const TSymbolUniqueId lessThan_Int3_Int3 = TSymbolUniqueId(368);
+ static constexpr const TSymbolUniqueId lessThan_Int4_Int4 = TSymbolUniqueId(369);
+ static constexpr const TSymbolUniqueId lessThan_UInt2_UInt2 = TSymbolUniqueId(370);
+ static constexpr const TSymbolUniqueId lessThan_UInt3_UInt3 = TSymbolUniqueId(371);
+ static constexpr const TSymbolUniqueId lessThan_UInt4_UInt4 = TSymbolUniqueId(372);
+ static constexpr const TSymbolUniqueId lessThanEqual_Float2_Float2 = TSymbolUniqueId(373);
+ static constexpr const TSymbolUniqueId lessThanEqual_Float3_Float3 = TSymbolUniqueId(374);
+ static constexpr const TSymbolUniqueId lessThanEqual_Float4_Float4 = TSymbolUniqueId(375);
+ static constexpr const TSymbolUniqueId lessThanEqual_Int2_Int2 = TSymbolUniqueId(376);
+ static constexpr const TSymbolUniqueId lessThanEqual_Int3_Int3 = TSymbolUniqueId(377);
+ static constexpr const TSymbolUniqueId lessThanEqual_Int4_Int4 = TSymbolUniqueId(378);
+ static constexpr const TSymbolUniqueId lessThanEqual_UInt2_UInt2 = TSymbolUniqueId(379);
+ static constexpr const TSymbolUniqueId lessThanEqual_UInt3_UInt3 = TSymbolUniqueId(380);
+ static constexpr const TSymbolUniqueId lessThanEqual_UInt4_UInt4 = TSymbolUniqueId(381);
+ static constexpr const TSymbolUniqueId greaterThan_Float2_Float2 = TSymbolUniqueId(382);
+ static constexpr const TSymbolUniqueId greaterThan_Float3_Float3 = TSymbolUniqueId(383);
+ static constexpr const TSymbolUniqueId greaterThan_Float4_Float4 = TSymbolUniqueId(384);
+ static constexpr const TSymbolUniqueId greaterThan_Int2_Int2 = TSymbolUniqueId(385);
+ static constexpr const TSymbolUniqueId greaterThan_Int3_Int3 = TSymbolUniqueId(386);
+ static constexpr const TSymbolUniqueId greaterThan_Int4_Int4 = TSymbolUniqueId(387);
+ static constexpr const TSymbolUniqueId greaterThan_UInt2_UInt2 = TSymbolUniqueId(388);
+ static constexpr const TSymbolUniqueId greaterThan_UInt3_UInt3 = TSymbolUniqueId(389);
+ static constexpr const TSymbolUniqueId greaterThan_UInt4_UInt4 = TSymbolUniqueId(390);
+ static constexpr const TSymbolUniqueId greaterThanEqual_Float2_Float2 = TSymbolUniqueId(391);
+ static constexpr const TSymbolUniqueId greaterThanEqual_Float3_Float3 = TSymbolUniqueId(392);
+ static constexpr const TSymbolUniqueId greaterThanEqual_Float4_Float4 = TSymbolUniqueId(393);
+ static constexpr const TSymbolUniqueId greaterThanEqual_Int2_Int2 = TSymbolUniqueId(394);
+ static constexpr const TSymbolUniqueId greaterThanEqual_Int3_Int3 = TSymbolUniqueId(395);
+ static constexpr const TSymbolUniqueId greaterThanEqual_Int4_Int4 = TSymbolUniqueId(396);
+ static constexpr const TSymbolUniqueId greaterThanEqual_UInt2_UInt2 = TSymbolUniqueId(397);
+ static constexpr const TSymbolUniqueId greaterThanEqual_UInt3_UInt3 = TSymbolUniqueId(398);
+ static constexpr const TSymbolUniqueId greaterThanEqual_UInt4_UInt4 = TSymbolUniqueId(399);
+ static constexpr const TSymbolUniqueId equal_Float2_Float2 = TSymbolUniqueId(400);
+ static constexpr const TSymbolUniqueId equal_Float3_Float3 = TSymbolUniqueId(401);
+ static constexpr const TSymbolUniqueId equal_Float4_Float4 = TSymbolUniqueId(402);
+ static constexpr const TSymbolUniqueId equal_Int2_Int2 = TSymbolUniqueId(403);
+ static constexpr const TSymbolUniqueId equal_Int3_Int3 = TSymbolUniqueId(404);
+ static constexpr const TSymbolUniqueId equal_Int4_Int4 = TSymbolUniqueId(405);
+ static constexpr const TSymbolUniqueId equal_UInt2_UInt2 = TSymbolUniqueId(406);
+ static constexpr const TSymbolUniqueId equal_UInt3_UInt3 = TSymbolUniqueId(407);
+ static constexpr const TSymbolUniqueId equal_UInt4_UInt4 = TSymbolUniqueId(408);
+ static constexpr const TSymbolUniqueId equal_Bool2_Bool2 = TSymbolUniqueId(409);
+ static constexpr const TSymbolUniqueId equal_Bool3_Bool3 = TSymbolUniqueId(410);
+ static constexpr const TSymbolUniqueId equal_Bool4_Bool4 = TSymbolUniqueId(411);
+ static constexpr const TSymbolUniqueId notEqual_Float2_Float2 = TSymbolUniqueId(412);
+ static constexpr const TSymbolUniqueId notEqual_Float3_Float3 = TSymbolUniqueId(413);
+ static constexpr const TSymbolUniqueId notEqual_Float4_Float4 = TSymbolUniqueId(414);
+ static constexpr const TSymbolUniqueId notEqual_Int2_Int2 = TSymbolUniqueId(415);
+ static constexpr const TSymbolUniqueId notEqual_Int3_Int3 = TSymbolUniqueId(416);
+ static constexpr const TSymbolUniqueId notEqual_Int4_Int4 = TSymbolUniqueId(417);
+ static constexpr const TSymbolUniqueId notEqual_UInt2_UInt2 = TSymbolUniqueId(418);
+ static constexpr const TSymbolUniqueId notEqual_UInt3_UInt3 = TSymbolUniqueId(419);
+ static constexpr const TSymbolUniqueId notEqual_UInt4_UInt4 = TSymbolUniqueId(420);
+ static constexpr const TSymbolUniqueId notEqual_Bool2_Bool2 = TSymbolUniqueId(421);
+ static constexpr const TSymbolUniqueId notEqual_Bool3_Bool3 = TSymbolUniqueId(422);
+ static constexpr const TSymbolUniqueId notEqual_Bool4_Bool4 = TSymbolUniqueId(423);
+ static constexpr const TSymbolUniqueId any_Bool2 = TSymbolUniqueId(424);
+ static constexpr const TSymbolUniqueId any_Bool3 = TSymbolUniqueId(425);
+ static constexpr const TSymbolUniqueId any_Bool4 = TSymbolUniqueId(426);
+ static constexpr const TSymbolUniqueId all_Bool2 = TSymbolUniqueId(427);
+ static constexpr const TSymbolUniqueId all_Bool3 = TSymbolUniqueId(428);
+ static constexpr const TSymbolUniqueId all_Bool4 = TSymbolUniqueId(429);
+ static constexpr const TSymbolUniqueId notFunc_Bool2 = TSymbolUniqueId(430);
+ static constexpr const TSymbolUniqueId notFunc_Bool3 = TSymbolUniqueId(431);
+ static constexpr const TSymbolUniqueId notFunc_Bool4 = TSymbolUniqueId(432);
+ static constexpr const TSymbolUniqueId bitfieldExtract_Int1_Int1_Int1 = TSymbolUniqueId(433);
+ static constexpr const TSymbolUniqueId bitfieldExtract_Int2_Int1_Int1 = TSymbolUniqueId(434);
+ static constexpr const TSymbolUniqueId bitfieldExtract_Int3_Int1_Int1 = TSymbolUniqueId(435);
+ static constexpr const TSymbolUniqueId bitfieldExtract_Int4_Int1_Int1 = TSymbolUniqueId(436);
+ static constexpr const TSymbolUniqueId bitfieldExtract_UInt1_Int1_Int1 = TSymbolUniqueId(437);
+ static constexpr const TSymbolUniqueId bitfieldExtract_UInt2_Int1_Int1 = TSymbolUniqueId(438);
+ static constexpr const TSymbolUniqueId bitfieldExtract_UInt3_Int1_Int1 = TSymbolUniqueId(439);
+ static constexpr const TSymbolUniqueId bitfieldExtract_UInt4_Int1_Int1 = TSymbolUniqueId(440);
+ static constexpr const TSymbolUniqueId bitfieldInsert_Int1_Int1_Int1_Int1 =
+ TSymbolUniqueId(441);
+ static constexpr const TSymbolUniqueId bitfieldInsert_Int2_Int2_Int1_Int1 =
+ TSymbolUniqueId(442);
+ static constexpr const TSymbolUniqueId bitfieldInsert_Int3_Int3_Int1_Int1 =
+ TSymbolUniqueId(443);
+ static constexpr const TSymbolUniqueId bitfieldInsert_Int4_Int4_Int1_Int1 =
+ TSymbolUniqueId(444);
+ static constexpr const TSymbolUniqueId bitfieldInsert_UInt1_UInt1_Int1_Int1 =
+ TSymbolUniqueId(445);
+ static constexpr const TSymbolUniqueId bitfieldInsert_UInt2_UInt2_Int1_Int1 =
+ TSymbolUniqueId(446);
+ static constexpr const TSymbolUniqueId bitfieldInsert_UInt3_UInt3_Int1_Int1 =
+ TSymbolUniqueId(447);
+ static constexpr const TSymbolUniqueId bitfieldInsert_UInt4_UInt4_Int1_Int1 =
+ TSymbolUniqueId(448);
+ static constexpr const TSymbolUniqueId bitfieldReverse_Int1 = TSymbolUniqueId(449);
+ static constexpr const TSymbolUniqueId bitfieldReverse_Int2 = TSymbolUniqueId(450);
+ static constexpr const TSymbolUniqueId bitfieldReverse_Int3 = TSymbolUniqueId(451);
+ static constexpr const TSymbolUniqueId bitfieldReverse_Int4 = TSymbolUniqueId(452);
+ static constexpr const TSymbolUniqueId bitfieldReverse_UInt1 = TSymbolUniqueId(453);
+ static constexpr const TSymbolUniqueId bitfieldReverse_UInt2 = TSymbolUniqueId(454);
+ static constexpr const TSymbolUniqueId bitfieldReverse_UInt3 = TSymbolUniqueId(455);
+ static constexpr const TSymbolUniqueId bitfieldReverse_UInt4 = TSymbolUniqueId(456);
+ static constexpr const TSymbolUniqueId bitCount_Int1 = TSymbolUniqueId(457);
+ static constexpr const TSymbolUniqueId bitCount_Int2 = TSymbolUniqueId(458);
+ static constexpr const TSymbolUniqueId bitCount_Int3 = TSymbolUniqueId(459);
+ static constexpr const TSymbolUniqueId bitCount_Int4 = TSymbolUniqueId(460);
+ static constexpr const TSymbolUniqueId bitCount_UInt1 = TSymbolUniqueId(461);
+ static constexpr const TSymbolUniqueId bitCount_UInt2 = TSymbolUniqueId(462);
+ static constexpr const TSymbolUniqueId bitCount_UInt3 = TSymbolUniqueId(463);
+ static constexpr const TSymbolUniqueId bitCount_UInt4 = TSymbolUniqueId(464);
+ static constexpr const TSymbolUniqueId findLSB_Int1 = TSymbolUniqueId(465);
+ static constexpr const TSymbolUniqueId findLSB_Int2 = TSymbolUniqueId(466);
+ static constexpr const TSymbolUniqueId findLSB_Int3 = TSymbolUniqueId(467);
+ static constexpr const TSymbolUniqueId findLSB_Int4 = TSymbolUniqueId(468);
+ static constexpr const TSymbolUniqueId findLSB_UInt1 = TSymbolUniqueId(469);
+ static constexpr const TSymbolUniqueId findLSB_UInt2 = TSymbolUniqueId(470);
+ static constexpr const TSymbolUniqueId findLSB_UInt3 = TSymbolUniqueId(471);
+ static constexpr const TSymbolUniqueId findLSB_UInt4 = TSymbolUniqueId(472);
+ static constexpr const TSymbolUniqueId findMSB_Int1 = TSymbolUniqueId(473);
+ static constexpr const TSymbolUniqueId findMSB_Int2 = TSymbolUniqueId(474);
+ static constexpr const TSymbolUniqueId findMSB_Int3 = TSymbolUniqueId(475);
+ static constexpr const TSymbolUniqueId findMSB_Int4 = TSymbolUniqueId(476);
+ static constexpr const TSymbolUniqueId findMSB_UInt1 = TSymbolUniqueId(477);
+ static constexpr const TSymbolUniqueId findMSB_UInt2 = TSymbolUniqueId(478);
+ static constexpr const TSymbolUniqueId findMSB_UInt3 = TSymbolUniqueId(479);
+ static constexpr const TSymbolUniqueId findMSB_UInt4 = TSymbolUniqueId(480);
+ static constexpr const TSymbolUniqueId uaddCarry_UInt1_UInt1_UInt1 = TSymbolUniqueId(481);
+ static constexpr const TSymbolUniqueId pt_o_0D = TSymbolUniqueId(482);
+ static constexpr const TSymbolUniqueId uaddCarry_UInt2_UInt2_UInt2 = TSymbolUniqueId(483);
+ static constexpr const TSymbolUniqueId pt_o_1D = TSymbolUniqueId(484);
+ static constexpr const TSymbolUniqueId uaddCarry_UInt3_UInt3_UInt3 = TSymbolUniqueId(485);
+ static constexpr const TSymbolUniqueId pt_o_2D = TSymbolUniqueId(486);
+ static constexpr const TSymbolUniqueId uaddCarry_UInt4_UInt4_UInt4 = TSymbolUniqueId(487);
+ static constexpr const TSymbolUniqueId pt_o_3D = TSymbolUniqueId(488);
+ static constexpr const TSymbolUniqueId usubBorrow_UInt1_UInt1_UInt1 = TSymbolUniqueId(489);
+ static constexpr const TSymbolUniqueId usubBorrow_UInt2_UInt2_UInt2 = TSymbolUniqueId(490);
+ static constexpr const TSymbolUniqueId usubBorrow_UInt3_UInt3_UInt3 = TSymbolUniqueId(491);
+ static constexpr const TSymbolUniqueId usubBorrow_UInt4_UInt4_UInt4 = TSymbolUniqueId(492);
+ static constexpr const TSymbolUniqueId umulExtended_UInt1_UInt1_UInt1_UInt1 =
+ TSymbolUniqueId(493);
+ static constexpr const TSymbolUniqueId umulExtended_UInt2_UInt2_UInt2_UInt2 =
+ TSymbolUniqueId(494);
+ static constexpr const TSymbolUniqueId umulExtended_UInt3_UInt3_UInt3_UInt3 =
+ TSymbolUniqueId(495);
+ static constexpr const TSymbolUniqueId umulExtended_UInt4_UInt4_UInt4_UInt4 =
+ TSymbolUniqueId(496);
+ static constexpr const TSymbolUniqueId imulExtended_Int1_Int1_Int1_Int1 = TSymbolUniqueId(497);
+ static constexpr const TSymbolUniqueId imulExtended_Int2_Int2_Int2_Int2 = TSymbolUniqueId(498);
+ static constexpr const TSymbolUniqueId imulExtended_Int3_Int3_Int3_Int3 = TSymbolUniqueId(499);
+ static constexpr const TSymbolUniqueId imulExtended_Int4_Int4_Int4_Int4 = TSymbolUniqueId(500);
+ static constexpr const TSymbolUniqueId texture2D_Sampler2D1_Float2 = TSymbolUniqueId(501);
+ static constexpr const TSymbolUniqueId pt0H = TSymbolUniqueId(502);
+ static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float3 = TSymbolUniqueId(503);
+ static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float4 = TSymbolUniqueId(504);
+ static constexpr const TSymbolUniqueId textureCube_SamplerCube1_Float3 = TSymbolUniqueId(505);
+ static constexpr const TSymbolUniqueId pt0J = TSymbolUniqueId(506);
+ static constexpr const TSymbolUniqueId texture2D_SamplerExternalOES1_Float2 =
+ TSymbolUniqueId(507);
+ static constexpr const TSymbolUniqueId pt0L = TSymbolUniqueId(508);
+ static constexpr const TSymbolUniqueId texture2DProj_SamplerExternalOES1_Float3 =
+ TSymbolUniqueId(509);
+ static constexpr const TSymbolUniqueId texture2DProj_SamplerExternalOES1_Float4 =
+ TSymbolUniqueId(510);
+ static constexpr const TSymbolUniqueId texture2DRect_Sampler2DRect1_Float2 =
+ TSymbolUniqueId(511);
+ static constexpr const TSymbolUniqueId pt0N = TSymbolUniqueId(512);
+ static constexpr const TSymbolUniqueId texture2DRectProj_Sampler2DRect1_Float3 =
+ TSymbolUniqueId(513);
+ static constexpr const TSymbolUniqueId texture2DRectProj_Sampler2DRect1_Float4 =
+ TSymbolUniqueId(514);
+ static constexpr const TSymbolUniqueId texture_Sampler2DRect1_Float2 = TSymbolUniqueId(515);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2DRect1_Float3 = TSymbolUniqueId(516);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2DRect1_Float4 = TSymbolUniqueId(517);
+ static constexpr const TSymbolUniqueId texture2DGradEXT_Sampler2D1_Float2_Float2_Float2 =
+ TSymbolUniqueId(518);
+ static constexpr const TSymbolUniqueId texture2DProjGradEXT_Sampler2D1_Float3_Float2_Float2 =
+ TSymbolUniqueId(519);
+ static constexpr const TSymbolUniqueId texture2DProjGradEXT_Sampler2D1_Float4_Float2_Float2 =
+ TSymbolUniqueId(520);
+ static constexpr const TSymbolUniqueId textureCubeGradEXT_SamplerCube1_Float3_Float3_Float3 =
+ TSymbolUniqueId(521);
+ static constexpr const TSymbolUniqueId texture2D_Sampler2D1_Float2_Float1 =
+ TSymbolUniqueId(522);
+ static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float3_Float1 =
+ TSymbolUniqueId(523);
+ static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float4_Float1 =
+ TSymbolUniqueId(524);
+ static constexpr const TSymbolUniqueId textureCube_SamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(525);
+ static constexpr const TSymbolUniqueId dFdxExt_Float1 = TSymbolUniqueId(526);
+ static constexpr const TSymbolUniqueId dFdxExt_Float2 = TSymbolUniqueId(527);
+ static constexpr const TSymbolUniqueId dFdxExt_Float3 = TSymbolUniqueId(528);
+ static constexpr const TSymbolUniqueId dFdxExt_Float4 = TSymbolUniqueId(529);
+ static constexpr const TSymbolUniqueId dFdyExt_Float1 = TSymbolUniqueId(530);
+ static constexpr const TSymbolUniqueId dFdyExt_Float2 = TSymbolUniqueId(531);
+ static constexpr const TSymbolUniqueId dFdyExt_Float3 = TSymbolUniqueId(532);
+ static constexpr const TSymbolUniqueId dFdyExt_Float4 = TSymbolUniqueId(533);
+ static constexpr const TSymbolUniqueId fwidthExt_Float1 = TSymbolUniqueId(534);
+ static constexpr const TSymbolUniqueId fwidthExt_Float2 = TSymbolUniqueId(535);
+ static constexpr const TSymbolUniqueId fwidthExt_Float3 = TSymbolUniqueId(536);
+ static constexpr const TSymbolUniqueId fwidthExt_Float4 = TSymbolUniqueId(537);
+ static constexpr const TSymbolUniqueId texture2DLodEXT_Sampler2D1_Float2_Float1 =
+ TSymbolUniqueId(538);
+ static constexpr const TSymbolUniqueId texture2DProjLodEXT_Sampler2D1_Float3_Float1 =
+ TSymbolUniqueId(539);
+ static constexpr const TSymbolUniqueId texture2DProjLodEXT_Sampler2D1_Float4_Float1 =
+ TSymbolUniqueId(540);
+ static constexpr const TSymbolUniqueId textureCubeLodEXT_SamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(541);
+ static constexpr const TSymbolUniqueId texture3D_Sampler3D1_Float3 = TSymbolUniqueId(542);
+ static constexpr const TSymbolUniqueId pt0I = TSymbolUniqueId(543);
+ static constexpr const TSymbolUniqueId texture3D_Sampler3D1_Float3_Float1 =
+ TSymbolUniqueId(544);
+ static constexpr const TSymbolUniqueId texture3DProj_Sampler3D1_Float4 = TSymbolUniqueId(545);
+ static constexpr const TSymbolUniqueId texture3DProj_Sampler3D1_Float4_Float1 =
+ TSymbolUniqueId(546);
+ static constexpr const TSymbolUniqueId texture3DLod_Sampler3D1_Float3_Float1 =
+ TSymbolUniqueId(547);
+ static constexpr const TSymbolUniqueId texture3DProjLod_Sampler3D1_Float4_Float1 =
+ TSymbolUniqueId(548);
+ static constexpr const TSymbolUniqueId texture2DLod_Sampler2D1_Float2_Float1 =
+ TSymbolUniqueId(549);
+ static constexpr const TSymbolUniqueId texture2DProjLod_Sampler2D1_Float3_Float1 =
+ TSymbolUniqueId(550);
+ static constexpr const TSymbolUniqueId texture2DProjLod_Sampler2D1_Float4_Float1 =
+ TSymbolUniqueId(551);
+ static constexpr const TSymbolUniqueId textureCubeLod_SamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(552);
+ static constexpr const TSymbolUniqueId texture_Sampler2D1_Float2 = TSymbolUniqueId(553);
+ static constexpr const TSymbolUniqueId texture_ISampler2D1_Float2 = TSymbolUniqueId(554);
+ static constexpr const TSymbolUniqueId pt0Q = TSymbolUniqueId(555);
+ static constexpr const TSymbolUniqueId texture_USampler2D1_Float2 = TSymbolUniqueId(556);
+ static constexpr const TSymbolUniqueId pt0W = TSymbolUniqueId(557);
+ static constexpr const TSymbolUniqueId texture_Sampler3D1_Float3 = TSymbolUniqueId(558);
+ static constexpr const TSymbolUniqueId texture_ISampler3D1_Float3 = TSymbolUniqueId(559);
+ static constexpr const TSymbolUniqueId pt0R = TSymbolUniqueId(560);
+ static constexpr const TSymbolUniqueId texture_USampler3D1_Float3 = TSymbolUniqueId(561);
+ static constexpr const TSymbolUniqueId pt0X = TSymbolUniqueId(562);
+ static constexpr const TSymbolUniqueId texture_SamplerCube1_Float3 = TSymbolUniqueId(563);
+ static constexpr const TSymbolUniqueId texture_ISamplerCube1_Float3 = TSymbolUniqueId(564);
+ static constexpr const TSymbolUniqueId pt0S = TSymbolUniqueId(565);
+ static constexpr const TSymbolUniqueId texture_USamplerCube1_Float3 = TSymbolUniqueId(566);
+ static constexpr const TSymbolUniqueId pt0Y = TSymbolUniqueId(567);
+ static constexpr const TSymbolUniqueId texture_Sampler2DArray1_Float3 = TSymbolUniqueId(568);
+ static constexpr const TSymbolUniqueId pt0K = TSymbolUniqueId(569);
+ static constexpr const TSymbolUniqueId texture_ISampler2DArray1_Float3 = TSymbolUniqueId(570);
+ static constexpr const TSymbolUniqueId pt0T = TSymbolUniqueId(571);
+ static constexpr const TSymbolUniqueId texture_USampler2DArray1_Float3 = TSymbolUniqueId(572);
+ static constexpr const TSymbolUniqueId pt0Z = TSymbolUniqueId(573);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float3 = TSymbolUniqueId(574);
+ static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float3 = TSymbolUniqueId(575);
+ static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float3 = TSymbolUniqueId(576);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float4 = TSymbolUniqueId(577);
+ static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float4 = TSymbolUniqueId(578);
+ static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float4 = TSymbolUniqueId(579);
+ static constexpr const TSymbolUniqueId textureProj_Sampler3D1_Float4 = TSymbolUniqueId(580);
+ static constexpr const TSymbolUniqueId textureProj_ISampler3D1_Float4 = TSymbolUniqueId(581);
+ static constexpr const TSymbolUniqueId textureProj_USampler3D1_Float4 = TSymbolUniqueId(582);
+ static constexpr const TSymbolUniqueId textureLod_Sampler2D1_Float2_Float1 =
+ TSymbolUniqueId(583);
+ static constexpr const TSymbolUniqueId textureLod_ISampler2D1_Float2_Float1 =
+ TSymbolUniqueId(584);
+ static constexpr const TSymbolUniqueId textureLod_USampler2D1_Float2_Float1 =
+ TSymbolUniqueId(585);
+ static constexpr const TSymbolUniqueId textureLod_Sampler3D1_Float3_Float1 =
+ TSymbolUniqueId(586);
+ static constexpr const TSymbolUniqueId textureLod_ISampler3D1_Float3_Float1 =
+ TSymbolUniqueId(587);
+ static constexpr const TSymbolUniqueId textureLod_USampler3D1_Float3_Float1 =
+ TSymbolUniqueId(588);
+ static constexpr const TSymbolUniqueId textureLod_SamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(589);
+ static constexpr const TSymbolUniqueId textureLod_ISamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(590);
+ static constexpr const TSymbolUniqueId textureLod_USamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(591);
+ static constexpr const TSymbolUniqueId textureLod_Sampler2DArray1_Float3_Float1 =
+ TSymbolUniqueId(592);
+ static constexpr const TSymbolUniqueId textureLod_ISampler2DArray1_Float3_Float1 =
+ TSymbolUniqueId(593);
+ static constexpr const TSymbolUniqueId textureLod_USampler2DArray1_Float3_Float1 =
+ TSymbolUniqueId(594);
+ static constexpr const TSymbolUniqueId texture_Sampler2DShadow1_Float3 = TSymbolUniqueId(595);
+ static constexpr const TSymbolUniqueId pt0c = TSymbolUniqueId(596);
+ static constexpr const TSymbolUniqueId texture_SamplerCubeShadow1_Float4 = TSymbolUniqueId(597);
+ static constexpr const TSymbolUniqueId pt0d = TSymbolUniqueId(598);
+ static constexpr const TSymbolUniqueId texture_Sampler2DArrayShadow1_Float4 =
+ TSymbolUniqueId(599);
+ static constexpr const TSymbolUniqueId pt0e = TSymbolUniqueId(600);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2DShadow1_Float4 =
+ TSymbolUniqueId(601);
+ static constexpr const TSymbolUniqueId textureLod_Sampler2DShadow1_Float3_Float1 =
+ TSymbolUniqueId(602);
+ static constexpr const TSymbolUniqueId textureSize_Sampler2D1_Int1 = TSymbolUniqueId(603);
+ static constexpr const TSymbolUniqueId textureSize_ISampler2D1_Int1 = TSymbolUniqueId(604);
+ static constexpr const TSymbolUniqueId textureSize_USampler2D1_Int1 = TSymbolUniqueId(605);
+ static constexpr const TSymbolUniqueId textureSize_Sampler3D1_Int1 = TSymbolUniqueId(606);
+ static constexpr const TSymbolUniqueId textureSize_ISampler3D1_Int1 = TSymbolUniqueId(607);
+ static constexpr const TSymbolUniqueId textureSize_USampler3D1_Int1 = TSymbolUniqueId(608);
+ static constexpr const TSymbolUniqueId textureSize_SamplerCube1_Int1 = TSymbolUniqueId(609);
+ static constexpr const TSymbolUniqueId textureSize_ISamplerCube1_Int1 = TSymbolUniqueId(610);
+ static constexpr const TSymbolUniqueId textureSize_USamplerCube1_Int1 = TSymbolUniqueId(611);
+ static constexpr const TSymbolUniqueId textureSize_Sampler2DArray1_Int1 = TSymbolUniqueId(612);
+ static constexpr const TSymbolUniqueId textureSize_ISampler2DArray1_Int1 = TSymbolUniqueId(613);
+ static constexpr const TSymbolUniqueId textureSize_USampler2DArray1_Int1 = TSymbolUniqueId(614);
+ static constexpr const TSymbolUniqueId textureSize_Sampler2DShadow1_Int1 = TSymbolUniqueId(615);
+ static constexpr const TSymbolUniqueId textureSize_SamplerCubeShadow1_Int1 =
+ TSymbolUniqueId(616);
+ static constexpr const TSymbolUniqueId textureSize_Sampler2DArrayShadow1_Int1 =
+ TSymbolUniqueId(617);
+ static constexpr const TSymbolUniqueId textureProjLod_Sampler2D1_Float3_Float1 =
+ TSymbolUniqueId(618);
+ static constexpr const TSymbolUniqueId textureProjLod_ISampler2D1_Float3_Float1 =
+ TSymbolUniqueId(619);
+ static constexpr const TSymbolUniqueId textureProjLod_USampler2D1_Float3_Float1 =
+ TSymbolUniqueId(620);
+ static constexpr const TSymbolUniqueId textureProjLod_Sampler2D1_Float4_Float1 =
+ TSymbolUniqueId(621);
+ static constexpr const TSymbolUniqueId textureProjLod_ISampler2D1_Float4_Float1 =
+ TSymbolUniqueId(622);
+ static constexpr const TSymbolUniqueId textureProjLod_USampler2D1_Float4_Float1 =
+ TSymbolUniqueId(623);
+ static constexpr const TSymbolUniqueId textureProjLod_Sampler3D1_Float4_Float1 =
+ TSymbolUniqueId(624);
+ static constexpr const TSymbolUniqueId textureProjLod_ISampler3D1_Float4_Float1 =
+ TSymbolUniqueId(625);
+ static constexpr const TSymbolUniqueId textureProjLod_USampler3D1_Float4_Float1 =
+ TSymbolUniqueId(626);
+ static constexpr const TSymbolUniqueId textureProjLod_Sampler2DShadow1_Float4_Float1 =
+ TSymbolUniqueId(627);
+ static constexpr const TSymbolUniqueId texelFetch_Sampler2D1_Int2_Int1 = TSymbolUniqueId(628);
+ static constexpr const TSymbolUniqueId texelFetch_ISampler2D1_Int2_Int1 = TSymbolUniqueId(629);
+ static constexpr const TSymbolUniqueId texelFetch_USampler2D1_Int2_Int1 = TSymbolUniqueId(630);
+ static constexpr const TSymbolUniqueId texelFetch_Sampler3D1_Int3_Int1 = TSymbolUniqueId(631);
+ static constexpr const TSymbolUniqueId texelFetch_ISampler3D1_Int3_Int1 = TSymbolUniqueId(632);
+ static constexpr const TSymbolUniqueId texelFetch_USampler3D1_Int3_Int1 = TSymbolUniqueId(633);
+ static constexpr const TSymbolUniqueId texelFetch_Sampler2DArray1_Int3_Int1 =
+ TSymbolUniqueId(634);
+ static constexpr const TSymbolUniqueId texelFetch_ISampler2DArray1_Int3_Int1 =
+ TSymbolUniqueId(635);
+ static constexpr const TSymbolUniqueId texelFetch_USampler2DArray1_Int3_Int1 =
+ TSymbolUniqueId(636);
+ static constexpr const TSymbolUniqueId textureGrad_Sampler2D1_Float2_Float2_Float2 =
+ TSymbolUniqueId(637);
+ static constexpr const TSymbolUniqueId textureGrad_ISampler2D1_Float2_Float2_Float2 =
+ TSymbolUniqueId(638);
+ static constexpr const TSymbolUniqueId textureGrad_USampler2D1_Float2_Float2_Float2 =
+ TSymbolUniqueId(639);
+ static constexpr const TSymbolUniqueId textureGrad_Sampler3D1_Float3_Float3_Float3 =
+ TSymbolUniqueId(640);
+ static constexpr const TSymbolUniqueId textureGrad_ISampler3D1_Float3_Float3_Float3 =
+ TSymbolUniqueId(641);
+ static constexpr const TSymbolUniqueId textureGrad_USampler3D1_Float3_Float3_Float3 =
+ TSymbolUniqueId(642);
+ static constexpr const TSymbolUniqueId textureGrad_SamplerCube1_Float3_Float3_Float3 =
+ TSymbolUniqueId(643);
+ static constexpr const TSymbolUniqueId textureGrad_ISamplerCube1_Float3_Float3_Float3 =
+ TSymbolUniqueId(644);
+ static constexpr const TSymbolUniqueId textureGrad_USamplerCube1_Float3_Float3_Float3 =
+ TSymbolUniqueId(645);
+ static constexpr const TSymbolUniqueId textureGrad_Sampler2DShadow1_Float3_Float2_Float2 =
+ TSymbolUniqueId(646);
+ static constexpr const TSymbolUniqueId textureGrad_SamplerCubeShadow1_Float4_Float3_Float3 =
+ TSymbolUniqueId(647);
+ static constexpr const TSymbolUniqueId textureGrad_Sampler2DArray1_Float3_Float2_Float2 =
+ TSymbolUniqueId(648);
+ static constexpr const TSymbolUniqueId textureGrad_ISampler2DArray1_Float3_Float2_Float2 =
+ TSymbolUniqueId(649);
+ static constexpr const TSymbolUniqueId textureGrad_USampler2DArray1_Float3_Float2_Float2 =
+ TSymbolUniqueId(650);
+ static constexpr const TSymbolUniqueId textureGrad_Sampler2DArrayShadow1_Float4_Float2_Float2 =
+ TSymbolUniqueId(651);
+ static constexpr const TSymbolUniqueId textureProjGrad_Sampler2D1_Float3_Float2_Float2 =
+ TSymbolUniqueId(652);
+ static constexpr const TSymbolUniqueId textureProjGrad_ISampler2D1_Float3_Float2_Float2 =
+ TSymbolUniqueId(653);
+ static constexpr const TSymbolUniqueId textureProjGrad_USampler2D1_Float3_Float2_Float2 =
+ TSymbolUniqueId(654);
+ static constexpr const TSymbolUniqueId textureProjGrad_Sampler2D1_Float4_Float2_Float2 =
+ TSymbolUniqueId(655);
+ static constexpr const TSymbolUniqueId textureProjGrad_ISampler2D1_Float4_Float2_Float2 =
+ TSymbolUniqueId(656);
+ static constexpr const TSymbolUniqueId textureProjGrad_USampler2D1_Float4_Float2_Float2 =
+ TSymbolUniqueId(657);
+ static constexpr const TSymbolUniqueId textureProjGrad_Sampler3D1_Float4_Float3_Float3 =
+ TSymbolUniqueId(658);
+ static constexpr const TSymbolUniqueId textureProjGrad_ISampler3D1_Float4_Float3_Float3 =
+ TSymbolUniqueId(659);
+ static constexpr const TSymbolUniqueId textureProjGrad_USampler3D1_Float4_Float3_Float3 =
+ TSymbolUniqueId(660);
+ static constexpr const TSymbolUniqueId textureProjGrad_Sampler2DShadow1_Float4_Float2_Float2 =
+ TSymbolUniqueId(661);
+ static constexpr const TSymbolUniqueId textureSize_Sampler2DMS1 = TSymbolUniqueId(662);
+ static constexpr const TSymbolUniqueId pt0O = TSymbolUniqueId(663);
+ static constexpr const TSymbolUniqueId textureSize_ISampler2DMS1 = TSymbolUniqueId(664);
+ static constexpr const TSymbolUniqueId pt0U = TSymbolUniqueId(665);
+ static constexpr const TSymbolUniqueId textureSize_USampler2DMS1 = TSymbolUniqueId(666);
+ static constexpr const TSymbolUniqueId pt0a = TSymbolUniqueId(667);
+ static constexpr const TSymbolUniqueId textureSizeExt_Sampler2DMS1 = TSymbolUniqueId(668);
+ static constexpr const TSymbolUniqueId textureSizeExt_ISampler2DMS1 = TSymbolUniqueId(669);
+ static constexpr const TSymbolUniqueId textureSizeExt_USampler2DMS1 = TSymbolUniqueId(670);
+ static constexpr const TSymbolUniqueId textureSize_Sampler2DMSArray1 = TSymbolUniqueId(671);
+ static constexpr const TSymbolUniqueId pt0P = TSymbolUniqueId(672);
+ static constexpr const TSymbolUniqueId textureSize_ISampler2DMSArray1 = TSymbolUniqueId(673);
+ static constexpr const TSymbolUniqueId pt0V = TSymbolUniqueId(674);
+ static constexpr const TSymbolUniqueId textureSize_USampler2DMSArray1 = TSymbolUniqueId(675);
+ static constexpr const TSymbolUniqueId pt0b = TSymbolUniqueId(676);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler2D1_Float2_Int2 =
+ TSymbolUniqueId(677);
+ static constexpr const TSymbolUniqueId textureOffset_ISampler2D1_Float2_Int2 =
+ TSymbolUniqueId(678);
+ static constexpr const TSymbolUniqueId textureOffset_USampler2D1_Float2_Int2 =
+ TSymbolUniqueId(679);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler3D1_Float3_Int3 =
+ TSymbolUniqueId(680);
+ static constexpr const TSymbolUniqueId textureOffset_ISampler3D1_Float3_Int3 =
+ TSymbolUniqueId(681);
+ static constexpr const TSymbolUniqueId textureOffset_USampler3D1_Float3_Int3 =
+ TSymbolUniqueId(682);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler2DShadow1_Float3_Int2 =
+ TSymbolUniqueId(683);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler2DArray1_Float3_Int2 =
+ TSymbolUniqueId(684);
+ static constexpr const TSymbolUniqueId textureOffset_ISampler2DArray1_Float3_Int2 =
+ TSymbolUniqueId(685);
+ static constexpr const TSymbolUniqueId textureOffset_USampler2DArray1_Float3_Int2 =
+ TSymbolUniqueId(686);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float3_Int2 =
+ TSymbolUniqueId(687);
+ static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float3_Int2 =
+ TSymbolUniqueId(688);
+ static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float3_Int2 =
+ TSymbolUniqueId(689);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float4_Int2 =
+ TSymbolUniqueId(690);
+ static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float4_Int2 =
+ TSymbolUniqueId(691);
+ static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float4_Int2 =
+ TSymbolUniqueId(692);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler3D1_Float4_Int3 =
+ TSymbolUniqueId(693);
+ static constexpr const TSymbolUniqueId textureProjOffset_ISampler3D1_Float4_Int3 =
+ TSymbolUniqueId(694);
+ static constexpr const TSymbolUniqueId textureProjOffset_USampler3D1_Float4_Int3 =
+ TSymbolUniqueId(695);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler2DShadow1_Float4_Int2 =
+ TSymbolUniqueId(696);
+ static constexpr const TSymbolUniqueId textureLodOffset_Sampler2D1_Float2_Float1_Int2 =
+ TSymbolUniqueId(697);
+ static constexpr const TSymbolUniqueId textureLodOffset_ISampler2D1_Float2_Float1_Int2 =
+ TSymbolUniqueId(698);
+ static constexpr const TSymbolUniqueId textureLodOffset_USampler2D1_Float2_Float1_Int2 =
+ TSymbolUniqueId(699);
+ static constexpr const TSymbolUniqueId textureLodOffset_Sampler3D1_Float3_Float1_Int3 =
+ TSymbolUniqueId(700);
+ static constexpr const TSymbolUniqueId textureLodOffset_ISampler3D1_Float3_Float1_Int3 =
+ TSymbolUniqueId(701);
+ static constexpr const TSymbolUniqueId textureLodOffset_USampler3D1_Float3_Float1_Int3 =
+ TSymbolUniqueId(702);
+ static constexpr const TSymbolUniqueId textureLodOffset_Sampler2DShadow1_Float3_Float1_Int2 =
+ TSymbolUniqueId(703);
+ static constexpr const TSymbolUniqueId textureLodOffset_Sampler2DArray1_Float3_Float1_Int2 =
+ TSymbolUniqueId(704);
+ static constexpr const TSymbolUniqueId textureLodOffset_ISampler2DArray1_Float3_Float1_Int2 =
+ TSymbolUniqueId(705);
+ static constexpr const TSymbolUniqueId textureLodOffset_USampler2DArray1_Float3_Float1_Int2 =
+ TSymbolUniqueId(706);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_Sampler2D1_Float3_Float1_Int2 =
+ TSymbolUniqueId(707);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_ISampler2D1_Float3_Float1_Int2 =
+ TSymbolUniqueId(708);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_USampler2D1_Float3_Float1_Int2 =
+ TSymbolUniqueId(709);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_Sampler2D1_Float4_Float1_Int2 =
+ TSymbolUniqueId(710);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_ISampler2D1_Float4_Float1_Int2 =
+ TSymbolUniqueId(711);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_USampler2D1_Float4_Float1_Int2 =
+ TSymbolUniqueId(712);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_Sampler3D1_Float4_Float1_Int3 =
+ TSymbolUniqueId(713);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_ISampler3D1_Float4_Float1_Int3 =
+ TSymbolUniqueId(714);
+ static constexpr const TSymbolUniqueId textureProjLodOffset_USampler3D1_Float4_Float1_Int3 =
+ TSymbolUniqueId(715);
+ static constexpr const TSymbolUniqueId
+ textureProjLodOffset_Sampler2DShadow1_Float4_Float1_Int2 = TSymbolUniqueId(716);
+ static constexpr const TSymbolUniqueId texelFetchOffset_Sampler2D1_Int2_Int1_Int2 =
+ TSymbolUniqueId(717);
+ static constexpr const TSymbolUniqueId texelFetchOffset_ISampler2D1_Int2_Int1_Int2 =
+ TSymbolUniqueId(718);
+ static constexpr const TSymbolUniqueId texelFetchOffset_USampler2D1_Int2_Int1_Int2 =
+ TSymbolUniqueId(719);
+ static constexpr const TSymbolUniqueId texelFetchOffset_Sampler3D1_Int3_Int1_Int3 =
+ TSymbolUniqueId(720);
+ static constexpr const TSymbolUniqueId texelFetchOffset_ISampler3D1_Int3_Int1_Int3 =
+ TSymbolUniqueId(721);
+ static constexpr const TSymbolUniqueId texelFetchOffset_USampler3D1_Int3_Int1_Int3 =
+ TSymbolUniqueId(722);
+ static constexpr const TSymbolUniqueId texelFetchOffset_Sampler2DArray1_Int3_Int1_Int2 =
+ TSymbolUniqueId(723);
+ static constexpr const TSymbolUniqueId texelFetchOffset_ISampler2DArray1_Int3_Int1_Int2 =
+ TSymbolUniqueId(724);
+ static constexpr const TSymbolUniqueId texelFetchOffset_USampler2DArray1_Int3_Int1_Int2 =
+ TSymbolUniqueId(725);
+ static constexpr const TSymbolUniqueId textureGradOffset_Sampler2D1_Float2_Float2_Float2_Int2 =
+ TSymbolUniqueId(726);
+ static constexpr const TSymbolUniqueId textureGradOffset_ISampler2D1_Float2_Float2_Float2_Int2 =
+ TSymbolUniqueId(727);
+ static constexpr const TSymbolUniqueId textureGradOffset_USampler2D1_Float2_Float2_Float2_Int2 =
+ TSymbolUniqueId(728);
+ static constexpr const TSymbolUniqueId textureGradOffset_Sampler3D1_Float3_Float3_Float3_Int3 =
+ TSymbolUniqueId(729);
+ static constexpr const TSymbolUniqueId textureGradOffset_ISampler3D1_Float3_Float3_Float3_Int3 =
+ TSymbolUniqueId(730);
+ static constexpr const TSymbolUniqueId textureGradOffset_USampler3D1_Float3_Float3_Float3_Int3 =
+ TSymbolUniqueId(731);
+ static constexpr const TSymbolUniqueId
+ textureGradOffset_Sampler2DShadow1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(732);
+ static constexpr const TSymbolUniqueId
+ textureGradOffset_Sampler2DArray1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(733);
+ static constexpr const TSymbolUniqueId
+ textureGradOffset_ISampler2DArray1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(734);
+ static constexpr const TSymbolUniqueId
+ textureGradOffset_USampler2DArray1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(735);
+ static constexpr const TSymbolUniqueId
+ textureGradOffset_Sampler2DArrayShadow1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(736);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_Sampler2D1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(737);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_ISampler2D1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(738);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_USampler2D1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(739);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_Sampler2D1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(740);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_ISampler2D1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(741);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_USampler2D1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(742);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_Sampler3D1_Float4_Float3_Float3_Int3 = TSymbolUniqueId(743);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_ISampler3D1_Float4_Float3_Float3_Int3 = TSymbolUniqueId(744);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_USampler3D1_Float4_Float3_Float3_Int3 = TSymbolUniqueId(745);
+ static constexpr const TSymbolUniqueId
+ textureProjGradOffset_Sampler2DShadow1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(746);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler2D1_Float2_Int2_Float1 =
+ TSymbolUniqueId(747);
+ static constexpr const TSymbolUniqueId textureOffset_ISampler2D1_Float2_Int2_Float1 =
+ TSymbolUniqueId(748);
+ static constexpr const TSymbolUniqueId textureOffset_USampler2D1_Float2_Int2_Float1 =
+ TSymbolUniqueId(749);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler3D1_Float3_Int3_Float1 =
+ TSymbolUniqueId(750);
+ static constexpr const TSymbolUniqueId textureOffset_ISampler3D1_Float3_Int3_Float1 =
+ TSymbolUniqueId(751);
+ static constexpr const TSymbolUniqueId textureOffset_USampler3D1_Float3_Int3_Float1 =
+ TSymbolUniqueId(752);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler2DShadow1_Float3_Int2_Float1 =
+ TSymbolUniqueId(753);
+ static constexpr const TSymbolUniqueId textureOffset_Sampler2DArray1_Float3_Int2_Float1 =
+ TSymbolUniqueId(754);
+ static constexpr const TSymbolUniqueId textureOffset_ISampler2DArray1_Float3_Int2_Float1 =
+ TSymbolUniqueId(755);
+ static constexpr const TSymbolUniqueId textureOffset_USampler2DArray1_Float3_Int2_Float1 =
+ TSymbolUniqueId(756);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float3_Int2_Float1 =
+ TSymbolUniqueId(757);
+ static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float3_Int2_Float1 =
+ TSymbolUniqueId(758);
+ static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float3_Int2_Float1 =
+ TSymbolUniqueId(759);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float4_Int2_Float1 =
+ TSymbolUniqueId(760);
+ static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float4_Int2_Float1 =
+ TSymbolUniqueId(761);
+ static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float4_Int2_Float1 =
+ TSymbolUniqueId(762);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler3D1_Float4_Int3_Float1 =
+ TSymbolUniqueId(763);
+ static constexpr const TSymbolUniqueId textureProjOffset_ISampler3D1_Float4_Int3_Float1 =
+ TSymbolUniqueId(764);
+ static constexpr const TSymbolUniqueId textureProjOffset_USampler3D1_Float4_Int3_Float1 =
+ TSymbolUniqueId(765);
+ static constexpr const TSymbolUniqueId textureProjOffset_Sampler2DShadow1_Float4_Int2_Float1 =
+ TSymbolUniqueId(766);
+ static constexpr const TSymbolUniqueId texture_SamplerExternalOES1_Float2 =
+ TSymbolUniqueId(767);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float3 =
+ TSymbolUniqueId(768);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float4 =
+ TSymbolUniqueId(769);
+ static constexpr const TSymbolUniqueId textureSize_SamplerExternalOES1_Int1 =
+ TSymbolUniqueId(770);
+ static constexpr const TSymbolUniqueId texelFetch_SamplerExternalOES1_Int2_Int1 =
+ TSymbolUniqueId(771);
+ static constexpr const TSymbolUniqueId texture_SamplerExternal2DY2YEXT1_Float2 =
+ TSymbolUniqueId(772);
+ static constexpr const TSymbolUniqueId pt0M = TSymbolUniqueId(773);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float3 =
+ TSymbolUniqueId(774);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float4 =
+ TSymbolUniqueId(775);
+ static constexpr const TSymbolUniqueId rgb_2_yuv_Float3_YuvCscStandardEXT1 =
+ TSymbolUniqueId(776);
+ static constexpr const TSymbolUniqueId pt0G = TSymbolUniqueId(777);
+ static constexpr const TSymbolUniqueId yuv_2_rgb_Float3_YuvCscStandardEXT1 =
+ TSymbolUniqueId(778);
+ static constexpr const TSymbolUniqueId textureSize_SamplerExternal2DY2YEXT1_Int1 =
+ TSymbolUniqueId(779);
+ static constexpr const TSymbolUniqueId texelFetch_SamplerExternal2DY2YEXT1_Int2_Int1 =
+ TSymbolUniqueId(780);
+ static constexpr const TSymbolUniqueId texture_Sampler2D1_Float2_Float1 = TSymbolUniqueId(781);
+ static constexpr const TSymbolUniqueId texture_ISampler2D1_Float2_Float1 = TSymbolUniqueId(782);
+ static constexpr const TSymbolUniqueId texture_USampler2D1_Float2_Float1 = TSymbolUniqueId(783);
+ static constexpr const TSymbolUniqueId texture_Sampler3D1_Float3_Float1 = TSymbolUniqueId(784);
+ static constexpr const TSymbolUniqueId texture_ISampler3D1_Float3_Float1 = TSymbolUniqueId(785);
+ static constexpr const TSymbolUniqueId texture_USampler3D1_Float3_Float1 = TSymbolUniqueId(786);
+ static constexpr const TSymbolUniqueId texture_SamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(787);
+ static constexpr const TSymbolUniqueId texture_ISamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(788);
+ static constexpr const TSymbolUniqueId texture_USamplerCube1_Float3_Float1 =
+ TSymbolUniqueId(789);
+ static constexpr const TSymbolUniqueId texture_Sampler2DArray1_Float3_Float1 =
+ TSymbolUniqueId(790);
+ static constexpr const TSymbolUniqueId texture_ISampler2DArray1_Float3_Float1 =
+ TSymbolUniqueId(791);
+ static constexpr const TSymbolUniqueId texture_USampler2DArray1_Float3_Float1 =
+ TSymbolUniqueId(792);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float3_Float1 =
+ TSymbolUniqueId(793);
+ static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float3_Float1 =
+ TSymbolUniqueId(794);
+ static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float3_Float1 =
+ TSymbolUniqueId(795);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float4_Float1 =
+ TSymbolUniqueId(796);
+ static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float4_Float1 =
+ TSymbolUniqueId(797);
+ static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float4_Float1 =
+ TSymbolUniqueId(798);
+ static constexpr const TSymbolUniqueId textureProj_Sampler3D1_Float4_Float1 =
+ TSymbolUniqueId(799);
+ static constexpr const TSymbolUniqueId textureProj_ISampler3D1_Float4_Float1 =
+ TSymbolUniqueId(800);
+ static constexpr const TSymbolUniqueId textureProj_USampler3D1_Float4_Float1 =
+ TSymbolUniqueId(801);
+ static constexpr const TSymbolUniqueId texture_Sampler2DShadow1_Float3_Float1 =
+ TSymbolUniqueId(802);
+ static constexpr const TSymbolUniqueId texture_SamplerCubeShadow1_Float4_Float1 =
+ TSymbolUniqueId(803);
+ static constexpr const TSymbolUniqueId textureProj_Sampler2DShadow1_Float4_Float1 =
+ TSymbolUniqueId(804);
+ static constexpr const TSymbolUniqueId texture_SamplerExternalOES1_Float2_Float1 =
+ TSymbolUniqueId(805);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float3_Float1 =
+ TSymbolUniqueId(806);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float4_Float1 =
+ TSymbolUniqueId(807);
+ static constexpr const TSymbolUniqueId texture_SamplerExternal2DY2YEXT1_Float2_Float1 =
+ TSymbolUniqueId(808);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float3_Float1 =
+ TSymbolUniqueId(809);
+ static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float4_Float1 =
+ TSymbolUniqueId(810);
+ static constexpr const TSymbolUniqueId texelFetch_Sampler2DMS1_Int2_Int1 = TSymbolUniqueId(811);
+ static constexpr const TSymbolUniqueId texelFetch_ISampler2DMS1_Int2_Int1 =
+ TSymbolUniqueId(812);
+ static constexpr const TSymbolUniqueId texelFetch_USampler2DMS1_Int2_Int1 =
+ TSymbolUniqueId(813);
+ static constexpr const TSymbolUniqueId texelFetchExt_Sampler2DMS1_Int2_Int1 =
+ TSymbolUniqueId(814);
+ static constexpr const TSymbolUniqueId texelFetchExt_ISampler2DMS1_Int2_Int1 =
+ TSymbolUniqueId(815);
+ static constexpr const TSymbolUniqueId texelFetchExt_USampler2DMS1_Int2_Int1 =
+ TSymbolUniqueId(816);
+ static constexpr const TSymbolUniqueId texelFetch_Sampler2DMSArray1_Int3_Int1 =
+ TSymbolUniqueId(817);
+ static constexpr const TSymbolUniqueId texelFetch_ISampler2DMSArray1_Int3_Int1 =
+ TSymbolUniqueId(818);
+ static constexpr const TSymbolUniqueId texelFetch_USampler2DMSArray1_Int3_Int1 =
+ TSymbolUniqueId(819);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2D1_Float2 = TSymbolUniqueId(820);
+ static constexpr const TSymbolUniqueId textureGather_ISampler2D1_Float2 = TSymbolUniqueId(821);
+ static constexpr const TSymbolUniqueId textureGather_USampler2D1_Float2 = TSymbolUniqueId(822);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2D1_Float2_Int1 =
+ TSymbolUniqueId(823);
+ static constexpr const TSymbolUniqueId textureGather_ISampler2D1_Float2_Int1 =
+ TSymbolUniqueId(824);
+ static constexpr const TSymbolUniqueId textureGather_USampler2D1_Float2_Int1 =
+ TSymbolUniqueId(825);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2DArray1_Float3 =
+ TSymbolUniqueId(826);
+ static constexpr const TSymbolUniqueId textureGather_ISampler2DArray1_Float3 =
+ TSymbolUniqueId(827);
+ static constexpr const TSymbolUniqueId textureGather_USampler2DArray1_Float3 =
+ TSymbolUniqueId(828);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2DArray1_Float3_Int1 =
+ TSymbolUniqueId(829);
+ static constexpr const TSymbolUniqueId textureGather_ISampler2DArray1_Float3_Int1 =
+ TSymbolUniqueId(830);
+ static constexpr const TSymbolUniqueId textureGather_USampler2DArray1_Float3_Int1 =
+ TSymbolUniqueId(831);
+ static constexpr const TSymbolUniqueId textureGather_SamplerCube1_Float3 = TSymbolUniqueId(832);
+ static constexpr const TSymbolUniqueId textureGather_ISamplerCube1_Float3 =
+ TSymbolUniqueId(833);
+ static constexpr const TSymbolUniqueId textureGather_USamplerCube1_Float3 =
+ TSymbolUniqueId(834);
+ static constexpr const TSymbolUniqueId textureGather_SamplerCube1_Float3_Int1 =
+ TSymbolUniqueId(835);
+ static constexpr const TSymbolUniqueId textureGather_ISamplerCube1_Float3_Int1 =
+ TSymbolUniqueId(836);
+ static constexpr const TSymbolUniqueId textureGather_USamplerCube1_Float3_Int1 =
+ TSymbolUniqueId(837);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2DShadow1_Float2 =
+ TSymbolUniqueId(838);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2DShadow1_Float2_Float1 =
+ TSymbolUniqueId(839);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2DArrayShadow1_Float3 =
+ TSymbolUniqueId(840);
+ static constexpr const TSymbolUniqueId textureGather_Sampler2DArrayShadow1_Float3_Float1 =
+ TSymbolUniqueId(841);
+ static constexpr const TSymbolUniqueId textureGather_SamplerCubeShadow1_Float3 =
+ TSymbolUniqueId(842);
+ static constexpr const TSymbolUniqueId textureGather_SamplerCubeShadow1_Float3_Float1 =
+ TSymbolUniqueId(843);
+ static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2D1_Float2_Int2 =
+ TSymbolUniqueId(844);
+ static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2D1_Float2_Int2 =
+ TSymbolUniqueId(845);
+ static constexpr const TSymbolUniqueId textureGatherOffset_USampler2D1_Float2_Int2 =
+ TSymbolUniqueId(846);
+ static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2D1_Float2_Int2_Int1 =
+ TSymbolUniqueId(847);
+ static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2D1_Float2_Int2_Int1 =
+ TSymbolUniqueId(848);
+ static constexpr const TSymbolUniqueId textureGatherOffset_USampler2D1_Float2_Int2_Int1 =
+ TSymbolUniqueId(849);
+ static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2DArray1_Float3_Int2 =
+ TSymbolUniqueId(850);
+ static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2DArray1_Float3_Int2 =
+ TSymbolUniqueId(851);
+ static constexpr const TSymbolUniqueId textureGatherOffset_USampler2DArray1_Float3_Int2 =
+ TSymbolUniqueId(852);
+ static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2DArray1_Float3_Int2_Int1 =
+ TSymbolUniqueId(853);
+ static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2DArray1_Float3_Int2_Int1 =
+ TSymbolUniqueId(854);
+ static constexpr const TSymbolUniqueId textureGatherOffset_USampler2DArray1_Float3_Int2_Int1 =
+ TSymbolUniqueId(855);
+ static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2DShadow1_Float2_Float1_Int2 =
+ TSymbolUniqueId(856);
+ static constexpr const TSymbolUniqueId
+ textureGatherOffset_Sampler2DArrayShadow1_Float3_Float1_Int2 = TSymbolUniqueId(857);
+ static constexpr const TSymbolUniqueId dFdx_Float1 = TSymbolUniqueId(858);
+ static constexpr const TSymbolUniqueId dFdx_Float2 = TSymbolUniqueId(859);
+ static constexpr const TSymbolUniqueId dFdx_Float3 = TSymbolUniqueId(860);
+ static constexpr const TSymbolUniqueId dFdx_Float4 = TSymbolUniqueId(861);
+ static constexpr const TSymbolUniqueId dFdy_Float1 = TSymbolUniqueId(862);
+ static constexpr const TSymbolUniqueId dFdy_Float2 = TSymbolUniqueId(863);
+ static constexpr const TSymbolUniqueId dFdy_Float3 = TSymbolUniqueId(864);
+ static constexpr const TSymbolUniqueId dFdy_Float4 = TSymbolUniqueId(865);
+ static constexpr const TSymbolUniqueId fwidth_Float1 = TSymbolUniqueId(866);
+ static constexpr const TSymbolUniqueId fwidth_Float2 = TSymbolUniqueId(867);
+ static constexpr const TSymbolUniqueId fwidth_Float3 = TSymbolUniqueId(868);
+ static constexpr const TSymbolUniqueId fwidth_Float4 = TSymbolUniqueId(869);
+ static constexpr const TSymbolUniqueId atomicCounter_AtomicCounter1 = TSymbolUniqueId(870);
+ static constexpr const TSymbolUniqueId pt0F = TSymbolUniqueId(871);
+ static constexpr const TSymbolUniqueId atomicCounterIncrement_AtomicCounter1 =
+ TSymbolUniqueId(872);
+ static constexpr const TSymbolUniqueId atomicCounterDecrement_AtomicCounter1 =
+ TSymbolUniqueId(873);
+ static constexpr const TSymbolUniqueId atomicAdd_UInt1_UInt1 = TSymbolUniqueId(874);
+ static constexpr const TSymbolUniqueId pt_io_0D = TSymbolUniqueId(875);
+ static constexpr const TSymbolUniqueId atomicAdd_Int1_Int1 = TSymbolUniqueId(876);
+ static constexpr const TSymbolUniqueId pt_io_0C = TSymbolUniqueId(877);
+ static constexpr const TSymbolUniqueId atomicMin_UInt1_UInt1 = TSymbolUniqueId(878);
+ static constexpr const TSymbolUniqueId atomicMin_Int1_Int1 = TSymbolUniqueId(879);
+ static constexpr const TSymbolUniqueId atomicMax_UInt1_UInt1 = TSymbolUniqueId(880);
+ static constexpr const TSymbolUniqueId atomicMax_Int1_Int1 = TSymbolUniqueId(881);
+ static constexpr const TSymbolUniqueId atomicAnd_UInt1_UInt1 = TSymbolUniqueId(882);
+ static constexpr const TSymbolUniqueId atomicAnd_Int1_Int1 = TSymbolUniqueId(883);
+ static constexpr const TSymbolUniqueId atomicOr_UInt1_UInt1 = TSymbolUniqueId(884);
+ static constexpr const TSymbolUniqueId atomicOr_Int1_Int1 = TSymbolUniqueId(885);
+ static constexpr const TSymbolUniqueId atomicXor_UInt1_UInt1 = TSymbolUniqueId(886);
+ static constexpr const TSymbolUniqueId atomicXor_Int1_Int1 = TSymbolUniqueId(887);
+ static constexpr const TSymbolUniqueId atomicExchange_UInt1_UInt1 = TSymbolUniqueId(888);
+ static constexpr const TSymbolUniqueId atomicExchange_Int1_Int1 = TSymbolUniqueId(889);
+ static constexpr const TSymbolUniqueId atomicCompSwap_UInt1_UInt1_UInt1 = TSymbolUniqueId(890);
+ static constexpr const TSymbolUniqueId atomicCompSwap_Int1_Int1_Int1 = TSymbolUniqueId(891);
+ static constexpr const TSymbolUniqueId imageSize_Image2D1 = TSymbolUniqueId(892);
+ static constexpr const TSymbolUniqueId pt0f = TSymbolUniqueId(893);
+ static constexpr const TSymbolUniqueId imageSize_IImage2D1 = TSymbolUniqueId(894);
+ static constexpr const TSymbolUniqueId pt0g = TSymbolUniqueId(895);
+ static constexpr const TSymbolUniqueId imageSize_UImage2D1 = TSymbolUniqueId(896);
+ static constexpr const TSymbolUniqueId pt0h = TSymbolUniqueId(897);
+ static constexpr const TSymbolUniqueId imageSize_Image3D1 = TSymbolUniqueId(898);
+ static constexpr const TSymbolUniqueId pt0i = TSymbolUniqueId(899);
+ static constexpr const TSymbolUniqueId imageSize_IImage3D1 = TSymbolUniqueId(900);
+ static constexpr const TSymbolUniqueId pt0j = TSymbolUniqueId(901);
+ static constexpr const TSymbolUniqueId imageSize_UImage3D1 = TSymbolUniqueId(902);
+ static constexpr const TSymbolUniqueId pt0k = TSymbolUniqueId(903);
+ static constexpr const TSymbolUniqueId imageSize_Image2DArray1 = TSymbolUniqueId(904);
+ static constexpr const TSymbolUniqueId pt0l = TSymbolUniqueId(905);
+ static constexpr const TSymbolUniqueId imageSize_IImage2DArray1 = TSymbolUniqueId(906);
+ static constexpr const TSymbolUniqueId pt0m = TSymbolUniqueId(907);
+ static constexpr const TSymbolUniqueId imageSize_UImage2DArray1 = TSymbolUniqueId(908);
+ static constexpr const TSymbolUniqueId pt0n = TSymbolUniqueId(909);
+ static constexpr const TSymbolUniqueId imageSize_ImageCube1 = TSymbolUniqueId(910);
+ static constexpr const TSymbolUniqueId pt0o = TSymbolUniqueId(911);
+ static constexpr const TSymbolUniqueId imageSize_IImageCube1 = TSymbolUniqueId(912);
+ static constexpr const TSymbolUniqueId pt0p = TSymbolUniqueId(913);
+ static constexpr const TSymbolUniqueId imageSize_UImageCube1 = TSymbolUniqueId(914);
+ static constexpr const TSymbolUniqueId pt0q = TSymbolUniqueId(915);
+ static constexpr const TSymbolUniqueId imageLoad_Image2D1_Int2 = TSymbolUniqueId(916);
+ static constexpr const TSymbolUniqueId imageLoad_IImage2D1_Int2 = TSymbolUniqueId(917);
+ static constexpr const TSymbolUniqueId imageLoad_UImage2D1_Int2 = TSymbolUniqueId(918);
+ static constexpr const TSymbolUniqueId imageLoad_Image3D1_Int3 = TSymbolUniqueId(919);
+ static constexpr const TSymbolUniqueId imageLoad_IImage3D1_Int3 = TSymbolUniqueId(920);
+ static constexpr const TSymbolUniqueId imageLoad_UImage3D1_Int3 = TSymbolUniqueId(921);
+ static constexpr const TSymbolUniqueId imageLoad_Image2DArray1_Int3 = TSymbolUniqueId(922);
+ static constexpr const TSymbolUniqueId imageLoad_IImage2DArray1_Int3 = TSymbolUniqueId(923);
+ static constexpr const TSymbolUniqueId imageLoad_UImage2DArray1_Int3 = TSymbolUniqueId(924);
+ static constexpr const TSymbolUniqueId imageLoad_ImageCube1_Int3 = TSymbolUniqueId(925);
+ static constexpr const TSymbolUniqueId imageLoad_IImageCube1_Int3 = TSymbolUniqueId(926);
+ static constexpr const TSymbolUniqueId imageLoad_UImageCube1_Int3 = TSymbolUniqueId(927);
+ static constexpr const TSymbolUniqueId imageStore_Image2D1_Int2_Float4 = TSymbolUniqueId(928);
+ static constexpr const TSymbolUniqueId imageStore_IImage2D1_Int2_Int4 = TSymbolUniqueId(929);
+ static constexpr const TSymbolUniqueId imageStore_UImage2D1_Int2_UInt4 = TSymbolUniqueId(930);
+ static constexpr const TSymbolUniqueId imageStore_Image3D1_Int3_Float4 = TSymbolUniqueId(931);
+ static constexpr const TSymbolUniqueId imageStore_IImage3D1_Int3_Int4 = TSymbolUniqueId(932);
+ static constexpr const TSymbolUniqueId imageStore_UImage3D1_Int3_UInt4 = TSymbolUniqueId(933);
+ static constexpr const TSymbolUniqueId imageStore_Image2DArray1_Int3_Float4 =
+ TSymbolUniqueId(934);
+ static constexpr const TSymbolUniqueId imageStore_IImage2DArray1_Int3_Int4 =
+ TSymbolUniqueId(935);
+ static constexpr const TSymbolUniqueId imageStore_UImage2DArray1_Int3_UInt4 =
+ TSymbolUniqueId(936);
+ static constexpr const TSymbolUniqueId imageStore_ImageCube1_Int3_Float4 = TSymbolUniqueId(937);
+ static constexpr const TSymbolUniqueId imageStore_IImageCube1_Int3_Int4 = TSymbolUniqueId(938);
+ static constexpr const TSymbolUniqueId imageStore_UImageCube1_Int3_UInt4 = TSymbolUniqueId(939);
+ static constexpr const TSymbolUniqueId memoryBarrier = TSymbolUniqueId(940);
+ static constexpr const TSymbolUniqueId memoryBarrierAtomicCounter = TSymbolUniqueId(941);
+ static constexpr const TSymbolUniqueId memoryBarrierBuffer = TSymbolUniqueId(942);
+ static constexpr const TSymbolUniqueId memoryBarrierImage = TSymbolUniqueId(943);
+ static constexpr const TSymbolUniqueId barrier = TSymbolUniqueId(944);
+ static constexpr const TSymbolUniqueId memoryBarrierShared = TSymbolUniqueId(945);
+ static constexpr const TSymbolUniqueId groupMemoryBarrier = TSymbolUniqueId(946);
+ static constexpr const TSymbolUniqueId EmitVertex = TSymbolUniqueId(947);
+ static constexpr const TSymbolUniqueId EndPrimitive = TSymbolUniqueId(948);
+ static constexpr const TSymbolUniqueId gl_DepthRangeParameters = TSymbolUniqueId(949);
+ static constexpr const TSymbolUniqueId gl_DepthRange = TSymbolUniqueId(950);
+ static constexpr const TSymbolUniqueId gl_MaxVertexAttribs = TSymbolUniqueId(951);
+ static constexpr const TSymbolUniqueId gl_MaxVertexUniformVectors = TSymbolUniqueId(952);
+ static constexpr const TSymbolUniqueId gl_MaxVertexTextureImageUnits = TSymbolUniqueId(953);
+ static constexpr const TSymbolUniqueId gl_MaxCombinedTextureImageUnits = TSymbolUniqueId(954);
+ static constexpr const TSymbolUniqueId gl_MaxTextureImageUnits = TSymbolUniqueId(955);
+ static constexpr const TSymbolUniqueId gl_MaxFragmentUniformVectors = TSymbolUniqueId(956);
+ static constexpr const TSymbolUniqueId gl_MaxVaryingVectors = TSymbolUniqueId(957);
+ static constexpr const TSymbolUniqueId gl_MaxDrawBuffers = TSymbolUniqueId(958);
+ static constexpr const TSymbolUniqueId gl_MaxDualSourceDrawBuffersEXT = TSymbolUniqueId(959);
+ static constexpr const TSymbolUniqueId gl_MaxVertexOutputVectors = TSymbolUniqueId(960);
+ static constexpr const TSymbolUniqueId gl_MaxFragmentInputVectors = TSymbolUniqueId(961);
+ static constexpr const TSymbolUniqueId gl_MinProgramTexelOffset = TSymbolUniqueId(962);
+ static constexpr const TSymbolUniqueId gl_MaxProgramTexelOffset = TSymbolUniqueId(963);
+ static constexpr const TSymbolUniqueId gl_MaxImageUnits = TSymbolUniqueId(964);
+ static constexpr const TSymbolUniqueId gl_MaxVertexImageUniforms = TSymbolUniqueId(965);
+ static constexpr const TSymbolUniqueId gl_MaxFragmentImageUniforms = TSymbolUniqueId(966);
+ static constexpr const TSymbolUniqueId gl_MaxComputeImageUniforms = TSymbolUniqueId(967);
+ static constexpr const TSymbolUniqueId gl_MaxCombinedImageUniforms = TSymbolUniqueId(968);
+ static constexpr const TSymbolUniqueId gl_MaxCombinedShaderOutputResources =
+ TSymbolUniqueId(969);
+ static constexpr const TSymbolUniqueId gl_MaxComputeWorkGroupCount = TSymbolUniqueId(970);
+ static constexpr const TSymbolUniqueId gl_MaxComputeWorkGroupSize = TSymbolUniqueId(971);
+ static constexpr const TSymbolUniqueId gl_MaxComputeUniformComponents = TSymbolUniqueId(972);
+ static constexpr const TSymbolUniqueId gl_MaxComputeTextureImageUnits = TSymbolUniqueId(973);
+ static constexpr const TSymbolUniqueId gl_MaxComputeAtomicCounters = TSymbolUniqueId(974);
+ static constexpr const TSymbolUniqueId gl_MaxComputeAtomicCounterBuffers = TSymbolUniqueId(975);
+ static constexpr const TSymbolUniqueId gl_MaxVertexAtomicCounters = TSymbolUniqueId(976);
+ static constexpr const TSymbolUniqueId gl_MaxFragmentAtomicCounters = TSymbolUniqueId(977);
+ static constexpr const TSymbolUniqueId gl_MaxCombinedAtomicCounters = TSymbolUniqueId(978);
+ static constexpr const TSymbolUniqueId gl_MaxAtomicCounterBindings = TSymbolUniqueId(979);
+ static constexpr const TSymbolUniqueId gl_MaxVertexAtomicCounterBuffers = TSymbolUniqueId(980);
+ static constexpr const TSymbolUniqueId gl_MaxFragmentAtomicCounterBuffers =
+ TSymbolUniqueId(981);
+ static constexpr const TSymbolUniqueId gl_MaxCombinedAtomicCounterBuffers =
+ TSymbolUniqueId(982);
+ static constexpr const TSymbolUniqueId gl_MaxAtomicCounterBufferSize = TSymbolUniqueId(983);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryInputComponents = TSymbolUniqueId(984);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryOutputComponents = TSymbolUniqueId(985);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryImageUniforms = TSymbolUniqueId(986);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryTextureImageUnits = TSymbolUniqueId(987);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryOutputVertices = TSymbolUniqueId(988);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryTotalOutputComponents =
+ TSymbolUniqueId(989);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryUniformComponents = TSymbolUniqueId(990);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryAtomicCounters = TSymbolUniqueId(991);
+ static constexpr const TSymbolUniqueId gl_MaxGeometryAtomicCounterBuffers =
+ TSymbolUniqueId(992);
+ static constexpr const TSymbolUniqueId gl_FragCoord = TSymbolUniqueId(993);
+ static constexpr const TSymbolUniqueId gl_FrontFacing = TSymbolUniqueId(994);
+ static constexpr const TSymbolUniqueId gl_PointCoord = TSymbolUniqueId(995);
+ static constexpr const TSymbolUniqueId gl_FragColor = TSymbolUniqueId(996);
+ static constexpr const TSymbolUniqueId gl_FragData = TSymbolUniqueId(997);
+ static constexpr const TSymbolUniqueId gl_FragDepth = TSymbolUniqueId(998);
+ static constexpr const TSymbolUniqueId gl_SecondaryFragColorEXT = TSymbolUniqueId(999);
+ static constexpr const TSymbolUniqueId gl_SecondaryFragDataEXT = TSymbolUniqueId(1000);
+ static constexpr const TSymbolUniqueId gl_FragDepthEXT = TSymbolUniqueId(1001);
+ static constexpr const TSymbolUniqueId gl_LastFragData = TSymbolUniqueId(1002);
+ static constexpr const TSymbolUniqueId gl_LastFragColor = TSymbolUniqueId(1003);
+ static constexpr const TSymbolUniqueId gl_LastFragDataNV = TSymbolUniqueId(1004);
+ static constexpr const TSymbolUniqueId gl_LastFragColorARM = TSymbolUniqueId(1005);
+ static constexpr const TSymbolUniqueId gl_PrimitiveID = TSymbolUniqueId(1006);
+ static constexpr const TSymbolUniqueId gl_Layer = TSymbolUniqueId(1007);
+ static constexpr const TSymbolUniqueId gl_Position = TSymbolUniqueId(1008);
+ static constexpr const TSymbolUniqueId gl_PointSize = TSymbolUniqueId(1009);
+ static constexpr const TSymbolUniqueId gl_InstanceID = TSymbolUniqueId(1010);
+ static constexpr const TSymbolUniqueId gl_VertexID = TSymbolUniqueId(1011);
+ static constexpr const TSymbolUniqueId gl_ViewportIndex = TSymbolUniqueId(1012);
+ static constexpr const TSymbolUniqueId gl_LayerVS = TSymbolUniqueId(1013);
+ static constexpr const TSymbolUniqueId gl_DrawID = TSymbolUniqueId(1014);
+ static constexpr const TSymbolUniqueId gl_DrawIDESSL1 = TSymbolUniqueId(1015);
+ static constexpr const TSymbolUniqueId gl_BaseVertex = TSymbolUniqueId(1016);
+ static constexpr const TSymbolUniqueId gl_BaseInstance = TSymbolUniqueId(1017);
+ static constexpr const TSymbolUniqueId gl_NumWorkGroups = TSymbolUniqueId(1018);
+ static constexpr const TSymbolUniqueId gl_WorkGroupSize = TSymbolUniqueId(1019);
+ static constexpr const TSymbolUniqueId gl_WorkGroupID = TSymbolUniqueId(1020);
+ static constexpr const TSymbolUniqueId gl_LocalInvocationID = TSymbolUniqueId(1021);
+ static constexpr const TSymbolUniqueId gl_GlobalInvocationID = TSymbolUniqueId(1022);
+ static constexpr const TSymbolUniqueId gl_LocalInvocationIndex = TSymbolUniqueId(1023);
+ static constexpr const TSymbolUniqueId gl_PrimitiveIDIn = TSymbolUniqueId(1024);
+ static constexpr const TSymbolUniqueId gl_InvocationID = TSymbolUniqueId(1025);
+ static constexpr const TSymbolUniqueId gl_PrimitiveIDGS = TSymbolUniqueId(1026);
+ static constexpr const TSymbolUniqueId gl_LayerGS = TSymbolUniqueId(1027);
+ static constexpr const TSymbolUniqueId gl_PerVertex = TSymbolUniqueId(1028);
+ static constexpr const TSymbolUniqueId gl_in = TSymbolUniqueId(1029);
+ static constexpr const TSymbolUniqueId gl_PerVertexOutBlock = TSymbolUniqueId(1030);
+ static constexpr const TSymbolUniqueId gl_PositionGS = TSymbolUniqueId(1031);
+ static constexpr const TSymbolUniqueId gl_ViewID_OVR = TSymbolUniqueId(1032);
+ static constexpr const TSymbolUniqueId gl_ViewID_OVRESSL1 = TSymbolUniqueId(1033);
+
+}; // class BuiltInId
+
+namespace BuiltInVariable
+{
+
+const TVariable *gl_BaseInstance();
+const TVariable *gl_BaseVertex();
+const TVariable *gl_DrawID();
+const TVariable *gl_DrawIDESSL1();
+const TVariable *gl_FragColor();
+const TVariable *gl_FragCoord();
+const TVariable *gl_FragDepth();
+const TVariable *gl_FrontFacing();
+const TVariable *gl_GlobalInvocationID();
+const TVariable *gl_InstanceID();
+const TVariable *gl_InvocationID();
+const TVariable *gl_LastFragColor();
+const TVariable *gl_LastFragColorARM();
+const TVariable *gl_Layer();
+const TVariable *gl_LayerGS();
+const TVariable *gl_LayerVS();
+const TVariable *gl_LocalInvocationID();
+const TVariable *gl_LocalInvocationIndex();
+const TVariable *gl_NumWorkGroups();
+const TVariable *gl_PointCoord();
+const TVariable *gl_PointSize();
+const TVariable *gl_Position();
+const TVariable *gl_PrimitiveID();
+const TVariable *gl_PrimitiveIDGS();
+const TVariable *gl_PrimitiveIDIn();
+const TVariable *gl_SecondaryFragColorEXT();
+const TVariable *gl_VertexID();
+const TVariable *gl_ViewID_OVR();
+const TVariable *gl_ViewID_OVRESSL1();
+const TVariable *gl_ViewportIndex();
+const TVariable *gl_WorkGroupID();
+const TVariable *gl_WorkGroupSize();
+
+} // namespace BuiltInVariable
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp
new file mode 100644
index 0000000000..198040df14
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp
@@ -0,0 +1,32 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// FindFunction.cpp: Find functions.
+
+#include "compiler/translator/tree_util/FindFunction.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+size_t FindFirstFunctionDefinitionIndex(TIntermBlock *root)
+{
+ const TIntermSequence &sequence = *root->getSequence();
+ for (size_t index = 0; index < sequence.size(); ++index)
+ {
+ TIntermNode *node = sequence[index];
+ TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
+ if (nodeFunction != nullptr)
+ {
+ return index;
+ }
+ }
+ return std::numeric_limits<size_t>::max();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h
new file mode 100644
index 0000000000..946a135037
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h
@@ -0,0 +1,21 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// FindFunction.h: Adds functions to find functions
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_FINDFUNCTION_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_FINDFUNCTION_H_
+
+#include <cstddef>
+
+namespace sh
+{
+class TIntermBlock;
+
+size_t FindFirstFunctionDefinitionIndex(TIntermBlock *root);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_FINDFUNCTION_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp
new file mode 100644
index 0000000000..0e3023b2bf
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp
@@ -0,0 +1,54 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// FindMain.cpp: Find the main() function definition in a given AST.
+
+#include "compiler/translator/tree_util/FindMain.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+size_t FindMainIndex(TIntermBlock *root)
+{
+ const TIntermSequence &sequence = *root->getSequence();
+ for (size_t index = 0; index < sequence.size(); ++index)
+ {
+ TIntermNode *node = sequence[index];
+ TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
+ if (nodeFunction != nullptr && nodeFunction->getFunction()->isMain())
+ {
+ return index;
+ }
+ }
+ return std::numeric_limits<size_t>::max();
+}
+
+TIntermFunctionDefinition *FindMain(TIntermBlock *root)
+{
+ for (TIntermNode *node : *root->getSequence())
+ {
+ TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
+ if (nodeFunction != nullptr && nodeFunction->getFunction()->isMain())
+ {
+ return nodeFunction;
+ }
+ }
+ return nullptr;
+}
+
+TIntermBlock *FindMainBody(TIntermBlock *root)
+{
+ TIntermFunctionDefinition *main = FindMain(root);
+ ASSERT(main != nullptr);
+ TIntermBlock *mainBody = main->getBody();
+ ASSERT(mainBody != nullptr);
+ return mainBody;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h
new file mode 100644
index 0000000000..a313315d76
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// FindMain.h: Adds functions to get the main function definition and its body.
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_FINDMAIN_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_FINDMAIN_H_
+
+#include <cstddef>
+
+namespace sh
+{
+class TIntermBlock;
+class TIntermFunctionDefinition;
+
+size_t FindMainIndex(TIntermBlock *root);
+TIntermFunctionDefinition *FindMain(TIntermBlock *root);
+TIntermBlock *FindMainBody(TIntermBlock *root);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_FINDMAIN_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp
new file mode 100644
index 0000000000..3eeb9cfd05
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FindSymbol.cpp:
+// Utility for finding a symbol node inside an AST tree.
+
+#include "compiler/translator/tree_util/FindSymbolNode.h"
+
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SymbolFinder : public TIntermTraverser
+{
+ public:
+ SymbolFinder(const ImmutableString &symbolName)
+ : TIntermTraverser(true, false, false), mSymbolName(symbolName), mNodeFound(nullptr)
+ {}
+
+ void visitSymbol(TIntermSymbol *node)
+ {
+ if (node->variable().symbolType() != SymbolType::Empty && node->getName() == mSymbolName)
+ {
+ mNodeFound = node;
+ }
+ }
+
+ bool isFound() const { return mNodeFound != nullptr; }
+ const TIntermSymbol *getNode() const { return mNodeFound; }
+
+ private:
+ ImmutableString mSymbolName;
+ TIntermSymbol *mNodeFound;
+};
+
+} // anonymous namespace
+
+const TIntermSymbol *FindSymbolNode(TIntermNode *root, const ImmutableString &symbolName)
+{
+ SymbolFinder finder(symbolName);
+ root->traverse(&finder);
+ return finder.getNode();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h
new file mode 100644
index 0000000000..f285479277
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FindSymbolNode.h:
+// Utility for finding a symbol node inside an AST tree.
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_FINDSYMBOLNODE_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_FINDSYMBOLNODE_H_
+
+namespace sh
+{
+
+class ImmutableString;
+class TIntermNode;
+class TIntermSymbol;
+
+const TIntermSymbol *FindSymbolNode(TIntermNode *root, const ImmutableString &symbolName);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_FINDSYMBOLNODE_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
new file mode 100644
index 0000000000..0f3c3a42a3
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
@@ -0,0 +1,204 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IntermNodePatternMatcher is a helper class for matching node trees to given patterns.
+// It can be used whenever the same checks for certain node structures are common to multiple AST
+// traversers.
+//
+
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool ContainsMatrixNode(const TIntermSequence &sequence)
+{
+ for (size_t ii = 0; ii < sequence.size(); ++ii)
+ {
+ TIntermTyped *node = sequence[ii]->getAsTyped();
+ if (node && node->isMatrix())
+ return true;
+ }
+ return false;
+}
+
+bool ContainsVectorNode(const TIntermSequence &sequence)
+{
+ for (size_t ii = 0; ii < sequence.size(); ++ii)
+ {
+ TIntermTyped *node = sequence[ii]->getAsTyped();
+ if (node && node->isVector())
+ return true;
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {}
+
+// static
+bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node)
+{
+ return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft());
+}
+
+// static
+bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node)
+{
+ return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() &&
+ node->getLeft()->getBasicType() != EbtStruct;
+}
+
+bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
+{
+ if ((mMask & kExpressionReturningArray) != 0)
+ {
+ if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
+ !parentNode->getAsBlock())
+ {
+ return true;
+ }
+ }
+
+ if ((mMask & kUnfoldedShortCircuitExpression) != 0)
+ {
+ if (node->getRight()->hasSideEffects() &&
+ (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermUnary *node)
+{
+ if ((mMask & kArrayLengthMethod) != 0)
+ {
+ if (node->getOp() == EOpArrayLength)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
+{
+ // L-value tracking information is needed to check for dynamic indexing in L-value.
+ // Traversers that don't track l-values can still use this class and match binary nodes with
+ // this variation of this method if they don't need to check for dynamic indexing in l-values.
+ ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0);
+ return matchInternal(node, parentNode);
+}
+
+bool IntermNodePatternMatcher::match(TIntermBinary *node,
+ TIntermNode *parentNode,
+ bool isLValueRequiredHere)
+{
+ if (matchInternal(node, parentNode))
+ {
+ return true;
+ }
+ if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0)
+ {
+ if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
+{
+ if ((mMask & kExpressionReturningArray) != 0)
+ {
+ if (parentNode != nullptr)
+ {
+ TIntermBinary *parentBinary = parentNode->getAsBinaryNode();
+ bool parentIsAssignment =
+ (parentBinary != nullptr &&
+ (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
+
+ if (node->getType().isArray() && !parentIsAssignment &&
+ (node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock())
+ {
+ return true;
+ }
+ }
+ }
+ if ((mMask & kScalarizedVecOrMatConstructor) != 0)
+ {
+ if (node->getOp() == EOpConstruct)
+ {
+ if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence())))
+ {
+ return true;
+ }
+ else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence())))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermTernary *node)
+{
+ if ((mMask & kUnfoldedShortCircuitExpression) != 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
+{
+ if ((mMask & kMultiDeclaration) != 0)
+ {
+ if (node->getSequence()->size() > 1)
+ {
+ return true;
+ }
+ }
+ if ((mMask & kArrayDeclaration) != 0)
+ {
+ if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
+ {
+ return true;
+ }
+ // Need to check from all declarators whether they are arrays since that may vary between
+ // declarators.
+ for (TIntermNode *declarator : *node->getSequence())
+ {
+ if (declarator->getAsTyped()->isArray())
+ {
+ return true;
+ }
+ }
+ }
+ if ((mMask & kNamelessStructDeclaration) != 0)
+ {
+ TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
+ if (declarator->getBasicType() == EbtStruct &&
+ declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h
new file mode 100644
index 0000000000..25a46ff4f6
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IntermNodePatternMatcher is a helper class for matching node trees to given patterns.
+// It can be used whenever the same checks for certain node structures are common to multiple AST
+// traversers.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMNODEPATTERNMATCHER_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_INTERMNODEPATTERNMATCHER_H_
+
+namespace sh
+{
+
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermDeclaration;
+class TIntermNode;
+class TIntermTernary;
+class TIntermUnary;
+
+class IntermNodePatternMatcher
+{
+ public:
+ static bool IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node);
+ static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
+
+ enum PatternType
+ {
+ // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf
+ kUnfoldedShortCircuitExpression = 0x0001,
+
+ // Matches expressions that return arrays with the exception of simple statements where a
+ // constructor or function call result is assigned.
+ kExpressionReturningArray = 0x0001 << 1,
+
+ // Matches dynamic indexing of vectors or matrices in l-values.
+ kDynamicIndexingOfVectorOrMatrixInLValue = 0x0001 << 2,
+
+ // Matches declarations with more than one declared variables.
+ kMultiDeclaration = 0x0001 << 3,
+
+ // Matches declarations of arrays.
+ kArrayDeclaration = 0x0001 << 4,
+
+ // Matches declarations of structs where the struct type does not have a name.
+ kNamelessStructDeclaration = 0x0001 << 5,
+
+ // Matches array length() method.
+ kArrayLengthMethod = 0x0001 << 6,
+
+ // Matches a vector or matrix constructor whose arguments are scalarized by the
+ // SH_SCALARIZE_VEC_OR_MAT_CONSTRUCTOR_ARGUMENTS workaround.
+ kScalarizedVecOrMatConstructor = 0x0001 << 7
+ };
+ IntermNodePatternMatcher(const unsigned int mask);
+
+ bool match(TIntermUnary *node);
+
+ bool match(TIntermBinary *node, TIntermNode *parentNode);
+
+ // Use this version for checking binary node matches in case you're using flag
+ // kDynamicIndexingOfVectorOrMatrixInLValue.
+ bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
+
+ bool match(TIntermAggregate *node, TIntermNode *parentNode);
+ bool match(TIntermTernary *node);
+ bool match(TIntermDeclaration *node);
+
+ private:
+ const unsigned int mMask;
+
+ bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_INTERMNODEPATTERNMATCHER_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp
new file mode 100644
index 0000000000..224535bd8c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp
@@ -0,0 +1,291 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly
+// meant to be used in AST transforms.
+
+#include "compiler/translator/tree_util/IntermNode_util.h"
+
+#include "compiler/translator/FunctionLookup.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const TFunction *LookUpBuiltInFunction(const char *name,
+ const TIntermSequence *arguments,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments);
+ const TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion);
+ if (symbol)
+ {
+ ASSERT(symbol->isFunction());
+ return static_cast<const TFunction *>(symbol);
+ }
+ return nullptr;
+}
+
+} // anonymous namespace
+
+TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func)
+{
+ return new TIntermFunctionPrototype(&func);
+}
+
+TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
+ TIntermBlock *functionBody)
+{
+ return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody);
+}
+
+TIntermTyped *CreateZeroNode(const TType &type)
+{
+ TType constType(type);
+ constType.setQualifier(EvqConst);
+
+ if (!type.isArray() && type.getBasicType() != EbtStruct)
+ {
+ size_t size = constType.getObjectSize();
+ TConstantUnion *u = new TConstantUnion[size];
+ for (size_t i = 0; i < size; ++i)
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ u[i].setFConst(0.0f);
+ break;
+ case EbtInt:
+ u[i].setIConst(0);
+ break;
+ case EbtUInt:
+ u[i].setUConst(0u);
+ break;
+ case EbtBool:
+ u[i].setBConst(false);
+ break;
+ default:
+ // CreateZeroNode is called by ParseContext that keeps parsing even when an
+ // error occurs, so it is possible for CreateZeroNode to be called with
+ // non-basic types. This happens only on error condition but CreateZeroNode
+ // needs to return a value with the correct type to continue the typecheck.
+ // That's why we handle non-basic type by setting whatever value, we just need
+ // the type to be right.
+ u[i].setIConst(42);
+ break;
+ }
+ }
+
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
+ return node;
+ }
+
+ TIntermSequence *arguments = new TIntermSequence();
+
+ if (type.isArray())
+ {
+ TType elementType(type);
+ elementType.toArrayElementType();
+
+ size_t arraySize = type.getOutermostArraySize();
+ for (size_t i = 0; i < arraySize; ++i)
+ {
+ arguments->push_back(CreateZeroNode(elementType));
+ }
+ }
+ else
+ {
+ ASSERT(type.getBasicType() == EbtStruct);
+
+ const TStructure *structure = type.getStruct();
+ for (const auto &field : structure->fields())
+ {
+ arguments->push_back(CreateZeroNode(*field->type()));
+ }
+ }
+
+ return TIntermAggregate::CreateConstructor(constType, arguments);
+}
+
+TIntermConstantUnion *CreateIndexNode(int index)
+{
+ TConstantUnion *u = new TConstantUnion[1];
+ u[0].setIConst(index);
+
+ TType type(EbtInt, EbpUndefined, EvqConst, 1);
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+ return node;
+}
+
+TIntermConstantUnion *CreateBoolNode(bool value)
+{
+ TConstantUnion *u = new TConstantUnion[1];
+ u[0].setBConst(value);
+
+ TType type(EbtBool, EbpUndefined, EvqConst, 1);
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+ return node;
+}
+
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
+{
+ ASSERT(symbolTable != nullptr);
+ // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
+ // variable. This might need to be done in other places as well.
+ return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal);
+}
+
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
+{
+ ASSERT(symbolTable != nullptr);
+ if (type->getQualifier() == qualifier)
+ {
+ return CreateTempVariable(symbolTable, type);
+ }
+ TType *typeWithQualifier = new TType(*type);
+ typeWithQualifier->setQualifier(qualifier);
+ return CreateTempVariable(symbolTable, typeWithQualifier);
+}
+
+TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
+{
+ ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
+ ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
+ tempVariable->getType().getQualifier() == EvqConst ||
+ tempVariable->getType().getQualifier() == EvqGlobal);
+ return new TIntermSymbol(tempVariable);
+}
+
+TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
+{
+ TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
+ tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
+ return tempDeclaration;
+}
+
+TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
+ TIntermTyped *initializer)
+{
+ ASSERT(initializer != nullptr);
+ TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
+ TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
+ TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
+ tempDeclaration->appendDeclarator(tempInit);
+ return tempDeclaration;
+}
+
+TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
+{
+ ASSERT(rightNode != nullptr);
+ TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
+ return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
+}
+
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+ const TType *type,
+ TQualifier qualifier,
+ TIntermDeclaration **declarationOut)
+{
+ TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
+ *declarationOut = CreateTempDeclarationNode(variable);
+ return variable;
+}
+
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+ TIntermTyped *initializer,
+ TQualifier qualifier,
+ TIntermDeclaration **declarationOut)
+{
+ TVariable *variable =
+ CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
+ *declarationOut = CreateTempInitDeclarationNode(variable, initializer);
+ return variable;
+}
+
+const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ TFieldList *fieldList,
+ TQualifier qualifier,
+ const TMemoryQualifier &memoryQualifier,
+ const char *blockTypeName,
+ const char *blockVariableName)
+{
+ // Define an interface block.
+ TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
+ TInterfaceBlock *interfaceBlock =
+ new TInterfaceBlock(symbolTable, ImmutableString(blockTypeName), fieldList, layoutQualifier,
+ SymbolType::AngleInternal);
+
+ // Turn the inteface block into a declaration.
+ TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier);
+ interfaceBlockType->setMemoryQualifier(memoryQualifier);
+
+ TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration;
+ TVariable *interfaceBlockVar = new TVariable(symbolTable, ImmutableString(blockVariableName),
+ interfaceBlockType, SymbolType::AngleInternal);
+ TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar);
+ interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator);
+
+ // Insert the declarations before the first function.
+ TIntermSequence *insertSequence = new TIntermSequence;
+ insertSequence->push_back(interfaceBlockDecl);
+
+ size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
+ root->insertChildNodes(firstFunctionIndex, *insertSequence);
+
+ return interfaceBlockVar;
+}
+
+TIntermBlock *EnsureBlock(TIntermNode *node)
+{
+ if (node == nullptr)
+ return nullptr;
+ TIntermBlock *blockNode = node->getAsBlock();
+ if (blockNode != nullptr)
+ return blockNode;
+
+ blockNode = new TIntermBlock();
+ blockNode->setLine(node->getLine());
+ blockNode->appendStatement(node);
+ return blockNode;
+}
+
+TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
+{
+ const TVariable *var = static_cast<const TVariable *>(symbolTable.findGlobal(name));
+ ASSERT(var);
+ return new TIntermSymbol(var);
+}
+
+TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ const TVariable *var =
+ static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
+ ASSERT(var);
+ return new TIntermSymbol(var);
+}
+
+TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
+ TIntermSequence *arguments,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
+ ASSERT(fn);
+ TOperator op = fn->getBuiltInOp();
+ if (op != EOpCallBuiltInFunction && arguments->size() == 1)
+ {
+ return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn);
+ }
+ return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h
new file mode 100644
index 0000000000..3a82ec07a7
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h
@@ -0,0 +1,76 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IntermNode_util.h: High-level utilities for creating AST nodes and node hierarchies. Mostly meant
+// to be used in AST transforms.
+
+#ifndef COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
+#define COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/FindFunction.h"
+
+namespace sh
+{
+
+class TSymbolTable;
+class TVariable;
+
+TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func);
+TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
+ TIntermBlock *functionBody);
+
+TIntermTyped *CreateZeroNode(const TType &type);
+TIntermConstantUnion *CreateIndexNode(int index);
+TIntermConstantUnion *CreateBoolNode(bool value);
+
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type);
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier);
+
+TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable);
+TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable);
+TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
+ TIntermTyped *initializer);
+TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode);
+
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+ const TType *type,
+ TQualifier qualifier,
+ TIntermDeclaration **declarationOut);
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+ TIntermTyped *initializer,
+ TQualifier qualifier,
+ TIntermDeclaration **declarationOut);
+const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ TFieldList *fieldList,
+ TQualifier qualifier,
+ const TMemoryQualifier &memoryQualifier,
+ const char *blockTypeName,
+ const char *blockVariableName);
+
+// If the input node is nullptr, return nullptr.
+// If the input node is a block node, return it.
+// If the input node is not a block node, put it inside a block node and return that.
+TIntermBlock *EnsureBlock(TIntermNode *node);
+
+// Should be called from inside Compiler::compileTreeImpl() where the global level is in scope.
+TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name,
+ const TSymbolTable &symbolTable);
+
+// Note: this can't access desktop GLSL built-ins. Those can only be accessed directly through
+// BuiltIn_autogen.h.
+TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
+ TIntermSequence *arguments,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp
new file mode 100644
index 0000000000..c38baa12bf
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp
@@ -0,0 +1,638 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+
+namespace sh
+{
+
+// Traverse the intermediate representation tree, and call a node type specific visit function for
+// each node. Traversal is done recursively through the node member function traverse(). Nodes with
+// children can have their whole subtree skipped if preVisit is turned on and the type specific
+// function returns false.
+template <typename T>
+void TIntermTraverser::traverse(T *node)
+{
+ ScopedNodeInTraversalPath addToPath(this, node);
+ if (!addToPath.isWithinDepthLimit())
+ return;
+
+ bool visit = true;
+
+ // Visit the node before children if pre-visiting.
+ if (preVisit)
+ visit = node->visit(PreVisit, this);
+
+ if (visit)
+ {
+ size_t childIndex = 0;
+ size_t childCount = node->getChildCount();
+
+ while (childIndex < childCount && visit)
+ {
+ node->getChildNode(childIndex)->traverse(this);
+ if (inVisit && childIndex != childCount - 1)
+ {
+ visit = node->visit(InVisit, this);
+ }
+ ++childIndex;
+ }
+
+ if (visit && postVisit)
+ node->visit(PostVisit, this);
+ }
+}
+
+void TIntermNode::traverse(TIntermTraverser *it)
+{
+ it->traverse(this);
+}
+
+void TIntermSymbol::traverse(TIntermTraverser *it)
+{
+ TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
+ it->visitSymbol(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser *it)
+{
+ TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
+ it->visitConstantUnion(this);
+}
+
+void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
+{
+ TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
+ it->visitFunctionPrototype(this);
+}
+
+void TIntermBinary::traverse(TIntermTraverser *it)
+{
+ it->traverseBinary(this);
+}
+
+void TIntermUnary::traverse(TIntermTraverser *it)
+{
+ it->traverseUnary(this);
+}
+
+void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
+{
+ it->traverseFunctionDefinition(this);
+}
+
+void TIntermBlock::traverse(TIntermTraverser *it)
+{
+ it->traverseBlock(this);
+}
+
+void TIntermAggregate::traverse(TIntermTraverser *it)
+{
+ it->traverseAggregate(this);
+}
+
+void TIntermLoop::traverse(TIntermTraverser *it)
+{
+ it->traverseLoop(this);
+}
+
+void TIntermPreprocessorDirective::traverse(TIntermTraverser *it)
+{
+ it->visitPreprocessorDirective(this);
+}
+
+bool TIntermSymbol::visit(Visit visit, TIntermTraverser *it)
+{
+ it->visitSymbol(this);
+ return false;
+}
+
+bool TIntermConstantUnion::visit(Visit visit, TIntermTraverser *it)
+{
+ it->visitConstantUnion(this);
+ return false;
+}
+
+bool TIntermFunctionPrototype::visit(Visit visit, TIntermTraverser *it)
+{
+ it->visitFunctionPrototype(this);
+ return false;
+}
+
+bool TIntermFunctionDefinition::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitFunctionDefinition(visit, this);
+}
+
+bool TIntermUnary::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitUnary(visit, this);
+}
+
+bool TIntermSwizzle::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitSwizzle(visit, this);
+}
+
+bool TIntermBinary::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitBinary(visit, this);
+}
+
+bool TIntermTernary::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitTernary(visit, this);
+}
+
+bool TIntermAggregate::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitAggregate(visit, this);
+}
+
+bool TIntermDeclaration::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitDeclaration(visit, this);
+}
+
+bool TIntermInvariantDeclaration::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitInvariantDeclaration(visit, this);
+}
+
+bool TIntermBlock::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitBlock(visit, this);
+}
+
+bool TIntermIfElse::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitIfElse(visit, this);
+}
+
+bool TIntermLoop::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitLoop(visit, this);
+}
+
+bool TIntermBranch::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitBranch(visit, this);
+}
+
+bool TIntermSwitch::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitSwitch(visit, this);
+}
+
+bool TIntermCase::visit(Visit visit, TIntermTraverser *it)
+{
+ return it->visitCase(visit, this);
+}
+
+bool TIntermPreprocessorDirective::visit(Visit visit, TIntermTraverser *it)
+{
+ it->visitPreprocessorDirective(this);
+ return false;
+}
+
+TIntermTraverser::TIntermTraverser(bool preVisit,
+ bool inVisit,
+ bool postVisit,
+ TSymbolTable *symbolTable)
+ : preVisit(preVisit),
+ inVisit(inVisit),
+ postVisit(postVisit),
+ mMaxDepth(0),
+ mMaxAllowedDepth(std::numeric_limits<int>::max()),
+ mInGlobalScope(true),
+ mSymbolTable(symbolTable)
+{
+ // Only enabling inVisit is not supported.
+ ASSERT(!(inVisit && !preVisit && !postVisit));
+}
+
+TIntermTraverser::~TIntermTraverser() {}
+
+void TIntermTraverser::setMaxAllowedDepth(int depth)
+{
+ mMaxAllowedDepth = depth;
+}
+
+const TIntermBlock *TIntermTraverser::getParentBlock() const
+{
+ if (!mParentBlockStack.empty())
+ {
+ return mParentBlockStack.back().node;
+ }
+ return nullptr;
+}
+
+void TIntermTraverser::pushParentBlock(TIntermBlock *node)
+{
+ mParentBlockStack.push_back(ParentBlock(node, 0));
+}
+
+void TIntermTraverser::incrementParentBlockPos()
+{
+ ++mParentBlockStack.back().pos;
+}
+
+void TIntermTraverser::popParentBlock()
+{
+ ASSERT(!mParentBlockStack.empty());
+ mParentBlockStack.pop_back();
+}
+
+void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
+{
+ TIntermSequence emptyInsertionsAfter;
+ insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
+}
+
+void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
+ const TIntermSequence &insertionsAfter)
+{
+ ASSERT(!mParentBlockStack.empty());
+ ParentBlock &parentBlock = mParentBlockStack.back();
+ if (mPath.back() == parentBlock.node)
+ {
+ ASSERT(mParentBlockStack.size() >= 2u);
+ // The current node is a block node, so the parent block is not the topmost one in the block
+ // stack, but the one below that.
+ parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
+ }
+ NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
+ insertionsAfter);
+ mInsertions.push_back(insert);
+}
+
+void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
+{
+ TIntermSequence insertions;
+ insertions.push_back(statement);
+ insertStatementsInParentBlock(insertions);
+}
+
+void TIntermTraverser::insertStatementsInBlockAtPosition(TIntermBlock *parent,
+ size_t position,
+ const TIntermSequence &insertionsBefore,
+ const TIntermSequence &insertionsAfter)
+{
+ ASSERT(parent);
+ ASSERT(position >= 0);
+ ASSERT(position < parent->getChildCount());
+
+ mInsertions.emplace_back(parent, position, insertionsBefore, insertionsAfter);
+}
+
+void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
+{
+ mInFunctionCallOutParameter = inOutParameter;
+}
+
+bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
+{
+ return mInFunctionCallOutParameter;
+}
+
+void TIntermTraverser::traverseBinary(TIntermBinary *node)
+{
+ traverse(node);
+}
+
+void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
+{
+ ScopedNodeInTraversalPath addToPath(this, node);
+ if (!addToPath.isWithinDepthLimit())
+ return;
+
+ bool visit = true;
+
+ // visit the node before children if pre-visiting.
+ if (preVisit)
+ visit = node->visit(PreVisit, this);
+
+ // Visit the children, in the right order.
+ if (visit)
+ {
+ if (node->isAssignment())
+ {
+ ASSERT(!isLValueRequiredHere());
+ setOperatorRequiresLValue(true);
+ }
+
+ node->getLeft()->traverse(this);
+
+ if (node->isAssignment())
+ setOperatorRequiresLValue(false);
+
+ if (inVisit)
+ visit = node->visit(InVisit, this);
+
+ if (visit)
+ {
+ // Some binary operations like indexing can be inside an expression which must be an
+ // l-value.
+ bool parentOperatorRequiresLValue = operatorRequiresLValue();
+ bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
+
+ // Index is not required to be an l-value even when the surrounding expression is
+ // required to be an l-value.
+ TOperator op = node->getOp();
+ if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
+ op == EOpIndexDirectStruct || op == EOpIndexIndirect)
+ {
+ setOperatorRequiresLValue(false);
+ setInFunctionCallOutParameter(false);
+ }
+
+ node->getRight()->traverse(this);
+
+ setOperatorRequiresLValue(parentOperatorRequiresLValue);
+ setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
+
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ if (postVisit)
+ visit = node->visit(PostVisit, this);
+ }
+ }
+}
+
+void TIntermTraverser::traverseUnary(TIntermUnary *node)
+{
+ traverse(node);
+}
+
+void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
+{
+ ScopedNodeInTraversalPath addToPath(this, node);
+ if (!addToPath.isWithinDepthLimit())
+ return;
+
+ bool visit = true;
+
+ if (preVisit)
+ visit = node->visit(PreVisit, this);
+
+ if (visit)
+ {
+ ASSERT(!operatorRequiresLValue());
+ switch (node->getOp())
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ setOperatorRequiresLValue(true);
+ break;
+ default:
+ break;
+ }
+
+ node->getOperand()->traverse(this);
+
+ setOperatorRequiresLValue(false);
+
+ if (postVisit)
+ visit = node->visit(PostVisit, this);
+ }
+}
+
+// Traverse a function definition node. This keeps track of global scope.
+void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
+{
+ ScopedNodeInTraversalPath addToPath(this, node);
+ if (!addToPath.isWithinDepthLimit())
+ return;
+
+ bool visit = true;
+
+ if (preVisit)
+ visit = node->visit(PreVisit, this);
+
+ if (visit)
+ {
+ node->getFunctionPrototype()->traverse(this);
+ if (inVisit)
+ visit = node->visit(InVisit, this);
+ if (visit)
+ {
+ mInGlobalScope = false;
+ node->getBody()->traverse(this);
+ mInGlobalScope = true;
+ if (postVisit)
+ visit = node->visit(PostVisit, this);
+ }
+ }
+}
+
+// Traverse a block node. This keeps track of the position of traversed child nodes within the block
+// so that nodes may be inserted before or after them.
+void TIntermTraverser::traverseBlock(TIntermBlock *node)
+{
+ ScopedNodeInTraversalPath addToPath(this, node);
+ if (!addToPath.isWithinDepthLimit())
+ return;
+
+ pushParentBlock(node);
+
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = node->visit(PreVisit, this);
+
+ if (visit)
+ {
+ for (auto *child : *sequence)
+ {
+ if (visit)
+ {
+ child->traverse(this);
+ if (inVisit)
+ {
+ if (child != sequence->back())
+ visit = node->visit(InVisit, this);
+ }
+
+ incrementParentBlockPos();
+ }
+ }
+
+ if (visit && postVisit)
+ visit = node->visit(PostVisit, this);
+ }
+
+ popParentBlock();
+}
+
+void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
+{
+ traverse(node);
+}
+
+bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
+ const NodeInsertMultipleEntry &b)
+{
+ if (a.parent != b.parent)
+ {
+ return a.parent > b.parent;
+ }
+ return a.position > b.position;
+}
+
+void TIntermTraverser::updateTree()
+{
+ // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
+ // the same parent node are handled correctly.
+ std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
+ for (size_t ii = 0; ii < mInsertions.size(); ++ii)
+ {
+ // We can't know here what the intended ordering of two insertions to the same position is,
+ // so it is not supported.
+ ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
+ mInsertions[ii].parent != mInsertions[ii - 1].parent);
+ const NodeInsertMultipleEntry &insertion = mInsertions[ii];
+ ASSERT(insertion.parent);
+ if (!insertion.insertionsAfter.empty())
+ {
+ bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
+ insertion.insertionsAfter);
+ ASSERT(inserted);
+ }
+ if (!insertion.insertionsBefore.empty())
+ {
+ bool inserted =
+ insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
+ ASSERT(inserted);
+ }
+ }
+ for (size_t ii = 0; ii < mReplacements.size(); ++ii)
+ {
+ const NodeUpdateEntry &replacement = mReplacements[ii];
+ ASSERT(replacement.parent);
+ bool replaced =
+ replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
+ ASSERT(replaced);
+
+ if (!replacement.originalBecomesChildOfReplacement)
+ {
+ // In AST traversing, a parent is visited before its children.
+ // After we replace a node, if its immediate child is to
+ // be replaced, we need to make sure we don't update the replaced
+ // node; instead, we update the replacement node.
+ for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
+ {
+ NodeUpdateEntry &replacement2 = mReplacements[jj];
+ if (replacement2.parent == replacement.original)
+ replacement2.parent = replacement.replacement;
+ }
+ }
+ }
+ for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
+ {
+ const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
+ ASSERT(replacement.parent);
+ bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
+ replacement.replacements);
+ ASSERT(replaced);
+ }
+
+ clearReplacementQueue();
+}
+
+void TIntermTraverser::clearReplacementQueue()
+{
+ mReplacements.clear();
+ mMultiReplacements.clear();
+ mInsertions.clear();
+}
+
+void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
+{
+ queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
+}
+
+void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
+ TIntermNode *original,
+ TIntermNode *replacement,
+ OriginalNode originalStatus)
+{
+ bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
+ mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
+}
+
+TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
+ bool inVisit,
+ bool postVisit,
+ TSymbolTable *symbolTable)
+ : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
+ mOperatorRequiresLValue(false),
+ mInFunctionCallOutParameter(false)
+{
+ ASSERT(symbolTable);
+}
+
+void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
+{
+ ScopedNodeInTraversalPath addToPath(this, node);
+ if (!addToPath.isWithinDepthLimit())
+ return;
+
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = node->visit(PreVisit, this);
+
+ if (visit)
+ {
+ size_t paramIndex = 0u;
+ for (auto *child : *sequence)
+ {
+ if (visit)
+ {
+ if (node->getFunction())
+ {
+ // Both built-ins and user defined functions should have the function symbol
+ // set.
+ ASSERT(paramIndex < node->getFunction()->getParamCount());
+ TQualifier qualifier =
+ node->getFunction()->getParam(paramIndex)->getType().getQualifier();
+ setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
+ ++paramIndex;
+ }
+ else
+ {
+ ASSERT(node->isConstructor());
+ }
+ child->traverse(this);
+ if (inVisit)
+ {
+ if (child != sequence->back())
+ visit = node->visit(InVisit, this);
+ }
+ }
+ }
+ setInFunctionCallOutParameter(false);
+
+ if (visit && postVisit)
+ visit = node->visit(PostVisit, this);
+ }
+}
+
+void TIntermTraverser::traverseLoop(TIntermLoop *node)
+{
+ traverse(node);
+}
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h
new file mode 100644
index 0000000000..30687a4869
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h
@@ -0,0 +1,322 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IntermTraverse.h : base classes for AST traversers that walk the AST and
+// also have the ability to transform it by replacing nodes.
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/Visit.h"
+
+namespace sh
+{
+
+class TSymbolTable;
+class TSymbolUniqueId;
+
+// For traversing the tree. User should derive from this class overriding the visit functions,
+// and then pass an object of the subclass to a traverse method of a node.
+//
+// The traverse*() functions may also be overridden to do other bookkeeping on the tree to provide
+// contextual information to the visit functions, such as whether the node is the target of an
+// assignment. This is complex to maintain and so should only be done in special cases.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+// See also how to write AST transformations documentation:
+// https://github.com/google/angle/blob/master/doc/WritingShaderASTTransformations.md
+class TIntermTraverser : angle::NonCopyable
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE
+ TIntermTraverser(bool preVisit,
+ bool inVisit,
+ bool postVisit,
+ TSymbolTable *symbolTable = nullptr);
+ virtual ~TIntermTraverser();
+
+ virtual void visitSymbol(TIntermSymbol *node) {}
+ virtual void visitConstantUnion(TIntermConstantUnion *node) {}
+ virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
+ virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
+ virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
+ virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
+ virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
+ virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
+ virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
+ virtual void visitFunctionPrototype(TIntermFunctionPrototype *node) {}
+ virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+ {
+ return true;
+ }
+ virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
+ virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
+ virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+ {
+ return true;
+ }
+ virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
+ virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
+ virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
+ virtual void visitPreprocessorDirective(TIntermPreprocessorDirective *node) {}
+
+ // The traverse functions contain logic for iterating over the children of the node
+ // and calling the visit functions in the appropriate places. They also track some
+ // context that may be used by the visit functions.
+
+ // The generic traverse() function is used for nodes that don't need special handling.
+ // It's templated in order to avoid virtual function calls, this gains around 2% compiler
+ // performance.
+ template <typename T>
+ void traverse(T *node);
+
+ // Specialized traverse functions are implemented for node types where traversal logic may need
+ // to be overridden or where some special bookkeeping needs to be done.
+ virtual void traverseBinary(TIntermBinary *node);
+ virtual void traverseUnary(TIntermUnary *node);
+ virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
+ virtual void traverseAggregate(TIntermAggregate *node);
+ virtual void traverseBlock(TIntermBlock *node);
+ virtual void traverseLoop(TIntermLoop *node);
+
+ int getMaxDepth() const { return mMaxDepth; }
+
+ // If traversers need to replace nodes, they can add the replacements in
+ // mReplacements/mMultiReplacements during traversal and the user of the traverser should call
+ // this function after traversal to perform them.
+ void updateTree();
+
+ protected:
+ void setMaxAllowedDepth(int depth);
+
+ // Should only be called from traverse*() functions
+ bool incrementDepth(TIntermNode *current)
+ {
+ mMaxDepth = std::max(mMaxDepth, static_cast<int>(mPath.size()));
+ mPath.push_back(current);
+ return mMaxDepth < mMaxAllowedDepth;
+ }
+
+ // Should only be called from traverse*() functions
+ void decrementDepth() { mPath.pop_back(); }
+
+ int getCurrentTraversalDepth() const { return static_cast<int>(mPath.size()) - 1; }
+
+ // RAII helper for incrementDepth/decrementDepth
+ class ScopedNodeInTraversalPath
+ {
+ public:
+ ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current)
+ : mTraverser(traverser)
+ {
+ mWithinDepthLimit = mTraverser->incrementDepth(current);
+ }
+ ~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); }
+
+ bool isWithinDepthLimit() { return mWithinDepthLimit; }
+
+ private:
+ TIntermTraverser *mTraverser;
+ bool mWithinDepthLimit;
+ };
+ // Optimized traversal functions for leaf nodes directly access ScopedNodeInTraversalPath.
+ friend void TIntermSymbol::traverse(TIntermTraverser *);
+ friend void TIntermConstantUnion::traverse(TIntermTraverser *);
+ friend void TIntermFunctionPrototype::traverse(TIntermTraverser *);
+
+ TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; }
+
+ // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
+ TIntermNode *getAncestorNode(unsigned int n)
+ {
+ if (mPath.size() > n + 1u)
+ {
+ return mPath[mPath.size() - n - 2u];
+ }
+ return nullptr;
+ }
+
+ const TIntermBlock *getParentBlock() const;
+
+ void pushParentBlock(TIntermBlock *node);
+ void incrementParentBlockPos();
+ void popParentBlock();
+
+ // To replace a single node with multiple nodes in the parent aggregate. May be used with blocks
+ // but also with other nodes like declarations.
+ struct NodeReplaceWithMultipleEntry
+ {
+ NodeReplaceWithMultipleEntry(TIntermAggregateBase *parentIn,
+ TIntermNode *originalIn,
+ TIntermSequence replacementsIn)
+ : parent(parentIn), original(originalIn), replacements(std::move(replacementsIn))
+ {}
+
+ TIntermAggregateBase *parent;
+ TIntermNode *original;
+ TIntermSequence replacements;
+ };
+
+ // Helper to insert statements in the parent block of the node currently being traversed.
+ // The statements will be inserted before the node being traversed once updateTree is called.
+ // Should only be called during PreVisit or PostVisit if called from block nodes.
+ // Note that two insertions to the same position in the same block are not supported.
+ void insertStatementsInParentBlock(const TIntermSequence &insertions);
+
+ // Same as above, but supports simultaneous insertion of statements before and after the node
+ // currently being traversed.
+ void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
+ const TIntermSequence &insertionsAfter);
+
+ // Helper to insert a single statement.
+ void insertStatementInParentBlock(TIntermNode *statement);
+
+ // Explicitly specify where to insert statements. The statements are inserted before and after
+ // the specified position. The statements will be inserted once updateTree is called. Note that
+ // two insertions to the same position in the same block are not supported.
+ void insertStatementsInBlockAtPosition(TIntermBlock *parent,
+ size_t position,
+ const TIntermSequence &insertionsBefore,
+ const TIntermSequence &insertionsAfter);
+
+ enum class OriginalNode
+ {
+ BECOMES_CHILD,
+ IS_DROPPED
+ };
+
+ void clearReplacementQueue();
+
+ // Replace the node currently being visited with replacement.
+ void queueReplacement(TIntermNode *replacement, OriginalNode originalStatus);
+ // Explicitly specify a node to replace with replacement.
+ void queueReplacementWithParent(TIntermNode *parent,
+ TIntermNode *original,
+ TIntermNode *replacement,
+ OriginalNode originalStatus);
+
+ const bool preVisit;
+ const bool inVisit;
+ const bool postVisit;
+
+ int mMaxDepth;
+ int mMaxAllowedDepth;
+
+ bool mInGlobalScope;
+
+ // During traversing, save all the changes that need to happen into
+ // mReplacements/mMultiReplacements, then do them by calling updateTree().
+ // Multi replacements are processed after single replacements.
+ std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
+
+ TSymbolTable *mSymbolTable;
+
+ private:
+ // To insert multiple nodes into the parent block.
+ struct NodeInsertMultipleEntry
+ {
+ NodeInsertMultipleEntry(TIntermBlock *_parent,
+ TIntermSequence::size_type _position,
+ TIntermSequence _insertionsBefore,
+ TIntermSequence _insertionsAfter)
+ : parent(_parent),
+ position(_position),
+ insertionsBefore(_insertionsBefore),
+ insertionsAfter(_insertionsAfter)
+ {}
+
+ TIntermBlock *parent;
+ TIntermSequence::size_type position;
+ TIntermSequence insertionsBefore;
+ TIntermSequence insertionsAfter;
+ };
+
+ static bool CompareInsertion(const NodeInsertMultipleEntry &a,
+ const NodeInsertMultipleEntry &b);
+
+ // To replace a single node with another on the parent node
+ struct NodeUpdateEntry
+ {
+ NodeUpdateEntry(TIntermNode *_parent,
+ TIntermNode *_original,
+ TIntermNode *_replacement,
+ bool _originalBecomesChildOfReplacement)
+ : parent(_parent),
+ original(_original),
+ replacement(_replacement),
+ originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
+ {}
+
+ TIntermNode *parent;
+ TIntermNode *original;
+ TIntermNode *replacement;
+ bool originalBecomesChildOfReplacement;
+ };
+
+ struct ParentBlock
+ {
+ ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
+ : node(nodeIn), pos(posIn)
+ {}
+
+ TIntermBlock *node;
+ TIntermSequence::size_type pos;
+ };
+
+ std::vector<NodeInsertMultipleEntry> mInsertions;
+ std::vector<NodeUpdateEntry> mReplacements;
+
+ // All the nodes from root to the current node during traversing.
+ TVector<TIntermNode *> mPath;
+
+ // All the code blocks from the root to the current node's parent during traversal.
+ std::vector<ParentBlock> mParentBlockStack;
+};
+
+// Traverser parent class that tracks where a node is a destination of a write operation and so is
+// required to be an l-value.
+class TLValueTrackingTraverser : public TIntermTraverser
+{
+ public:
+ TLValueTrackingTraverser(bool preVisit,
+ bool inVisit,
+ bool postVisit,
+ TSymbolTable *symbolTable);
+ virtual ~TLValueTrackingTraverser() {}
+
+ void traverseBinary(TIntermBinary *node) final;
+ void traverseUnary(TIntermUnary *node) final;
+ void traverseAggregate(TIntermAggregate *node) final;
+
+ protected:
+ bool isLValueRequiredHere() const
+ {
+ return mOperatorRequiresLValue || mInFunctionCallOutParameter;
+ }
+
+ private:
+ // Track whether an l-value is required in the node that is currently being traversed by the
+ // surrounding operator.
+ // Use isLValueRequiredHere to check all conditions which require an l-value.
+ void setOperatorRequiresLValue(bool lValueRequired)
+ {
+ mOperatorRequiresLValue = lValueRequired;
+ }
+ bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
+
+ // Track whether an l-value is required inside a function call.
+ void setInFunctionCallOutParameter(bool inOutParameter);
+ bool isInFunctionCallOutParameter() const;
+
+ bool mOperatorRequiresLValue;
+ bool mInFunctionCallOutParameter;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h b/gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h
new file mode 100644
index 0000000000..c083531578
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NodeSearch.h: Utilities for searching translator node graphs
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_NODESEARCH_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_NODESEARCH_H_
+
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+template <class Parent>
+class NodeSearchTraverser : public TIntermTraverser
+{
+ public:
+ NodeSearchTraverser() : TIntermTraverser(true, false, false), mFound(false) {}
+
+ bool found() const { return mFound; }
+
+ static bool search(TIntermNode *node)
+ {
+ Parent searchTraverser;
+ node->traverse(&searchTraverser);
+ return searchTraverser.found();
+ }
+
+ protected:
+ bool mFound;
+};
+
+class FindDiscard : public NodeSearchTraverser<FindDiscard>
+{
+ public:
+ virtual bool visitBranch(Visit visit, TIntermBranch *node)
+ {
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ mFound = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return !mFound;
+ }
+};
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_NODESEARCH_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp
new file mode 100644
index 0000000000..14f6f7db98
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp
@@ -0,0 +1,136 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ReplaceShadowingVariables.cpp: Replace all references to any variable in the AST that is
+// a redefinition of a variable in a nested scope. This is a useful for ESSL 1.00 shaders
+// where the spec section "4.2.3. Redeclaring Variables" states "However, a nested scope can
+// override an outer scope's declaration of a particular variable name." This is changed in
+// later spec versions, such as ESSL 3.20 spec which states "If [a variable] is declared as
+// a parameter in a function definition, it is scoped until the end of that function
+// definition. A function's parameter declarations and body together form a single scope."
+//
+// So this class is useful when translating from ESSL 1.00 shaders, where function body var
+// redefinition is allowed, to later shader versions where it's not allowed.
+//
+
+#include "compiler/translator/tree_util/ReplaceShadowingVariables.h"
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+#include <unordered_set>
+
+namespace sh
+{
+
+namespace
+{
+
+// Custom struct to queue up any replacements until after AST traversal
+struct DeferredReplacementBlock
+{
+ const TVariable *originalVariable; // variable to be replaced
+ TVariable *replacementVariable; // variable to replace originalVar with
+ TIntermBlock *functionBody; // function body where replacement occurs
+};
+
+class ReplaceShadowingVariablesTraverser : public TIntermTraverser
+{
+ public:
+ ReplaceShadowingVariablesTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, true, true),
+ mSymbolTable(symbolTable),
+ mParameterNames{},
+ mFunctionBody(nullptr)
+ {}
+
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
+ {
+ // In pre-visit of function, record params
+ if (visit == PreVisit)
+ {
+ ASSERT(mParameterNames.size() == 0);
+ const TFunction *func = node->getFunctionPrototype()->getFunction();
+ // Grab all of the parameter names from the function prototype
+ uint32_t paramCount = func->getParamCount();
+ for (uint32_t i = 0; i < paramCount; ++i)
+ {
+ mParameterNames.emplace(std::string(func->getParam(i)->name().data()));
+ }
+ if (mParameterNames.size() > 0)
+ mFunctionBody = node->getBody();
+ }
+ else if (visit == PostVisit)
+ {
+ // Clear data saved from function definition
+ mParameterNames.clear();
+ mFunctionBody = nullptr;
+ }
+ return true;
+ }
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
+ {
+ if (visit == PreVisit && mParameterNames.size() != 0)
+ {
+ TIntermSequence *decls = node->getSequence();
+ for (auto &declVector : *decls)
+ {
+ // no init case
+ TIntermSymbol *symNode = declVector->getAsSymbolNode();
+ if (symNode == nullptr)
+ {
+ // init case
+ TIntermBinary *binaryNode = declVector->getAsBinaryNode();
+ ASSERT(binaryNode->getOp() == EOpInitialize);
+ symNode = binaryNode->getLeft()->getAsSymbolNode();
+ }
+ ASSERT(symNode != nullptr);
+ std::string varName = std::string(symNode->variable().name().data());
+ if (mParameterNames.count(varName) > 0)
+ {
+ // We found a redefined var so queue replacement
+ mReplacements.emplace_back(DeferredReplacementBlock{
+ &symNode->variable(),
+ CreateTempVariable(mSymbolTable, &symNode->variable().getType()),
+ mFunctionBody});
+ }
+ }
+ }
+ return true;
+ }
+ // Perform replacement of vars for any deferred replacements that were identified
+ void executeReplacements()
+ {
+ for (DeferredReplacementBlock &replace : mReplacements)
+ {
+ ReplaceVariable(replace.functionBody, replace.originalVariable,
+ replace.replacementVariable);
+ }
+ mReplacements.clear();
+ }
+
+ private:
+ TSymbolTable *mSymbolTable;
+ std::unordered_set<std::string> mParameterNames;
+ TIntermBlock *mFunctionBody;
+ std::vector<DeferredReplacementBlock> mReplacements;
+};
+
+} // anonymous namespace
+
+// Replaces every occurrence of a variable with another variable.
+void ReplaceShadowingVariables(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ ReplaceShadowingVariablesTraverser traverser(symbolTable);
+ root->traverse(&traverser);
+ traverser.executeReplacements();
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h
new file mode 100644
index 0000000000..79e2694d53
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h
@@ -0,0 +1,21 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ReplaceShadowingVariables.h: Find any variables that are redefined within a nested
+// scope and replace them with a newly named variable.
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_REPLACESHADOWINGVARIABLES_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_REPLACESHADOWINGVARIABLES_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void ReplaceShadowingVariables(TIntermBlock *root, TSymbolTable *symbolTable);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_REPLACESHADOWINGVARIABLES_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp
new file mode 100644
index 0000000000..7120cea20b
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ReplaceVariable.cpp: Replace all references to a specific variable in the AST with references to
+// another variable.
+
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class ReplaceVariableTraverser : public TIntermTraverser
+{
+ public:
+ ReplaceVariableTraverser(const TVariable *toBeReplaced, const TIntermTyped *replacement)
+ : TIntermTraverser(true, false, false),
+ mToBeReplaced(toBeReplaced),
+ mReplacement(replacement)
+ {}
+
+ void visitSymbol(TIntermSymbol *node) override
+ {
+ if (&node->variable() == mToBeReplaced)
+ {
+ queueReplacement(mReplacement->deepCopy(), OriginalNode::IS_DROPPED);
+ }
+ }
+
+ private:
+ const TVariable *const mToBeReplaced;
+ const TIntermTyped *const mReplacement;
+};
+
+} // anonymous namespace
+
+// Replaces every occurrence of a variable with another variable.
+void ReplaceVariable(TIntermBlock *root,
+ const TVariable *toBeReplaced,
+ const TVariable *replacement)
+{
+ ReplaceVariableTraverser traverser(toBeReplaced, new TIntermSymbol(replacement));
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+// Replaces every occurrence of a variable with a TIntermNode.
+void ReplaceVariableWithTyped(TIntermBlock *root,
+ const TVariable *toBeReplaced,
+ const TIntermTyped *replacement)
+{
+ ReplaceVariableTraverser traverser(toBeReplaced, replacement);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h
new file mode 100644
index 0000000000..3a9e34ee34
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ReplaceVariable.h: Replace all references to a specific variable in the AST with references to
+// another variable.
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TVariable;
+class TIntermTyped;
+
+void ReplaceVariable(TIntermBlock *root,
+ const TVariable *toBeReplaced,
+ const TVariable *replacement);
+void ReplaceVariableWithTyped(TIntermBlock *root,
+ const TVariable *toBeReplaced,
+ const TIntermTyped *replacement);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp
new file mode 100644
index 0000000000..bd00b8a0d9
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RunAtTheEndOfShader.cpp: Add code to be run at the end of the shader. In case main() contains a
+// return statement, this is done by replacing the main() function with another function that calls
+// the old main, like this:
+//
+// void main() { body }
+// =>
+// void main0() { body }
+// void main()
+// {
+// main0();
+// codeToRun
+// }
+//
+// This way the code will get run even if the return statement inside main is executed.
+//
+
+#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/FindMain.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kMainString("main");
+
+class ContainsReturnTraverser : public TIntermTraverser
+{
+ public:
+ ContainsReturnTraverser() : TIntermTraverser(true, false, false), mContainsReturn(false) {}
+
+ bool visitBranch(Visit visit, TIntermBranch *node) override
+ {
+ if (node->getFlowOp() == EOpReturn)
+ {
+ mContainsReturn = true;
+ }
+ return false;
+ }
+
+ bool containsReturn() { return mContainsReturn; }
+
+ private:
+ bool mContainsReturn;
+};
+
+bool ContainsReturn(TIntermNode *node)
+{
+ ContainsReturnTraverser traverser;
+ node->traverse(&traverser);
+ return traverser.containsReturn();
+}
+
+void WrapMainAndAppend(TIntermBlock *root,
+ TIntermFunctionDefinition *main,
+ TIntermNode *codeToRun,
+ TSymbolTable *symbolTable)
+{
+ // Replace main() with main0() with the same body.
+ TFunction *oldMain =
+ new TFunction(symbolTable, kEmptyImmutableString, SymbolType::AngleInternal,
+ StaticType::GetBasic<EbtVoid>(), false);
+ TIntermFunctionDefinition *oldMainDefinition =
+ CreateInternalFunctionDefinitionNode(*oldMain, main->getBody());
+
+ bool replaced = root->replaceChildNode(main, oldMainDefinition);
+ ASSERT(replaced);
+
+ // void main()
+ TFunction *newMain = new TFunction(symbolTable, kMainString, SymbolType::UserDefined,
+ StaticType::GetBasic<EbtVoid>(), false);
+ TIntermFunctionPrototype *newMainProto = new TIntermFunctionPrototype(newMain);
+
+ // {
+ // main0();
+ // codeToRun
+ // }
+ TIntermBlock *newMainBody = new TIntermBlock();
+ TIntermAggregate *oldMainCall =
+ TIntermAggregate::CreateFunctionCall(*oldMain, new TIntermSequence());
+ newMainBody->appendStatement(oldMainCall);
+ newMainBody->appendStatement(codeToRun);
+
+ // Add the new main() to the root node.
+ TIntermFunctionDefinition *newMainDefinition =
+ new TIntermFunctionDefinition(newMainProto, newMainBody);
+ root->appendStatement(newMainDefinition);
+}
+
+} // anonymous namespace
+
+void RunAtTheEndOfShader(TIntermBlock *root, TIntermNode *codeToRun, TSymbolTable *symbolTable)
+{
+ TIntermFunctionDefinition *main = FindMain(root);
+ if (!ContainsReturn(main))
+ {
+ main->getBody()->appendStatement(codeToRun);
+ return;
+ }
+
+ WrapMainAndAppend(root, main, codeToRun, symbolTable);
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h
new file mode 100644
index 0000000000..ed5a0bb64f
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RunAtTheEndOfShader.h: Add code to be run at the end of the shader.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEENDOFSHADER_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEENDOFSHADER_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TIntermNode;
+class TSymbolTable;
+
+void RunAtTheEndOfShader(TIntermBlock *root, TIntermNode *codeToRun, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEENDOFSHADER_H_ \ No newline at end of file
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h b/gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h
new file mode 100644
index 0000000000..2b22fbdf86
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_
+#define COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_
+
+namespace sh
+{
+
+enum Visit
+{
+ PreVisit,
+ InVisit,
+ PostVisit
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_
diff --git a/gfx/angle/checkout/src/compiler/translator/util.cpp b/gfx/angle/checkout/src/compiler/translator/util.cpp
new file mode 100644
index 0000000000..7781c1bc7c
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/util.cpp
@@ -0,0 +1,936 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/util.h"
+
+#include <limits>
+
+#include "common/utilities.h"
+#include "compiler/preprocessor/numeric_lex.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/SymbolTable.h"
+
+bool atoi_clamp(const char *str, unsigned int *value)
+{
+ bool success = angle::pp::numeric_lex_int(str, value);
+ if (!success)
+ *value = std::numeric_limits<unsigned int>::max();
+ return success;
+}
+
+namespace sh
+{
+
+namespace
+{
+
+bool IsInterpolationIn(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqSmoothIn:
+ case EvqFlatIn:
+ case EvqCentroidIn:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // anonymous namespace
+
+float NumericLexFloat32OutOfRangeToInfinity(const std::string &str)
+{
+ // Parses a decimal string using scientific notation into a floating point number.
+ // Out-of-range values are converted to infinity. Values that are too small to be
+ // represented are converted to zero.
+
+ // The mantissa in decimal scientific notation. The magnitude of the mantissa integer does not
+ // matter.
+ unsigned int decimalMantissa = 0;
+ size_t i = 0;
+ bool decimalPointSeen = false;
+ bool nonZeroSeenInMantissa = false;
+
+ // The exponent offset reflects the position of the decimal point.
+ int exponentOffset = -1;
+
+ // This is just a counter for how many decimal digits are written to decimalMantissa.
+ int mantissaDecimalDigits = 0;
+
+ while (i < str.length())
+ {
+ const char c = str[i];
+ if (c == 'e' || c == 'E')
+ {
+ break;
+ }
+ if (c == '.')
+ {
+ decimalPointSeen = true;
+ ++i;
+ continue;
+ }
+
+ unsigned int digit = static_cast<unsigned int>(c - '0');
+ ASSERT(digit < 10u);
+ if (digit != 0u)
+ {
+ nonZeroSeenInMantissa = true;
+ }
+ if (nonZeroSeenInMantissa)
+ {
+ // Add bits to the mantissa until space runs out in 32-bit int. This should be
+ // enough precision to make the resulting binary mantissa accurate to 1 ULP.
+ if (decimalMantissa <= (std::numeric_limits<unsigned int>::max() - 9u) / 10u)
+ {
+ decimalMantissa = decimalMantissa * 10u + digit;
+ ++mantissaDecimalDigits;
+ }
+ if (!decimalPointSeen)
+ {
+ ++exponentOffset;
+ }
+ }
+ else if (decimalPointSeen)
+ {
+ --exponentOffset;
+ }
+ ++i;
+ }
+ if (decimalMantissa == 0)
+ {
+ return 0.0f;
+ }
+ int exponent = 0;
+ if (i < str.length())
+ {
+ ASSERT(str[i] == 'e' || str[i] == 'E');
+ ++i;
+ bool exponentOutOfRange = false;
+ bool negativeExponent = false;
+ if (str[i] == '-')
+ {
+ negativeExponent = true;
+ ++i;
+ }
+ else if (str[i] == '+')
+ {
+ ++i;
+ }
+ while (i < str.length())
+ {
+ const char c = str[i];
+ unsigned int digit = static_cast<unsigned int>(c - '0');
+ ASSERT(digit < 10u);
+ if (exponent <= (std::numeric_limits<int>::max() - 9) / 10)
+ {
+ exponent = exponent * 10 + digit;
+ }
+ else
+ {
+ exponentOutOfRange = true;
+ }
+ ++i;
+ }
+ if (negativeExponent)
+ {
+ exponent = -exponent;
+ }
+ if (exponentOutOfRange)
+ {
+ if (negativeExponent)
+ {
+ return 0.0f;
+ }
+ else
+ {
+ return std::numeric_limits<float>::infinity();
+ }
+ }
+ }
+ // Do the calculation in 64-bit to avoid overflow.
+ long long exponentLong =
+ static_cast<long long>(exponent) + static_cast<long long>(exponentOffset);
+ if (exponentLong > std::numeric_limits<float>::max_exponent10)
+ {
+ return std::numeric_limits<float>::infinity();
+ }
+ else if (exponentLong < std::numeric_limits<float>::min_exponent10)
+ {
+ return 0.0f;
+ }
+ // The exponent is in range, so we need to actually evaluate the float.
+ exponent = static_cast<int>(exponentLong);
+ double value = decimalMantissa;
+
+ // Calculate the exponent offset to normalize the mantissa.
+ int normalizationExponentOffset = 1 - mantissaDecimalDigits;
+ // Apply the exponent.
+ value *= std::pow(10.0, static_cast<double>(exponent + normalizationExponentOffset));
+ if (value > static_cast<double>(std::numeric_limits<float>::max()))
+ {
+ return std::numeric_limits<float>::infinity();
+ }
+ if (value < static_cast<double>(std::numeric_limits<float>::min()))
+ {
+ return 0.0f;
+ }
+ return static_cast<float>(value);
+}
+
+bool strtof_clamp(const std::string &str, float *value)
+{
+ // Custom float parsing that can handle the following corner cases:
+ // 1. The decimal mantissa is very small but the exponent is very large, putting the resulting
+ // number inside the float range.
+ // 2. The decimal mantissa is very large but the exponent is very small, putting the resulting
+ // number inside the float range.
+ // 3. The value is out-of-range and should be evaluated as infinity.
+ // 4. The value is too small and should be evaluated as zero.
+ // See ESSL 3.00.6 section 4.1.4 for the relevant specification.
+ *value = NumericLexFloat32OutOfRangeToInfinity(str);
+ return !gl::isInf(*value);
+}
+
+GLenum GLVariableType(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ if (type.isVector())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2:
+ return GL_FLOAT_VEC2;
+ case 3:
+ return GL_FLOAT_VEC3;
+ case 4:
+ return GL_FLOAT_VEC4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+ }
+ else if (type.isMatrix())
+ {
+ switch (type.getCols())
+ {
+ case 2:
+ switch (type.getRows())
+ {
+ case 2:
+ return GL_FLOAT_MAT2;
+ case 3:
+ return GL_FLOAT_MAT2x3;
+ case 4:
+ return GL_FLOAT_MAT2x4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+
+ case 3:
+ switch (type.getRows())
+ {
+ case 2:
+ return GL_FLOAT_MAT3x2;
+ case 3:
+ return GL_FLOAT_MAT3;
+ case 4:
+ return GL_FLOAT_MAT3x4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+
+ case 4:
+ switch (type.getRows())
+ {
+ case 2:
+ return GL_FLOAT_MAT4x2;
+ case 3:
+ return GL_FLOAT_MAT4x3;
+ case 4:
+ return GL_FLOAT_MAT4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+ }
+ else
+ {
+ return GL_FLOAT;
+ }
+ }
+ else if (type.getBasicType() == EbtInt)
+ {
+ if (type.isVector())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2:
+ return GL_INT_VEC2;
+ case 3:
+ return GL_INT_VEC3;
+ case 4:
+ return GL_INT_VEC4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+ }
+ else
+ {
+ ASSERT(!type.isMatrix());
+ return GL_INT;
+ }
+ }
+ else if (type.getBasicType() == EbtUInt)
+ {
+ if (type.isVector())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2:
+ return GL_UNSIGNED_INT_VEC2;
+ case 3:
+ return GL_UNSIGNED_INT_VEC3;
+ case 4:
+ return GL_UNSIGNED_INT_VEC4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+ }
+ else
+ {
+ ASSERT(!type.isMatrix());
+ return GL_UNSIGNED_INT;
+ }
+ }
+ else if (type.getBasicType() == EbtBool)
+ {
+ if (type.isVector())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2:
+ return GL_BOOL_VEC2;
+ case 3:
+ return GL_BOOL_VEC3;
+ case 4:
+ return GL_BOOL_VEC4;
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return GL_NONE;
+#endif
+ }
+ }
+ else
+ {
+ ASSERT(!type.isMatrix());
+ return GL_BOOL;
+ }
+ }
+
+ switch (type.getBasicType())
+ {
+ case EbtSampler2D:
+ return GL_SAMPLER_2D;
+ case EbtSampler3D:
+ return GL_SAMPLER_3D;
+ case EbtSamplerCube:
+ return GL_SAMPLER_CUBE;
+ case EbtSamplerExternalOES:
+ return GL_SAMPLER_EXTERNAL_OES;
+ case EbtSamplerExternal2DY2YEXT:
+ return GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT;
+ case EbtSampler2DRect:
+ return GL_SAMPLER_2D_RECT_ANGLE;
+ case EbtSampler2DArray:
+ return GL_SAMPLER_2D_ARRAY;
+ case EbtSampler2DMS:
+ return GL_SAMPLER_2D_MULTISAMPLE;
+ case EbtSampler2DMSArray:
+ return GL_SAMPLER_2D_MULTISAMPLE_ARRAY;
+ case EbtISampler2D:
+ return GL_INT_SAMPLER_2D;
+ case EbtISampler3D:
+ return GL_INT_SAMPLER_3D;
+ case EbtISamplerCube:
+ return GL_INT_SAMPLER_CUBE;
+ case EbtISampler2DArray:
+ return GL_INT_SAMPLER_2D_ARRAY;
+ case EbtISampler2DMS:
+ return GL_INT_SAMPLER_2D_MULTISAMPLE;
+ case EbtISampler2DMSArray:
+ return GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
+ case EbtUSampler2D:
+ return GL_UNSIGNED_INT_SAMPLER_2D;
+ case EbtUSampler3D:
+ return GL_UNSIGNED_INT_SAMPLER_3D;
+ case EbtUSamplerCube:
+ return GL_UNSIGNED_INT_SAMPLER_CUBE;
+ case EbtUSampler2DArray:
+ return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
+ case EbtUSampler2DMS:
+ return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
+ case EbtUSampler2DMSArray:
+ return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
+ case EbtSampler2DShadow:
+ return GL_SAMPLER_2D_SHADOW;
+ case EbtSamplerCubeShadow:
+ return GL_SAMPLER_CUBE_SHADOW;
+ case EbtSampler2DArrayShadow:
+ return GL_SAMPLER_2D_ARRAY_SHADOW;
+ case EbtImage2D:
+ return GL_IMAGE_2D;
+ case EbtIImage2D:
+ return GL_INT_IMAGE_2D;
+ case EbtUImage2D:
+ return GL_UNSIGNED_INT_IMAGE_2D;
+ case EbtImage2DArray:
+ return GL_IMAGE_2D_ARRAY;
+ case EbtIImage2DArray:
+ return GL_INT_IMAGE_2D_ARRAY;
+ case EbtUImage2DArray:
+ return GL_UNSIGNED_INT_IMAGE_2D_ARRAY;
+ case EbtImage3D:
+ return GL_IMAGE_3D;
+ case EbtIImage3D:
+ return GL_INT_IMAGE_3D;
+ case EbtUImage3D:
+ return GL_UNSIGNED_INT_IMAGE_3D;
+ case EbtImageCube:
+ return GL_IMAGE_CUBE;
+ case EbtIImageCube:
+ return GL_INT_IMAGE_CUBE;
+ case EbtUImageCube:
+ return GL_UNSIGNED_INT_IMAGE_CUBE;
+ case EbtAtomicCounter:
+ return GL_UNSIGNED_INT_ATOMIC_COUNTER;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_NONE;
+}
+
+GLenum GLVariablePrecision(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ switch (type.getPrecision())
+ {
+ case EbpHigh:
+ return GL_HIGH_FLOAT;
+ case EbpMedium:
+ return GL_MEDIUM_FLOAT;
+ case EbpLow:
+ return GL_LOW_FLOAT;
+ case EbpUndefined:
+ // Desktop specs do not use precision
+ return GL_NONE;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt)
+ {
+ switch (type.getPrecision())
+ {
+ case EbpHigh:
+ return GL_HIGH_INT;
+ case EbpMedium:
+ return GL_MEDIUM_INT;
+ case EbpLow:
+ return GL_LOW_INT;
+ case EbpUndefined:
+ // Desktop specs do not use precision
+ return GL_NONE;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ // Other types (boolean, sampler) don't have a precision
+ return GL_NONE;
+}
+
+ImmutableString ArrayString(const TType &type)
+{
+ if (!type.isArray())
+ return ImmutableString("");
+
+ const TVector<unsigned int> &arraySizes = *type.getArraySizes();
+ constexpr const size_t kMaxDecimalDigitsPerSize = 10u;
+ ImmutableStringBuilder arrayString(arraySizes.size() * (kMaxDecimalDigitsPerSize + 2u));
+ for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend();
+ ++arraySizeIter)
+ {
+ arrayString << "[";
+ if (*arraySizeIter > 0)
+ {
+ arrayString.appendDecimal(*arraySizeIter);
+ }
+ arrayString << "]";
+ }
+ return arrayString;
+}
+
+ImmutableString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap)
+{
+ if (type.getBasicType() == EbtStruct)
+ return HashName(type.getStruct(), hashFunction, nameMap);
+ else
+ return ImmutableString(type.getBuiltInTypeNameString());
+}
+
+bool IsVaryingOut(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqVaryingOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ case EvqVertexOut:
+ case EvqGeometryOut:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool IsVaryingIn(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqSmoothIn:
+ case EvqFlatIn:
+ case EvqCentroidIn:
+ case EvqFragmentIn:
+ case EvqGeometryIn:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool IsVarying(TQualifier qualifier)
+{
+ return IsVaryingIn(qualifier) || IsVaryingOut(qualifier);
+}
+
+bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier)
+{
+ return (qualifier == EvqGeometryIn) ||
+ ((shaderType == GL_GEOMETRY_SHADER_EXT) && IsInterpolationIn(qualifier));
+}
+
+InterpolationType GetInterpolationType(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqFlatIn:
+ case EvqFlatOut:
+ return INTERPOLATION_FLAT;
+
+ case EvqSmoothIn:
+ case EvqSmoothOut:
+ case EvqVertexOut:
+ case EvqFragmentIn:
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqGeometryIn:
+ case EvqGeometryOut:
+ return INTERPOLATION_SMOOTH;
+
+ case EvqCentroidIn:
+ case EvqCentroidOut:
+ return INTERPOLATION_CENTROID;
+
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return INTERPOLATION_SMOOTH;
+#endif
+ }
+}
+
+TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
+{
+ switch (var.type)
+ {
+ case GL_BOOL:
+ return TType(EbtBool);
+ case GL_BOOL_VEC2:
+ return TType(EbtBool, 2);
+ case GL_BOOL_VEC3:
+ return TType(EbtBool, 3);
+ case GL_BOOL_VEC4:
+ return TType(EbtBool, 4);
+ case GL_FLOAT:
+ return TType(EbtFloat);
+ case GL_FLOAT_VEC2:
+ return TType(EbtFloat, 2);
+ case GL_FLOAT_VEC3:
+ return TType(EbtFloat, 3);
+ case GL_FLOAT_VEC4:
+ return TType(EbtFloat, 4);
+ case GL_FLOAT_MAT2:
+ return TType(EbtFloat, 2, 2);
+ case GL_FLOAT_MAT3:
+ return TType(EbtFloat, 3, 3);
+ case GL_FLOAT_MAT4:
+ return TType(EbtFloat, 4, 4);
+ case GL_FLOAT_MAT2x3:
+ return TType(EbtFloat, 2, 3);
+ case GL_FLOAT_MAT2x4:
+ return TType(EbtFloat, 2, 4);
+ case GL_FLOAT_MAT3x2:
+ return TType(EbtFloat, 3, 2);
+ case GL_FLOAT_MAT3x4:
+ return TType(EbtFloat, 3, 4);
+ case GL_FLOAT_MAT4x2:
+ return TType(EbtFloat, 4, 2);
+ case GL_FLOAT_MAT4x3:
+ return TType(EbtFloat, 4, 3);
+ case GL_INT:
+ return TType(EbtInt);
+ case GL_INT_VEC2:
+ return TType(EbtInt, 2);
+ case GL_INT_VEC3:
+ return TType(EbtInt, 3);
+ case GL_INT_VEC4:
+ return TType(EbtInt, 4);
+ case GL_UNSIGNED_INT:
+ return TType(EbtUInt);
+ case GL_UNSIGNED_INT_VEC2:
+ return TType(EbtUInt, 2);
+ case GL_UNSIGNED_INT_VEC3:
+ return TType(EbtUInt, 3);
+ case GL_UNSIGNED_INT_VEC4:
+ return TType(EbtUInt, 4);
+ default:
+ UNREACHABLE();
+#if !UNREACHABLE_IS_NORETURN
+ return TType();
+#endif
+ }
+}
+
+void DeclareGlobalVariable(TIntermBlock *root, const TVariable *variable)
+{
+ TIntermDeclaration *declaration = new TIntermDeclaration();
+ declaration->appendDeclarator(new TIntermSymbol(variable));
+
+ TIntermSequence *globalSequence = root->getSequence();
+ globalSequence->insert(globalSequence->begin(), declaration);
+}
+
+// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier
+bool CanBeInvariantESSL1(TQualifier qualifier)
+{
+ return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) ||
+ IsBuiltinOutputVariable(qualifier) ||
+ (IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing);
+}
+
+// GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier
+// GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier
+bool CanBeInvariantESSL3OrGreater(TQualifier qualifier)
+{
+ return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut ||
+ IsBuiltinOutputVariable(qualifier);
+}
+
+bool IsBuiltinOutputVariable(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqPosition:
+ case EvqPointSize:
+ case EvqFragDepth:
+ case EvqFragDepthEXT:
+ case EvqFragColor:
+ case EvqSecondaryFragColorEXT:
+ case EvqFragData:
+ case EvqSecondaryFragDataEXT:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool IsBuiltinFragmentInputVariable(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqFragCoord:
+ case EvqPointCoord:
+ case EvqFrontFacing:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool IsShaderOutput(TQualifier qualifier)
+{
+ return IsVaryingOut(qualifier) || IsBuiltinOutputVariable(qualifier);
+}
+
+bool IsOutputESSL(ShShaderOutput output)
+{
+ return output == SH_ESSL_OUTPUT;
+}
+
+bool IsOutputGLSL(ShShaderOutput output)
+{
+ switch (output)
+ {
+ case SH_GLSL_130_OUTPUT:
+ case SH_GLSL_140_OUTPUT:
+ case SH_GLSL_150_CORE_OUTPUT:
+ case SH_GLSL_330_CORE_OUTPUT:
+ case SH_GLSL_400_CORE_OUTPUT:
+ case SH_GLSL_410_CORE_OUTPUT:
+ case SH_GLSL_420_CORE_OUTPUT:
+ case SH_GLSL_430_CORE_OUTPUT:
+ case SH_GLSL_440_CORE_OUTPUT:
+ case SH_GLSL_450_CORE_OUTPUT:
+ case SH_GLSL_COMPATIBILITY_OUTPUT:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+bool IsOutputHLSL(ShShaderOutput output)
+{
+ switch (output)
+ {
+ case SH_HLSL_3_0_OUTPUT:
+ case SH_HLSL_4_1_OUTPUT:
+ case SH_HLSL_4_0_FL9_3_OUTPUT:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+bool IsOutputVulkan(ShShaderOutput output)
+{
+ return output == SH_GLSL_VULKAN_OUTPUT;
+}
+
+bool IsInShaderStorageBlock(TIntermTyped *node)
+{
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ return IsInShaderStorageBlock(swizzleNode->getOperand());
+ }
+
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexIndirect:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ return IsInShaderStorageBlock(binaryNode->getLeft());
+ default:
+ return false;
+ }
+ }
+
+ const TType &type = node->getType();
+ return type.getQualifier() == EvqBuffer;
+}
+
+GLenum GetImageInternalFormatType(TLayoutImageInternalFormat iifq)
+{
+ switch (iifq)
+ {
+ case EiifRGBA32F:
+ return GL_RGBA32F;
+ case EiifRGBA16F:
+ return GL_RGBA16F;
+ case EiifR32F:
+ return GL_R32F;
+ case EiifRGBA32UI:
+ return GL_RGBA32UI;
+ case EiifRGBA16UI:
+ return GL_RGBA16UI;
+ case EiifRGBA8UI:
+ return GL_RGBA8UI;
+ case EiifR32UI:
+ return GL_R32UI;
+ case EiifRGBA32I:
+ return GL_RGBA32I;
+ case EiifRGBA16I:
+ return GL_RGBA16I;
+ case EiifRGBA8I:
+ return GL_RGBA8I;
+ case EiifR32I:
+ return GL_R32I;
+ case EiifRGBA8:
+ return GL_RGBA8;
+ case EiifRGBA8_SNORM:
+ return GL_RGBA8_SNORM;
+ default:
+ return GL_NONE;
+ }
+}
+
+bool IsSpecWithFunctionBodyNewScope(ShShaderSpec shaderSpec, int shaderVersion)
+{
+ return (shaderVersion == 100 && !sh::IsWebGLBasedSpec(shaderSpec));
+}
+
+ImplicitTypeConversion GetConversion(TBasicType t1, TBasicType t2)
+{
+ if (t1 == t2)
+ return ImplicitTypeConversion::Same;
+
+ switch (t1)
+ {
+ case EbtInt:
+ switch (t2)
+ {
+ case EbtInt:
+ UNREACHABLE();
+ break;
+ case EbtUInt:
+ return ImplicitTypeConversion::Invalid;
+ case EbtFloat:
+ return ImplicitTypeConversion::Left;
+ default:
+ return ImplicitTypeConversion::Invalid;
+ }
+ break;
+ case EbtUInt:
+ switch (t2)
+ {
+ case EbtInt:
+ return ImplicitTypeConversion::Invalid;
+ case EbtUInt:
+ UNREACHABLE();
+ break;
+ case EbtFloat:
+ return ImplicitTypeConversion::Left;
+ default:
+ return ImplicitTypeConversion::Invalid;
+ }
+ break;
+ case EbtFloat:
+ switch (t2)
+ {
+ case EbtInt:
+ case EbtUInt:
+ return ImplicitTypeConversion::Right;
+ case EbtFloat:
+ UNREACHABLE();
+ break;
+ default:
+ return ImplicitTypeConversion::Invalid;
+ }
+ break;
+ default:
+ return ImplicitTypeConversion::Invalid;
+ }
+ return ImplicitTypeConversion::Invalid;
+}
+
+bool IsValidImplicitConversion(sh::ImplicitTypeConversion conversion, TOperator op)
+{
+ switch (conversion)
+ {
+ case sh::ImplicitTypeConversion::Same:
+ return true;
+ case sh::ImplicitTypeConversion::Left:
+ switch (op)
+ {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpAdd:
+ case EOpSub:
+ case EOpMul:
+ case EOpDiv:
+ return true;
+ default:
+ break;
+ }
+ break;
+ case sh::ImplicitTypeConversion::Right:
+ switch (op)
+ {
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpAdd:
+ case EOpSub:
+ case EOpMul:
+ case EOpDiv:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpDivAssign:
+ return true;
+ default:
+ break;
+ }
+ break;
+ case sh::ImplicitTypeConversion::Invalid:
+ break;
+ }
+ return false;
+}
+
+} // namespace sh
diff --git a/gfx/angle/checkout/src/compiler/translator/util.h b/gfx/angle/checkout/src/compiler/translator/util.h
new file mode 100644
index 0000000000..609c72af67
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/util.h
@@ -0,0 +1,92 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_UTIL_H_
+#define COMPILER_TRANSLATOR_UTIL_H_
+
+#include <stack>
+
+#include <GLSLANG/ShaderLang.h>
+#include "angle_gl.h"
+
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/Operator.h"
+#include "compiler/translator/Types.h"
+
+// If overflow happens, clamp the value to UINT_MIN or UINT_MAX.
+// Return false if overflow happens.
+bool atoi_clamp(const char *str, unsigned int *value);
+
+namespace sh
+{
+
+// Keeps track of whether an implicit conversion from int/uint to float is possible.
+// These conversions are supported in desktop GLSL shaders only.
+// Also keeps track of which side of operation should be converted.
+enum class ImplicitTypeConversion
+{
+ Same,
+ Left,
+ Right,
+ Invalid,
+};
+
+class TIntermBlock;
+class TSymbolTable;
+class TIntermTyped;
+
+float NumericLexFloat32OutOfRangeToInfinity(const std::string &str);
+
+// strtof_clamp is like strtof but
+// 1. it forces C locale, i.e. forcing '.' as decimal point.
+// 2. it sets the value to infinity if overflow happens.
+// 3. str should be guaranteed to be in the valid format for a floating point number as defined
+// by the grammar in the ESSL 3.00.6 spec section 4.1.4.
+// Return false if overflow happens.
+bool strtof_clamp(const std::string &str, float *value);
+
+GLenum GLVariableType(const TType &type);
+GLenum GLVariablePrecision(const TType &type);
+bool IsVaryingIn(TQualifier qualifier);
+bool IsVaryingOut(TQualifier qualifier);
+bool IsVarying(TQualifier qualifier);
+bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier);
+InterpolationType GetInterpolationType(TQualifier qualifier);
+
+// Returns array brackets including size with outermost array size first, as specified in GLSL ES
+// 3.10 section 4.1.9.
+ImmutableString ArrayString(const TType &type);
+
+ImmutableString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap);
+
+TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
+
+void DeclareGlobalVariable(TIntermBlock *root, const TVariable *variable);
+
+bool IsBuiltinOutputVariable(TQualifier qualifier);
+bool IsBuiltinFragmentInputVariable(TQualifier qualifier);
+bool CanBeInvariantESSL1(TQualifier qualifier);
+bool CanBeInvariantESSL3OrGreater(TQualifier qualifier);
+bool IsShaderOutput(TQualifier qualifier);
+bool IsOutputESSL(ShShaderOutput output);
+bool IsOutputGLSL(ShShaderOutput output);
+bool IsOutputHLSL(ShShaderOutput output);
+bool IsOutputVulkan(ShShaderOutput output);
+
+bool IsInShaderStorageBlock(TIntermTyped *node);
+
+GLenum GetImageInternalFormatType(TLayoutImageInternalFormat iifq);
+// ESSL 1.00 shaders nest function body scope within function parameter scope
+bool IsSpecWithFunctionBodyNewScope(ShShaderSpec shaderSpec, int shaderVersion);
+
+// Helper functions for implicit conversions
+ImplicitTypeConversion GetConversion(TBasicType t1, TBasicType t2);
+
+bool IsValidImplicitConversion(ImplicitTypeConversion conversion, TOperator op);
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_UTIL_H_